Skip to content

Commit

Permalink
Ruby Migration generator for event_id index
Browse files Browse the repository at this point in the history
RES Browser slowed down when displaying event overview.
It turned out it was because of "Event Streams" involving full table scan on
event_store_events_in_streams. Adding the index fixes the issue,
obviously.

Co-authored-by: Łukasz Reszke <[email protected]>
  • Loading branch information
lukaszreszke authored and fidel committed Jul 18, 2023
1 parent 0b6c34e commit 5c2c367
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_relative "active_record/generators/rails_migration_generator"
require_relative "active_record/generators/templates/template_directory"
require_relative "active_record/generators/verify_data_type_for_adapter"
require_relative "active_record/generators/event_id_index_migration_generator"
require_relative "active_record/event"
require_relative "active_record/with_default_models"
require_relative "active_record/with_abstract_base_class"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

module RubyEventStore
module ActiveRecord
class EventIdIndexMigrationGenerator
def call(migration_path)
path = build_path(migration_path)
write_to_file(path)
path
end

private

def absolute_path(path)
File.expand_path(path, __dir__)
end

def migration_code
migration_template.result_with_hash(migration_version: migration_version)
end

def migration_template
ERB.new(
File.read(
File.join(absolute_path("./templates"), "add_event_id_index_to_event_store_events_in_streams_template.erb")
)
)
end

def migration_version
::ActiveRecord::Migration.current_version
end

def timestamp
Time.now.strftime("%Y%m%d%H%M%S")
end

def write_to_file(path)
File.write(path, migration_code)
end

def build_path(migration_path)
File.join("#{migration_path}", "#{timestamp}_add_event_id_index_to_event_store_events_in_streams.rb")
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class AddEventIdIndexToEventStoreEventsInStreams < ActiveRecord::Migration[<%= migration_version %>]
def change
return if index_exists?(:event_store_events_in_streams, :event_id)

add_index :event_store_events_in_streams, [:event_id]
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# frozen_string_literal: true

require "spec_helper"
require_relative "../../support/helpers/silence_stdout"

module RubyEventStore
module ActiveRecord
::RSpec.describe EventIdIndexMigrationGenerator do
around { |example| SilenceStdout.silence_stdout { example.run } }
around do |example|
begin
@dir = Dir.mktmpdir(nil, "./")
example.call
ensure
FileUtils.rm_r(@dir)
FileUtils.rm_f(["./20221130213700_add_event_id_index_to_event_store_events_in_streams.rb"])
end
end

before { allow(Time).to receive(:now).and_return(Time.new(2022, 11, 30, 21, 37, 00)) }

specify "it is created within specified directory" do
migration_generator(@dir)

expect(migration_exists?(@dir)).to be_truthy
end

specify "returns path to migration file" do
path = migration_generator(@dir)

expected_path = "#{@dir}/20221130213700_add_event_id_index_to_event_store_events_in_streams.rb"
expect(path).to match(expected_path)
end

specify "uses particular migration version" do
migration_generator(@dir)

expect(read_migration(@dir)).to include("ActiveRecord::Migration[#{::ActiveRecord::Migration.current_version}]")
end

specify "uses particular migration version for rails 6.0" do
skip unless ENV["BUNDLE_GEMFILE"]&.include?("rails_6_0")

migration_generator(@dir)

expect(read_migration(@dir)).to include("ActiveRecord::Migration[6.0]")
end

specify "uses particular migration version for rails 6.1" do
skip unless ENV["BUNDLE_GEMFILE"]&.include?("rails_6_1")

migration_generator(@dir)

expect(read_migration(@dir)).to include("ActiveRecord::Migration[6.1]")
end

private

def migration_generator(dir)
EventIdIndexMigrationGenerator.new.call(dir)
end

def migration_exists?(dir)
File.exist?("#{dir}/20221130213700_add_event_id_index_to_event_store_events_in_streams.rb")
end

def read_migration(dir)
File.read("#{dir}/20221130213700_add_event_id_index_to_event_store_events_in_streams.rb")
end
end
end
end
6 changes: 3 additions & 3 deletions ruby_event_store-active_record/spec/migration_test_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ module ActiveRecord
Indexes:
"event_store_events_in_streams_pkey" PRIMARY KEY, btree (id)
"index_event_store_events_in_streams_on_created_at" btree (created_at)
"index_event_store_events_in_streams_on_event_id" btree (event_id)
"index_event_store_events_in_streams_on_stream_and_event_id" UNIQUE, btree (stream, event_id)
"index_event_store_events_in_streams_on_stream_and_position" UNIQUE, btree (stream, "position")
"index_event_store_events_in_streams_on_event_id" btree (event_id)
SCHEMA
end

Expand Down Expand Up @@ -101,8 +101,8 @@ module ActiveRecord
PRIMARY KEY (`id`),
UNIQUE KEY `index_event_store_events_in_streams_on_stream_and_event_id` (`stream`,`event_id`),
UNIQUE KEY `index_event_store_events_in_streams_on_stream_and_position` (`stream`,`position`),
KEY `index_event_store_events_in_streams_on_event_id` (`event_id`),
KEY `index_event_store_events_in_streams_on_created_at` (`created_at`)
KEY `index_event_store_events_in_streams_on_created_at` (`created_at`),
KEY `index_event_store_events_in_streams_on_event_id` (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=#{charset}#{collation}
SCHEMA
end
Expand Down

0 comments on commit 5c2c367

Please sign in to comment.