Class: RR::Syncers::TwoWaySyncer

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyrep/syncers/two_way_syncer.rb

Overview

This syncer implements a two way sync. Syncer options relevant for this syncer:

  • :left_record_handling, :right_record_handling: Handling of records only existing only in the named database. Can be any of the following:

    • :ignore: No action.

    • :delete: Delete from the source database.

    • :insert: Insert in the target database. Default Setting

    • Proc object: If a Proc object is given, it is responsible for dealing with the record. Called with the following parameters:

      • sync_helper: The current SyncHelper instance.

      • type: :left or :right to designate source database

      • row: column_name => value hash representing the row

  • :sync_conflict_handling: Handling of conflicting records. Can be any of the following:

    • :ignore: No action. Default Setting

    • :left_wins: Update right database with the field values in the left db.

    • :right_wins: Update left database with the field values in the right db.

    • Proc object: If a Proc object is given, it is responsible for dealing with the record. Called with the following parameters:

      • sync_helper: The current SyncHelper instance.

      • type: always :conflict

      • rows: A two element array of rows (column_name => value hashes). First left, than right record.

  • :logged_sync_events: Specifies which types of syncs are logged. Is either a single value or an array of multiple ones. Default: [:ignored_conflicts] Possible values:

    • :ignored_changes: log ignored (but not synced) non-conflict changes

    • :all_changes: log all non-conflict changes

    • :ignored_conflicts: log ignored (but not synced) conflicts

    • :all_conflicts: log all conflicts

Example of using a Proc object:

lambda do |sync_helper, type, row|
  # delete records existing only in the left database.
  sync_helper.delete(type, row) if type == :left
end

Constant Summary collapse

TYPE_DESCRIPTIONS =

Sync type descriptions that are written into the event log

{
  :left => 'left_record',
  :right => 'right_record',
  :conflict => 'conflict'
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sync_helper) ⇒ TwoWaySyncer

Initializes the syncer

  • sync_helper: The SyncHelper object provided information and utility functions.

Raises an ArgumentError if any of the option in sync_helper.sync_options is invalid.



100
101
102
103
104
105
106
107
# File 'lib/rubyrep/syncers/two_way_syncer.rb', line 100

def initialize(sync_helper)
  validate_left_right_record_handling_option sync_helper.sync_options[:left_record_handling]
  validate_left_right_record_handling_option sync_helper.sync_options[:right_record_handling]
  validate_conflict_handling_option sync_helper.sync_options[:sync_conflict_handling]
  validate_logging_options sync_helper.sync_options[:logged_sync_events]
  
  self.sync_helper = sync_helper
end

Instance Attribute Details

#sync_helperObject

The current SyncHelper object



50
51
52
# File 'lib/rubyrep/syncers/two_way_syncer.rb', line 50

def sync_helper
  @sync_helper
end

Class Method Details

.default_optionsObject

Provides default option for the syncer. Optional. Returns a hash with key => value pairs.



54
55
56
57
58
59
60
61
# File 'lib/rubyrep/syncers/two_way_syncer.rb', line 54

def self.default_options
  {
    :left_record_handling => :insert,
    :right_record_handling => :insert,
    :sync_conflict_handling => :ignore,
    :logged_sync_events => [:ignored_conflicts]
  }
end

Instance Method Details

#log_sync_outcome(type, action, row) ⇒ Object

Logs a sync event into the event log table as per configuration options.

  • type: Refer to DirectTableScan#run for a description

  • action: the sync action that is executed (The :left_record_handling / :right_record_handling or :sync_conflict_handling option)

  • row: Refer to DirectTableScan#run for a description



128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/rubyrep/syncers/two_way_syncer.rb', line 128

def log_sync_outcome(type, action, row)
  if type == :conflict
    return unless log_option_values.include?(:all_conflicts) or log_option_values.include?(:ignored_conflicts)
    return if action != :ignore and not log_option_values.include?(:all_conflicts)
    row = row[0] # Extract left row from row array
  else
    return unless log_option_values.include?(:all_changes) or log_option_values.include?(:ignored_changes)
    return if action != :ignore and not log_option_values.include?(:all_changes)
  end

  sync_helper.log_sync_outcome row, TYPE_DESCRIPTIONS[type], action
end

#sync_difference(type, row) ⇒ Object

Called to sync the provided difference. See DirectTableScan#run for a description of the type and row parameters.



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/rubyrep/syncers/two_way_syncer.rb', line 143

def sync_difference(type, row)
  if type == :left or type == :right
    option_key = type == :left ? :left_record_handling : :right_record_handling
    option = sync_helper.sync_options[option_key]
    log_sync_outcome type, option, row unless option.respond_to?(:call)
    if option == :ignore
      # nothing to do
    elsif option == :delete
      sync_helper.delete_record type, sync_helper.tables[type], row
    elsif option == :insert
      target = (type == :left ? :right : :left)
      sync_helper.insert_record target, sync_helper.tables[target], row
    else #option must be a Proc
      option.call sync_helper, type, row
    end
  else
    option = sync_helper.sync_options[:sync_conflict_handling]
    log_sync_outcome type, option, row unless option.respond_to?(:call)
    if option == :ignore
      # nothing to do
    elsif option == :right_wins
      sync_helper.update_record :left, sync_helper.tables[:left], row[1]
    elsif option == :left_wins
      sync_helper.update_record :right, sync_helper.tables[:right], row[0]
    else #option must be a Proc
      option.call sync_helper, type, row
    end
  end
end

#validate_conflict_handling_option(option) ⇒ Object

Verifies if the given :sync_conflict_handling option is valid. Raises an ArgumentError if option is invalid



76
77
78
79
80
81
82
# File 'lib/rubyrep/syncers/two_way_syncer.rb', line 76

def validate_conflict_handling_option(option)
  unless option.respond_to? :call
    unless [:ignore, :right_wins, :left_wins].include? option
      raise ArgumentError.new("#{option.inspect} not a valid :sync_conflict_handling option")
    end
  end
end

#validate_left_right_record_handling_option(option) ⇒ Object

Verifies if the given :left_record_handling / :right_record_handling option is valid. Raises an ArgumentError if option is invalid



66
67
68
69
70
71
72
# File 'lib/rubyrep/syncers/two_way_syncer.rb', line 66

def validate_left_right_record_handling_option(option)
  unless option.respond_to? :call
    unless [:ignore, :delete, :insert].include? option
      raise ArgumentError.new("#{option.inspect} not a valid :left_record_handling / :right_record_handling option")
    end
  end
end

#validate_logging_options(options) ⇒ Object

Verifies if the given :replication_logging option /options is / are valid. Raises an ArgumentError if invalid



86
87
88
89
90
91
92
93
# File 'lib/rubyrep/syncers/two_way_syncer.rb', line 86

def validate_logging_options(options)
  values = [options].flatten # ensure that I have an array
  values.each do |value|
    unless [:ignored_changes, :all_changes, :ignored_conflicts, :all_conflicts].include? value
      raise ArgumentError.new("#{value.inspect} not a valid :logged_sync_events option")
    end
  end
end