From 6416b83370442f8085f42d5039b63d8b0713ab40 Mon Sep 17 00:00:00 2001 From: Peter Hankiewicz Date: Wed, 9 Oct 2024 13:03:10 +0200 Subject: [PATCH] Optimize getting latest feed item in specific hub feed --- app/controllers/application_controller.rb | 2 +- app/helpers/hub_feeds_helper.rb | 13 +-- app/models/feed.rb | 8 ++ ...12_create_get_latest_feed_item_function.rb | 28 ++++++ db/schema.rb | 89 +++++++++---------- 5 files changed, 87 insertions(+), 53 deletions(-) create mode 100644 db/migrate/20241009105912_create_get_latest_feed_item_function.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c8bb9f65..670ccb25 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -60,7 +60,7 @@ def init_breadcrumbs end def user_not_authorized - logger.warn "User #{current_user.id} not authorized for request: #{request}" + logger.warn "User #{current_user.id} not authorized for request: #{request}" unless current_user.nil? flash[:alert] = "You can't access that - sorry!" redirect_to root_path end diff --git a/app/helpers/hub_feeds_helper.rb b/app/helpers/hub_feeds_helper.rb index 6a3e68dd..68f885be 100644 --- a/app/helpers/hub_feeds_helper.rb +++ b/app/helpers/hub_feeds_helper.rb @@ -2,12 +2,13 @@ # Helper methods for hub feeds module HubFeedsHelper def hub_feed_updated(hub_feed) - updated_at = - if hub_feed.feed_items.any? && !hub_feed.feed_items.reorder('').first.date_published.nil? - hub_feed.feed_items.reorder('').first.date_published - else - hub_feed.feed.updated_at - end + latest_item = hub_feed.fetch_latest_feed_item + + updated_at = if latest_item && latest_item['date_published'] + Date.parse(latest_item['date_published']) + else + hub_feed.updated_at.to_date + end updated_at.to_s(:long) end diff --git a/app/models/feed.rb b/app/models/feed.rb index a80c672f..b443279e 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -211,6 +211,14 @@ def self.title 'Feed' end + def fetch_latest_feed_item + result = ActiveRecord::Base.connection.exec_query( + "SELECT * FROM get_latest_feed_item($1)", "SQL", [[nil, self.id]] + ) + + result.first + end + private def remove_feed_items_feeds diff --git a/db/migrate/20241009105912_create_get_latest_feed_item_function.rb b/db/migrate/20241009105912_create_get_latest_feed_item_function.rb new file mode 100644 index 00000000..f9266c22 --- /dev/null +++ b/db/migrate/20241009105912_create_get_latest_feed_item_function.rb @@ -0,0 +1,28 @@ +class CreateGetLatestFeedItemFunction < ActiveRecord::Migration[5.1] + def up + execute <<-SQL + CREATE FUNCTION get_latest_feed_item(feed_id_param INTEGER) + RETURNS TABLE(id INTEGER, title VARCHAR, url VARCHAR, guid VARCHAR, authors VARCHAR, contributors VARCHAR, description VARCHAR, content VARCHAR, rights VARCHAR, date_published TIMESTAMP, last_updated TIMESTAMP, created_at TIMESTAMP, updated_at TIMESTAMP, image_url TEXT) AS $$ + BEGIN + RETURN QUERY + WITH relevant_feed_items AS ( + SELECT feed_item_id + FROM feed_items_feeds + WHERE feed_id = feed_id_param + ) + SELECT fi.* + FROM feed_items fi + JOIN relevant_feed_items rfi ON fi.id = rfi.feed_item_id + ORDER BY fi.date_published DESC + LIMIT 1; + END; + $$ LANGUAGE plpgsql; + SQL + end + + def down + execute <<-SQL + DROP FUNCTION IF EXISTS get_latest_feed_item(INTEGER); + SQL + end +end diff --git a/db/schema.rb b/db/schema.rb index 0d401aaa..ef21cebf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180822171418) do +ActiveRecord::Schema.define(version: 20241009105912) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -24,13 +24,13 @@ create_table "deactivated_taggings", id: :serial, force: :cascade do |t| t.integer "tag_id" + t.string "taggable_type" t.integer "taggable_id" - t.string "taggable_type", limit: 255 + t.string "tagger_type" t.integer "tagger_id" - t.string "tagger_type", limit: 255 + t.string "deactivator_type" t.integer "deactivator_id" - t.string "deactivator_type", limit: 255 - t.string "context", limit: 255 + t.string "context" t.datetime "created_at" t.index ["deactivator_id", "deactivator_type"], name: "d_taggings_deactivator_idx" t.index ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "d_taggings_idx" @@ -43,8 +43,8 @@ t.string "title", limit: 500, null: false t.string "description", limit: 1048576 t.string "lang", limit: 2, default: "en" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.index ["lang"], name: "index_documentations_on_lang" t.index ["match_key"], name: "index_documentations_on_match_key", unique: true t.index ["title"], name: "index_documentations_on_title" @@ -61,8 +61,8 @@ t.string "rights", limit: 500 t.datetime "date_published" t.datetime "last_updated" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.text "image_url" t.index ["authors"], name: "index_feed_items_on_authors" t.index ["contributors"], name: "index_feed_items_on_contributors" @@ -90,8 +90,8 @@ t.string "info", limit: 5120 t.string "status_code", limit: 25 t.string "changelog", limit: 1048576 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" end create_table "feed_subscribers", id: :serial, force: :cascade do |t| @@ -126,8 +126,8 @@ t.string "language", limit: 25 t.boolean "bookmarking_feed", default: false t.datetime "next_scheduled_retrieval" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.boolean "unsubscribe", default: false t.index ["authors"], name: "index_feeds_on_authors" t.index ["bookmarking_feed"], name: "index_feeds_on_bookmarking_feed" @@ -139,7 +139,7 @@ end create_table "friendly_id_slugs", id: :serial, force: :cascade do |t| - t.string "slug", limit: 255, null: false + t.string "slug", null: false t.integer "sluggable_id", null: false t.string "sluggable_type", limit: 40 t.datetime "created_at" @@ -160,8 +160,8 @@ t.integer "hub_id", null: false t.string "title", limit: 500 t.string "description", limit: 2048 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.index ["feed_id"], name: "index_hub_feeds_on_feed_id" t.index ["hub_id", "feed_id"], name: "index_hub_feeds_on_hub_id_and_feed_id", unique: true t.index ["hub_id"], name: "index_hub_feeds_on_hub_id" @@ -193,11 +193,10 @@ t.string "title", limit: 500, null: false t.string "description", limit: 2048 t.string "tag_prefix", limit: 25 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "nickname", limit: 255 - t.string "slug", limit: 255 - t.text "tag_count" + t.datetime "created_at" + t.datetime "updated_at" + t.string "nickname" + t.string "slug" t.boolean "notify_taggers" t.string "tags_delimiter", default: [",", "⎵"], array: true t.string "official_tag_prefix" @@ -215,15 +214,13 @@ t.integer "item_source_id", null: false t.string "item_source_type", limit: 100, null: false t.string "effect", limit: 25, default: "add", null: false - t.integer "position" t.integer "limit" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.integer "created_by_only_id" t.index ["effect"], name: "index_input_sources_on_effect" t.index ["item_source_id"], name: "index_input_sources_on_item_source_id" t.index ["item_source_type", "item_source_id", "effect", "republished_feed_id", "created_by_only_id"], name: "bob_the_index", unique: true - t.index ["position"], name: "index_input_sources_on_position" t.index ["republished_feed_id"], name: "index_input_sources_on_republished_feed_id" end @@ -239,8 +236,8 @@ t.string "title", limit: 500, null: false t.string "description", limit: 5120 t.integer "limit", default: 50 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "url_key", limit: 50, null: false t.index ["hub_id"], name: "index_republished_feeds_on_hub_id" t.index ["title"], name: "index_republished_feeds_on_title" @@ -251,8 +248,8 @@ t.string "name", limit: 40 t.string "authorizable_type", limit: 40 t.integer "authorizable_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.index ["authorizable_id"], name: "index_roles_on_authorizable_id" t.index ["authorizable_type"], name: "index_roles_on_authorizable_type" t.index ["name"], name: "index_roles_on_name" @@ -268,20 +265,20 @@ create_table "search_remixes", id: :serial, force: :cascade do |t| t.integer "hub_id" t.text "search_string" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" end create_table "tag_filters", id: :serial, force: :cascade do |t| t.integer "hub_id", null: false t.integer "tag_id", null: false t.integer "new_tag_id" + t.string "scope_type" t.integer "scope_id" - t.string "scope_type", limit: 255 t.boolean "applied", default: false - t.string "type", limit: 255 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "type" + t.datetime "created_at" + t.datetime "updated_at" t.index ["hub_id"], name: "index_tag_filters_on_hub_id" t.index ["new_tag_id"], name: "index_tag_filters_on_new_tag_id" t.index ["scope_type", "scope_id"], name: "index_tag_filters_on_scope_type_and_scope_id" @@ -291,11 +288,11 @@ create_table "taggings", id: :serial, force: :cascade do |t| t.integer "tag_id" + t.string "taggable_type" t.integer "taggable_id" - t.string "taggable_type", limit: 255 + t.string "tagger_type" t.integer "tagger_id" - t.string "tagger_type", limit: 255 - t.string "context", limit: 255 + t.string "context" t.datetime "created_at" t.index ["context"], name: "index_taggings_on_context" t.index ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true @@ -310,7 +307,7 @@ end create_table "tags", id: :serial, force: :cascade do |t| - t.string "name", limit: 255 + t.string "name" t.integer "taggings_count", default: 0 t.index ["name"], name: "index_tags_on_name", unique: true end @@ -319,21 +316,21 @@ t.string "first_name", limit: 100 t.string "last_name", limit: 100 t.string "url", limit: 250 - t.string "email", limit: 255, default: "", null: false - t.string "encrypted_password", limit: 128, default: "", null: false - t.string "reset_password_token", limit: 255 + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.integer "sign_in_count", default: 0 t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" - t.string "current_sign_in_ip", limit: 255 - t.string "last_sign_in_ip", limit: 255 - t.string "confirmation_token", limit: 255 + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.string "confirmation_token" t.datetime "confirmed_at" t.datetime "confirmation_sent_at" t.integer "failed_attempts", default: 0 - t.string "unlock_token", limit: 255 + t.string "unlock_token" t.datetime "locked_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false