Skip to content

Commit 2d50909

Browse files
fix: ensure proper migration order for database schema
test
1 parent 24467aa commit 2d50909

File tree

4 files changed

+47
-4
lines changed

4 files changed

+47
-4
lines changed

lib/generators/ruby_llm/install/templates/create_messages_migration.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
# This migration must be run AFTER create_chats and create_tool_calls migrations
4+
# to ensure proper foreign key references
35
class CreateMessages < ActiveRecord::Migration<%= migration_version %>
46
def change
57
create_table :messages do |t|
@@ -9,7 +11,7 @@ def change
911
t.string :model_id
1012
t.integer :input_tokens
1113
t.integer :output_tokens
12-
t.references :tool_call
14+
t.references :tool_call, foreign_key: true
1315
t.timestamps
1416
end
1517
end

lib/generators/ruby_llm/install/templates/create_tool_calls_migration.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
class CreateToolCalls < ActiveRecord::Migration<%= migration_version %>
55
def change
66
create_table :tool_calls do |t|
7-
t.references :message, null: false, foreign_key: true
7+
# No reference to message to avoid circular references
8+
# Messages will reference tool_calls, not the other way around
89
t.string :tool_call_id, null: false
910
t.string :name, null: false
1011

lib/generators/ruby_llm/install_generator.rb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,23 @@ def postgresql?
2727
end
2828

2929
def create_migration_files
30+
# Create migrations in the correct order with sequential timestamps
31+
# to ensure proper foreign key references:
32+
# 1. First create chats (no dependencies)
33+
# 2. Then create tool_calls (will be referenced by messages)
34+
# 3. Finally create messages (depends on both chats and tool_calls)
35+
36+
# Use a fixed timestamp for testing and to ensure they're sequential
37+
@migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S")
3038
migration_template "create_chats_migration.rb", "db/migrate/create_chats.rb"
31-
migration_template "create_messages_migration.rb", "db/migrate/create_messages.rb"
39+
40+
# Increment timestamp for the next migration
41+
@migration_number = (@migration_number.to_i + 1).to_s
3242
migration_template "create_tool_calls_migration.rb", "db/migrate/create_tool_calls.rb"
43+
44+
# Increment timestamp again for the final migration
45+
@migration_number = (@migration_number.to_i + 2).to_s
46+
migration_template "create_messages_migration.rb", "db/migrate/create_messages.rb"
3347
end
3448

3549
def create_model_files

spec/lib/generators/ruby_llm/template_files_spec.rb

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@
3030
expect(message_migration).to include("t.references :chat")
3131
expect(message_migration).to include("t.string :role")
3232
expect(message_migration).to include("t.text :content")
33+
expect(message_migration).to include("t.references :tool_call")
3334

3435
tool_call_migration = File.read(File.join(template_dir, "create_tool_calls_migration.rb"))
3536
expect(tool_call_migration).to include("create_table :tool_calls")
36-
expect(tool_call_migration).to include("t.references :message")
37+
expect(tool_call_migration).to include("# No reference to message to avoid circular references")
3738
expect(tool_call_migration).to include("t.string :tool_call_id")
3839
expect(tool_call_migration).to include("t.string :name")
3940

@@ -97,6 +98,31 @@
9798
expect(generator_content).to include("def create_model_files")
9899
expect(generator_content).to include("def create_initializer")
99100
end
101+
102+
it "creates migrations in the correct order" do
103+
generator_file = "/Users/kieranklaassen/rails/ruby_llm/lib/generators/ruby_llm/install_generator.rb"
104+
generator_content = File.read(generator_file)
105+
106+
# Check for correct order in migration creation
107+
# 1. First chats table (no dependencies)
108+
# 2. Then tool_calls table (will be referenced by messages)
109+
# 3. Finally messages table (depends on both chats and tool_calls)
110+
111+
# Simply check the order of template calls
112+
# Chats should come before tool_calls, which should come before messages
113+
chats_position = generator_content.index('create_chats.rb')
114+
tool_calls_position = generator_content.index('create_tool_calls.rb')
115+
messages_position = generator_content.index('create_messages.rb')
116+
117+
# Verify order: chats -> tool_calls -> messages
118+
expect(chats_position).to be < tool_calls_position
119+
expect(tool_calls_position).to be < messages_position
120+
121+
# Also test that the method enforces sequential timestamps
122+
expect(generator_content).to include("@migration_number = Time.now.utc.strftime")
123+
expect(generator_content).to include("@migration_number = (@migration_number.to_i + 1).to_s")
124+
expect(generator_content).to include("@migration_number = (@migration_number.to_i + 2).to_s")
125+
end
100126
end
101127

102128
describe "database adapter detection" do

0 commit comments

Comments
 (0)