diff --git a/app/models/message/pagination.rb b/app/models/message/pagination.rb index 0e7690b..4e3d743 100644 --- a/app/models/message/pagination.rb +++ b/app/models/message/pagination.rb @@ -36,7 +36,10 @@ module Message::Pagination scope :page_after, ->(message) { after(message).first_page } scope :page_created_since, ->(time) { where("created_at > ?", time).first_page } - scope :page_updated_since, ->(time) { where("updated_at > ?", time).last_page } + # Sorting on +created_at, which no index covers, has SQLite find the few messages updated since + # through (room_id, updated_at) and sort just those, instead of walking the whole room by + # (room_id, created_at) looking for them. + scope :page_updated_since, ->(time) { Page.load(where("updated_at > ?", time).reorder(Arel.sql("+messages.created_at")), :last, PAGE_SIZE) } end class_methods do diff --git a/db/migrate/20261005022000_add_room_id_and_updated_at_index_to_messages.rb b/db/migrate/20261005022000_add_room_id_and_updated_at_index_to_messages.rb new file mode 100644 index 0000000..dd53cc5 --- /dev/null +++ b/db/migrate/20261005022000_add_room_id_and_updated_at_index_to_messages.rb @@ -0,0 +1,5 @@ +class AddRoomIdAndUpdatedAtIndexToMessages < ActiveRecord::Migration[8.2] + def change + add_index :messages, %i[ room_id updated_at ], if_not_exists: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 8a900cb..460193a 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[8.2].define(version: 2026_10_04_225000) do +ActiveRecord::Schema[8.2].define(version: 2026_10_05_022000) do create_table "accounts", force: :cascade do |t| t.datetime "created_at", null: false t.text "custom_styles" @@ -102,6 +102,7 @@ ActiveRecord::Schema[8.2].define(version: 2026_10_04_225000) do t.datetime "updated_at", null: false t.index ["creator_id"], name: "index_messages_on_creator_id" t.index ["room_id", "created_at"], name: "index_messages_on_room_id_and_created_at" + t.index ["room_id", "updated_at"], name: "index_messages_on_room_id_and_updated_at" t.index ["room_id"], name: "index_messages_on_room_id" end diff --git a/test/models/message/pagination_test.rb b/test/models/message/pagination_test.rb new file mode 100644 index 0000000..261a9e9 --- /dev/null +++ b/test/models/message/pagination_test.rb @@ -0,0 +1,16 @@ +require "test_helper" + +class Message::PaginationTest < ActiveSupport::TestCase + test "messages updated since a time are the newest page of them, in creation order" do + room = rooms(:watercooler) + first, second, third = room.messages.ordered.first(3) + + travel 1.minute do + [ third, first, second ].each(&:touch) + + stub_const(Message::Pagination, :PAGE_SIZE, 2) do + assert_equal [ second, third ], room.messages.page_updated_since(30.seconds.ago).to_a + end + end + end +end