Class: RubySync::Event

Inherits:
Object show all
Includes:
Utilities
Defined in:
lib/ruby_sync/event.rb

Overview

Represents a change of some type to a record in the source datastore. If the event type is :add or :modify then the payload will be an array of RubySync::Operations describing changes to the attributes of the record.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utilities

#as_array, #call_if_exists, #class_called, #class_for_name, #class_name_for, #connector_called, #dump_after, #dump_before, #effective_operations, #ensure_dir_exists, #get_preference, #get_preference_file_path, #include_in_search_path, #log_progress, #perform_operations, #perform_transform, #pipeline_called, #set_preference, #something_called, #with_rescue

Constructor Details

#initialize(type, source, source_path = nil, association = nil, payload = nil) ⇒ Event

Returns a new instance of Event.



79
80
81
82
83
84
85
86
# File 'lib/ruby_sync/event.rb', line 79

def initialize type, source, source_path=nil, association=nil, payload=nil
  self.type = type.to_sym
  self.source = source
  self.source_path = source_path
  self.association = make_association(association)
  self.payload = payload
  @target_path = nil
end

Instance Attribute Details

#associationObject

:delete, :add, :modify, :disassociate



49
50
51
# File 'lib/ruby_sync/event.rb', line 49

def association
  @association
end

#payloadObject

:delete, :add, :modify, :disassociate



49
50
51
# File 'lib/ruby_sync/event.rb', line 49

def payload
  @payload
end

#sourceObject

:delete, :add, :modify, :disassociate



49
50
51
# File 'lib/ruby_sync/event.rb', line 49

def source
  @source
end

#source_pathObject

:delete, :add, :modify, :disassociate



49
50
51
# File 'lib/ruby_sync/event.rb', line 49

def source_path
  @source_path
end

#targetObject

:delete, :add, :modify, :disassociate



49
50
51
# File 'lib/ruby_sync/event.rb', line 49

def target
  @target
end

#target_pathObject

:delete, :add, :modify, :disassociate



49
50
51
# File 'lib/ruby_sync/event.rb', line 49

def target_path
  @target_path
end

#typeObject

:delete, :add, :modify, :disassociate



49
50
51
# File 'lib/ruby_sync/event.rb', line 49

def type
  @type
end

Class Method Details

.add(source, source_path, association = nil, payload = nil) ⇒ Object



65
66
67
# File 'lib/ruby_sync/event.rb', line 65

def self.add source, source_path, association=nil, payload=nil
  self.new(:add, source, source_path, association, payload)
end

.delete(source, source_path, association = nil) ⇒ Object



61
62
63
# File 'lib/ruby_sync/event.rb', line 61

def self.delete source, source_path, association=nil
  self.new(:delete, source, source_path, association)
end

.disassociate(source, source_path, association = nil, payload = nil) ⇒ Object

Remove the association between the entry on the source and the associated entry (if any) on the target.



75
76
77
# File 'lib/ruby_sync/event.rb', line 75

def self.disassociate source, source_path, association=nil, payload=nil
  self.new(:disassociate, source, source_path, association, payload)
end

.force_resync(source) ⇒ Object



57
58
59
# File 'lib/ruby_sync/event.rb', line 57

def self.force_resync source
  self.new(:force_resync, source)
end

.modify(source, source_path, association = nil, payload = nil) ⇒ Object



69
70
71
# File 'lib/ruby_sync/event.rb', line 69

def self.modify source, source_path, association=nil, payload=nil
  self.new(:modify, source, source_path, association, payload)
end

Instance Method Details

#add_default(field_name, value) ⇒ Object

Add a value to a given subject unless it already sets a value



199
200
201
# File 'lib/ruby_sync/event.rb', line 199

def add_default field_name, value
  add_value(field_name.to_s, value) unless sets_value? field_name.to_s
end

#add_value(field_name, value) ⇒ Object



204
205
206
# File 'lib/ruby_sync/event.rb', line 204

def add_value field_name, value
  uncommitted_operations << Operation.new(:add, field_name.to_s, as_array(value))
end

#affected_subjectsObject

Return a list of subjects that this event affects



143
144
145
# File 'lib/ruby_sync/event.rb', line 143

def affected_subjects
  @payload.map {|op| op.subject}.uniq
end

#append(new_operations) ⇒ Object

Add one or more operations to the list to be performed. The operations won’t be added to the payload until commit_changes is called and won’t be added at all if rollback_changes is called first.



237
238
239
240
# File 'lib/ruby_sync/event.rb', line 237

def append new_operations
  uncommitted_operations
  @uncommitted_operations += as_array(new_operations)
end

#associated?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/ruby_sync/event.rb', line 101

def associated?
  self.association && self.association.context && self.association.key
end

#commit_changesObject



247
248
249
250
251
252
# File 'lib/ruby_sync/event.rb', line 247

def commit_changes
  if uncommitted_operations 
    @payload = uncommitted_operations
    @uncommitted_operations = nil
  end
end

#convert_to_addObject

Retrieves all known values for the record affected by this event and sets the event’s type to :add If the source connector doesn’t implement retrieve we’ll assume thats because it can’t and that it gave us all it had to start with.



115
116
117
118
119
120
121
122
# File 'lib/ruby_sync/event.rb', line 115

def convert_to_add
  log.info "Converting '#{type}' event to add"
  if (source.respond_to? :retrieve)
    full = source.retrieve(source_path)
    payload = full.payload
  end
  @type = :add
end

#convert_to_modify(other, filter) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/ruby_sync/event.rb', line 125

def convert_to_modify(other, filter)
  log.info "Converting '#{type}' event to modify"

  # The add event contained an operation for each attribute of the source record.
  # Therefore, we should delete any attributes in the target record that don't appear
  # in the event.
  affected = affected_subjects
  other.each do |key, value|
    if filter.include?(key) and !affected.include?(key)
      log.info "Adding delete operation for #{key}"
      @payload << Operation.delete(key)
    end
  end 

  @type = :modify
end

#delete_when_blankObject



187
188
189
190
191
192
193
194
195
# File 'lib/ruby_sync/event.rb', line 187

def delete_when_blank
  @uncommitted_operations = uncommitted_operations.map do |op| 
  if op.sets_blank?
    @type == :modify ? op.same_but_as(:delete) : nil
  else
    op
  end
  end.compact
end

#downcase_subjectsObject



178
179
180
# File 'lib/ruby_sync/event.rb', line 178

def downcase_subjects
  @uncommitted_operations = uncommitted_operations.map {|op| Operation.new(op.type, op.subject.downcase, op.values)}
end

#drop_all_but_changes_to(*subjects) ⇒ Object



182
183
184
185
# File 'lib/ruby_sync/event.rb', line 182

def drop_all_but_changes_to *subjects
  subjects = subjects.flatten.collect {|s| s.to_s}
  @uncommitted_operations = uncommitted_operations.delete_if {|op| !subjects.include?(op.subject.to_s)}
end

#drop_changes_to(*subjects) ⇒ Object

Remove any operations from the payload that affect fields with the given key or keys (key can be a single field name or an array of field names).



172
173
174
175
176
# File 'lib/ruby_sync/event.rb', line 172

def drop_changes_to *subjects
  subjects = subjects.flatten.collect {|s| s.to_s}
  uncommitted_operations
  @uncommitted_operations = @uncommitted_operations.delete_if {|op| subjects.include? op.subject }
end

#effective_operation?Boolean

true unless this event in its current state would have no impact

Returns:

  • (Boolean)


273
274
275
276
277
# File 'lib/ruby_sync/event.rb', line 273

def effective_operation?
  !(
  @type == :modify && @payload.empty?
  )
end

#hintObject



147
148
149
# File 'lib/ruby_sync/event.rb', line 147

def hint
  "(#{source.name} => #{target.name}) #{source_path}"
end

#map(left, right = nil, &blk) ⇒ Object

Typically this will be called in the ‘transform_in’ and ‘transform_out’ blocks in a pipeline configuration.



256
257
258
259
260
261
262
263
264
265
266
# File 'lib/ruby_sync/event.rb', line 256

def map(left, right=nil, &blk)
  if right
    drop_changes_to left
    @uncommitted_operations = uncommitted_operations.map do |op|
      (op.subject.to_s == right.to_s)? op.same_but_on(left.to_s) : op
    end
  elsif blk and [:add, :modify].include? @type
    drop_changes_to left.to_s
    uncommitted_operations << RubySync::Operation.replace(left.to_s, blk.call) 
  end
end

#merge(other) ⇒ Object

Reduces the operations in this event to those that will alter the target record



107
108
109
# File 'lib/ruby_sync/event.rb', line 107

def merge other
  @payload = effective_operations(@payload, other)
end

#place(&blk) ⇒ Object



268
269
270
# File 'lib/ruby_sync/event.rb', line 268

def place(&blk)
  self.target_path = blk.call
end

#retrieve_association(context) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/ruby_sync/event.rb', line 88

def retrieve_association(context)
  if self.source.is_vault?
    self.association ||=  self.source.association_for(context, self.source_path)
  else
    if self.association # association key was supplied when the event was created
      self.association.context = context # just add the context
    else
      key = self.source.own_association_key_for(self.source_path)
      @association = Association.new(context, key)
    end
  end
end

#rollback_changesObject

Rollback any changes that



243
244
245
# File 'lib/ruby_sync/event.rb', line 243

def rollback_changes
  @uncommitted_operations = nil
end

#set_value(field_name, value) ⇒ Object



208
209
210
# File 'lib/ruby_sync/event.rb', line 208

def set_value field_name, value
  uncommitted_operations << Operation.new(:replace, field_name.to_s, as_array(value))
end

#sets_value?(subject, value = nil) ⇒ Boolean

True if this event will lead to the field name given being set. If value is non-nil then if it will lead to it being set to the value given. Note: This implementation is not completely accurate. Just looks at the last operation in the payload. A better implementation would look at all items that affect the named field to work out the value.

Returns:

  • (Boolean)


162
163
164
165
166
167
168
# File 'lib/ruby_sync/event.rb', line 162

def sets_value? subject, value=nil
  return false if @payload == nil
  @payload.reverse_each do |op|
    return true if op.subject == subject.to_s && (value == nil || op.values == as_array(value))
  end
  return false
end

#to_yaml_propertiesObject



152
153
154
# File 'lib/ruby_sync/event.rb', line 152

def to_yaml_properties
  %w{ @type @source_path @target_path @association @payload}
end

#uncommitted_operationsObject



224
225
226
227
# File 'lib/ruby_sync/event.rb', line 224

def uncommitted_operations
  @uncommitted_operations ||= @payload || []
  return @uncommitted_operations
end

#uncommitted_operations=(ops) ⇒ Object



229
230
231
# File 'lib/ruby_sync/event.rb', line 229

def uncommitted_operations= ops
  @uncommitted_operations = ops
end

#value_for(field_name, default = '') ⇒ Object Also known as: value_of



218
219
220
221
# File 'lib/ruby_sync/event.rb', line 218

def value_for field_name, default=''
  values = values_for field_name
  values[0] || default
end

#values_for(field_name, default = []) ⇒ Object Also known as: values_of



212
213
214
215
# File 'lib/ruby_sync/event.rb', line 212

def values_for field_name, default=[]
  values = perform_operations @payload, {}, :subjects=>[field_name.to_s]
  values[field_name.to_s] || default
end