Class: DataShifter::Shift

Inherits:
Object
  • Object
show all
Includes:
Axn
Defined in:
lib/data_shifter/shift.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.allow_external_requests(hosts) ⇒ Object

Allow these hosts (or regexes) for HTTP during dry run only. Combines with DataShifter.config.allow_external_requests. Has no effect in commit mode — HTTP is unrestricted when dry_run is false. Example: allow_external_requests [“api.readonly.example.com”, %rinternal.internal.companyz]



123
124
125
# File 'lib/data_shifter/shift.rb', line 123

def allow_external_requests(hosts)
  self._allow_external_requests = Array(hosts)
end

.description(text = nil) ⇒ Object



79
80
81
82
83
84
85
# File 'lib/data_shifter/shift.rb', line 79

def description(text = nil)
  if text.nil?
    _description
  else
    self._description = text.to_s.presence
  end
end

.progress(enabled = nil) ⇒ Object



108
109
110
111
112
113
114
# File 'lib/data_shifter/shift.rb', line 108

def progress(enabled = nil)
  if enabled.nil?
    _progress_enabled
  else
    self._progress_enabled = !!enabled
  end
end

.run!Object

Raises:

  • (StandardError)


148
149
150
151
152
153
# File 'lib/data_shifter/shift.rb', line 148

def run!
  dry_run = Internal::Env.dry_run?
  result = call(dry_run:)
  raise result.exception if result.exception
  raise StandardError, result.error unless result.ok?
end

.suppress_repeated_logs(enabled) ⇒ Object

Enable/disable log deduplication for this shift. Overrides DataShifter.config.suppress_repeated_logs. Example: suppress_repeated_logs false



129
130
131
# File 'lib/data_shifter/shift.rb', line 129

def suppress_repeated_logs(enabled)
  self._suppress_repeated_logs = !!enabled
end

.task(label = nil, &block) ⇒ Object

Define a task block to run instead of collection/process_record. Multiple blocks run in sequence; labels appear in errors and summary. Example:

task "Fix user A" do
  User.find(123).update!(...)
end
task "Fix user B" do
  User.find(456).update!(...)
end

Raises:

  • (ArgumentError)


142
143
144
145
146
# File 'lib/data_shifter/shift.rb', line 142

def task(label = nil, &block)
  raise ArgumentError, "task requires a block" unless block_given?

  self._task_blocks = (_task_blocks || []).dup + [{ label: label.presence, block: }]
end

.task_name(value = nil) ⇒ Object



87
88
89
90
91
92
93
# File 'lib/data_shifter/shift.rb', line 87

def task_name(value = nil)
  if value.nil?
    _task_name
  else
    self._task_name = value.to_s.presence
  end
end

.throttle(interval) ⇒ Object



116
117
118
# File 'lib/data_shifter/shift.rb', line 116

def throttle(interval)
  self._throttle_interval = interval
end

.transaction(mode) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/data_shifter/shift.rb', line 95

def transaction(mode)
  case mode
  when :per_record
    self._transaction_mode = :per_record
  when :none, false
    self._transaction_mode = :none
  when :single, true
    self._transaction_mode = :single
  else
    raise ArgumentError, "Invalid transaction mode: #{mode.inspect}. Expected :single, :per_record, :none, true, or false."
  end
end

Instance Method Details

#callObject

— Public API (intentionally exposed to subclasses) —



158
159
160
161
162
163
164
# File 'lib/data_shifter/shift.rb', line 158

def call
  if self.class._task_blocks.any?
    _run_task_blocks
  else
    _for_each_record_in(collection) { |record| process_record(record) }
  end
end

#dry_run?Boolean

Returns:

  • (Boolean)


177
# File 'lib/data_shifter/shift.rb', line 177

def dry_run? = dry_run

#find_exactly!(model, ids) ⇒ Object



166
167
168
169
170
171
172
173
174
175
# File 'lib/data_shifter/shift.rb', line 166

def find_exactly!(model, ids)
  ids = Array(ids).compact.uniq
  return model.none if ids.empty?

  records_by_id = model.where(id: ids).index_by(&:id)
  missing = ids.reject { |id| records_by_id.key?(id) }
  raise "Expected #{model.name} with ids #{ids.inspect}, but missing: #{missing.inspect}" if missing.any?

  ids.map { |id| records_by_id[id] }
end

#log(message) ⇒ Object



186
187
188
# File 'lib/data_shifter/shift.rb', line 186

def log(message)
  puts Internal::Colors.dim(message)
end

#skip!(reason = nil) ⇒ Object

Raises:

  • (SkipRecord)


179
180
181
182
183
184
# File 'lib/data_shifter/shift.rb', line 179

def skip!(reason = nil)
  @stats[:skipped] += 1
  key = reason.to_s.presence || "(no reason given)"
  @skip_reasons[key] += 1
  raise SkipRecord
end