Class: RubyLLM::Generators::UpgradeMigration

Inherits:
Object
  • Object
show all
Defined in:
lib/generators/ruby_llm/upgrade/upgrade_migration.rb

Overview

:nodoc: all

Constant Summary collapse

TABLE =
:ruby_llm_v2_upgrades
VERSION_COLUMN =
:ruby_llm_version

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection: ::ActiveRecord::Base.connection) ⇒ UpgradeMigration

Returns a new instance of UpgradeMigration.



14
15
16
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 14

def initialize(connection: ::ActiveRecord::Base.connection)
  @connection = connection
end

Class Method Details

.for(connection: ::ActiveRecord::Base.connection) ⇒ Object



9
10
11
12
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 9

def self.for(connection: ::ActiveRecord::Base.connection)
  require_relative 'online_copy_migration'
  OnlineCopyMigration.new(connection:)
end

Instance Method Details

#activateObject



79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 79

def activate
  state = states.first!
  return if state.active_version == 2 && state.status == 'active'

  unless %w[preparing reconciling].include?(state.status) || (state.active_version == 1 && state.needs_reconcile)
    raise 'Expected an unfinished copy upgrade'
  end

  raise 'Run the copy backfill before activating 2.0' if state.needs_reconcile

  state.update!(active_version: 2, status: 'active', needs_reconcile: false)
end

#backfill(force: true) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 64

def backfill(force: true)
  state = states.first!
  state.with_lock do
    unless %w[preparing reconciling].include?(state.status) ||
           (state.active_version == 1 && state.needs_reconcile)
      raise 'Expected an unfinished copy upgrade'
    end
    return if !force && !state.needs_reconcile

    state.update!(status: 'preparing', needs_reconcile: true)
  end
  reconcile
  state.update!(needs_reconcile: false)
end

#cleanupObject



139
140
141
142
143
144
145
146
147
148
149
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 139

def cleanup
  verify_cleanup
  settings = configuration
  legacy_tables = settings.values_at('model_table', 'tool_call_table')
  remove_legacy_foreign_keys(legacy_tables)
  chats = settings.fetch('chat_table')
  column = settings.fetch('model_foreign_key')
  @connection.remove_column(chats, column) if @connection.column_exists?(chats, column)
  @connection.remove_column(chats, VERSION_COLUMN) if @connection.column_exists?(chats, VERSION_COLUMN)
  legacy_tables.reverse_each { |table| @connection.drop_table(table) if @connection.table_exists?(table) }
end

#copy_model_referencesObject



57
58
59
60
61
62
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 57

def copy_model_references
  records(configuration.fetch('chat_table')).find_each do |chat|
    model = resolve_model(chat[configuration.fetch('model_foreign_key')])
    chat.update!(ruby_llm_model_id: model&.id)
  end
end

#copy_table(source, target) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 41

def copy_table(source, target)
  return if @connection.table_exists?(target)

  source_records = records(source)
  create_copy_table(source, target)
  columns = source_records.column_names & records(target).column_names
  names = columns.map { |column| @connection.quote_column_name(column) }.join(', ')
  key = @connection.quote_column_name(source_records.primary_key)
  @connection.execute(<<~SQL)
    INSERT INTO #{@connection.quote_table_name(target)} (#{names})
    SELECT #{names} FROM #{@connection.quote_table_name(source)}
    WHERE #{key} NOT IN (SELECT #{key} FROM #{@connection.quote_table_name(target)})
  SQL
  @connection.reset_pk_sequence!(target) if @connection.respond_to?(:reset_pk_sequence!)
end

#finalizeObject



123
124
125
126
127
128
129
130
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 123

def finalize
  state = states.first!
  state.with_lock do
    require_active_version(state, 2)
    verify_completed_work
    state.update!(status: 'finalized')
  end
end

#online?Boolean

Returns:

  • (Boolean)


39
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 39

def online? = false

#prepare(settings) ⇒ Object



18
19
20
21
22
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 18

def prepare(settings)
  create_state_table unless @connection.table_exists?(TABLE)
  prepare_state(settings)
  yield if block_given?
end

#resumeObject



109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 109

def resume
  state = states.first!
  state.with_lock do
    unless state.active_version == 1 && %w[active reconciling].include?(state.status)
      raise 'Resume requires a copy upgrade running on 1.16'
    end
    raise 'Finish the initial copy migrations before resuming 2.0' if state.needs_reconcile

    state.update!(status: 'reconciling')
  end
  reconcile
  state.update!(active_version: 2, status: 'active')
end

#rollbackObject



98
99
100
101
102
103
104
105
106
107
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 98

def rollback
  state = states.first!
  if state.active_version == 1 && %w[preparing reconciling].include?(state.status)
    state.with_lock do
      state.update!(status: 'active', needs_reconcile: state.needs_reconcile || state.status == 'preparing')
    end
    return
  end
  transition(2, 1) { verify_completed_work }
end

#verify_cleanupObject



132
133
134
135
136
137
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 132

def verify_cleanup
  state = states.first!
  return if state.active_version == 2 && state.status == 'finalized'

  raise 'Run ruby_llm:upgrade:finalize on 2.0 before copy-mode cleanup'
end

#verify_settings(settings) ⇒ Object



92
93
94
95
96
# File 'lib/generators/ruby_llm/upgrade/upgrade_migration.rb', line 92

def verify_settings(settings)
  return if configuration == settings.stringify_keys

  raise 'Use the same model mappings for every copy-upgrade phase'
end