Class: SheetsDB::Worksheet::Row

Inherits:
Object
  • Object
show all
Defined in:
lib/sheets_db/worksheet/row.rb

Defined Under Namespace

Classes: AssociationAlreadyRegisteredError, AttributeAlreadyRegisteredError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(worksheet:, row_position:) ⇒ Row

Returns a new instance of Row.



108
109
110
111
112
113
114
# File 'lib/sheets_db/worksheet/row.rb', line 108

def initialize(worksheet:, row_position:)
  @worksheet = worksheet
  @row_position = row_position
  @loaded_attributes = {}
  @loaded_associations = {}
  @changed_foreign_items = []
end

Instance Attribute Details

#changed_foreign_itemsObject (readonly)

Returns the value of attribute changed_foreign_items.



106
107
108
# File 'lib/sheets_db/worksheet/row.rb', line 106

def changed_foreign_items
  @changed_foreign_items
end

#loaded_associationsObject (readonly)

Returns the value of attribute loaded_associations.



106
107
108
# File 'lib/sheets_db/worksheet/row.rb', line 106

def loaded_associations
  @loaded_associations
end

#loaded_attributesObject (readonly)

Returns the value of attribute loaded_attributes.



106
107
108
# File 'lib/sheets_db/worksheet/row.rb', line 106

def loaded_attributes
  @loaded_attributes
end

#row_positionObject (readonly)

Returns the value of attribute row_position.



106
107
108
# File 'lib/sheets_db/worksheet/row.rb', line 106

def row_position
  @row_position
end

#worksheetObject (readonly)

Returns the value of attribute worksheet.



106
107
108
# File 'lib/sheets_db/worksheet/row.rb', line 106

def worksheet
  @worksheet
end

Class Method Details

.association_definitionsObject



101
102
103
# File 'lib/sheets_db/worksheet/row.rb', line 101

def association_definitions
  attribute_definitions.select { |_, value| value[:association] }
end

.attribute(name, type: String, multiple: false, transform: nil, column_name: nil, if_column_missing: nil) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/sheets_db/worksheet/row.rb', line 16

def attribute(name, type: String, multiple: false, transform: nil, column_name: nil, if_column_missing: nil)
  register_attribute(name, type: type, multiple: multiple, transform: transform, column_name: (column_name || name).to_s, association: false, if_column_missing: if_column_missing)

  define_method(name) do
    begin
      get_modified_attribute(name)
    rescue KeyError
      get_persisted_attribute(name)
    end
  end

  define_method("#{name}=") do |value|
    stage_attribute_modification(name, value)
  end
end

.attribute_definitionsObject



97
98
99
# File 'lib/sheets_db/worksheet/row.rb', line 97

def attribute_definitions
  @attribute_definitions ||= {}
end

.belongs_to_association(name, from_collection:, foreign_key:, multiple: false) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/sheets_db/worksheet/row.rb', line 57

def belongs_to_association(name, from_collection:, foreign_key:, multiple: false)
  register_attribute(name, from_collection: from_collection, foreign_key: foreign_key, multiple: multiple, association: true)

  define_method(name) do
    @loaded_associations[name] ||= begin
      response = spreadsheet.find_associations_by_attribute(from_collection, foreign_key, id)
      multiple ? response : response.first
    end
  end

  define_method("#{name}=") do |value|
    existing_values = Array(send(name))
    Array(value).each do |foreign_item|
      next if existing_values.delete(foreign_item)
      foreign_item.add_element_to_attribute(foreign_key, id)
      @changed_foreign_items << foreign_item
    end
    existing_values.each do |existing_foreign_item|
      existing_foreign_item.remove_element_from_attribute(foreign_key, id)
      @changed_foreign_items << existing_foreign_item
    end
    @loaded_associations[name] = value
  end
end

.belongs_to_many(name, from_collection:, foreign_key:) ⇒ Object



86
87
88
# File 'lib/sheets_db/worksheet/row.rb', line 86

def belongs_to_many(name, from_collection:, foreign_key:)
  belongs_to_association(name, from_collection: from_collection, foreign_key: foreign_key, multiple: true)
end

.belongs_to_one(name, from_collection:, foreign_key:) ⇒ Object



82
83
84
# File 'lib/sheets_db/worksheet/row.rb', line 82

def belongs_to_one(name, from_collection:, foreign_key:)
  belongs_to_association(name, from_collection: from_collection, foreign_key: foreign_key, multiple: false)
end

.has_association(name, from_collection:, key:, multiple: false) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/sheets_db/worksheet/row.rb', line 32

def has_association(name, from_collection:, key:, multiple: false)
  register_attribute(name, from_collection: from_collection, key: key, multiple: multiple, association: true)

  define_method(name) do
    @loaded_associations[name] ||= begin
      response = spreadsheet.find_associations_by_ids(from_collection, Array(send(key)))
      multiple ? response : response.first
    end
  end

  define_method("#{name}=") do |value|
    assignment_value = multiple ? value.map(&:id) : value.id
    send("#{key}=", assignment_value)
    @loaded_associations[name] = value
  end
end

.has_many(name, from_collection:, key:) ⇒ Object



53
54
55
# File 'lib/sheets_db/worksheet/row.rb', line 53

def has_many(name, from_collection:, key:)
  has_association(name, from_collection: from_collection, key: key, multiple: true)
end

.has_one(name, from_collection:, key:) ⇒ Object



49
50
51
# File 'lib/sheets_db/worksheet/row.rb', line 49

def has_one(name, from_collection:, key:)
  has_association(name, from_collection: from_collection, key: key, multiple: false)
end

.inherited(subclass) ⇒ Object



8
9
10
11
12
13
14
# File 'lib/sheets_db/worksheet/row.rb', line 8

def inherited(subclass)
  super
  subclass.instance_variable_set(
    :@attribute_definitions,
    Marshal.load(Marshal.dump(@attribute_definitions))
  )
end

.register_attribute(name, **options) ⇒ Object



90
91
92
93
94
95
# File 'lib/sheets_db/worksheet/row.rb', line 90

def register_attribute(name, **options)
  if attribute_definitions.fetch(name, nil)
    raise AttributeAlreadyRegisteredError, name
  end
  attribute_definitions[name] = options
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



246
247
248
249
250
# File 'lib/sheets_db/worksheet/row.rb', line 246

def ==(other)
  other.is_a?(self.class) &&
    other.worksheet == worksheet &&
    other.row_position == row_position
end

#add_element_to_attribute(name, value) ⇒ Object



164
165
166
# File 'lib/sheets_db/worksheet/row.rb', line 164

def add_element_to_attribute(name, value)
  modify_collection_attribute(name, value, remove: false)
end

#assign_next_row_position_if_not_setObject



184
185
186
# File 'lib/sheets_db/worksheet/row.rb', line 184

def assign_next_row_position_if_not_set
  @row_position ||= worksheet.next_available_row_position
end

#associationsObject



215
216
217
218
219
# File 'lib/sheets_db/worksheet/row.rb', line 215

def associations
  get_all_attributes do |options|
    options.fetch(:association, false)
  end
end

#attributesObject



209
210
211
212
213
# File 'lib/sheets_db/worksheet/row.rb', line 209

def attributes
  get_all_attributes do |options|
    !options.fetch(:association, false)
  end
end

#column_namesObject



116
117
118
# File 'lib/sheets_db/worksheet/row.rb', line 116

def column_names
  worksheet.column_names
end

#get_all_attributes(&block) ⇒ Object



221
222
223
224
225
226
# File 'lib/sheets_db/worksheet/row.rb', line 221

def get_all_attributes(&block)
  self.class.attribute_definitions.each_with_object({}) { |(name, options), memo|
    memo[name] = send(name) if block.call(options)
    memo
  }
end

#get_modified_attribute(name) ⇒ Object



124
125
126
127
# File 'lib/sheets_db/worksheet/row.rb', line 124

def get_modified_attribute(name)
  loaded_attributes.fetch(name, {}).
    fetch(:changed)
end

#get_persisted_attribute(name) ⇒ Object



129
130
131
132
133
# File 'lib/sheets_db/worksheet/row.rb', line 129

def get_persisted_attribute(name)
  loaded_attributes[name] ||= {}
  loaded_attributes[name][:original] ||=
    worksheet.attribute_at_row_position(name, row_position)
end

#hashObject



254
255
256
# File 'lib/sheets_db/worksheet/row.rb', line 254

def hash
  [self.class, worksheet, row_position].hash
end

#modify_collection_attribute(name, value, remove:) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/sheets_db/worksheet/row.rb', line 151

def modify_collection_attribute(name, value, remove:)
  attribute_definition = self.class.attribute_definitions.fetch(name, {})
  existing_value = Array(send(name))
  return if remove && !existing_value.include?(value)
  return if !remove && existing_value.include?(value)
  assignment_value = if attribute_definition[:multiple]
    remove ? existing_value - [value] : existing_value.concat([value])
  else
    remove ? nil : value
  end
  send("#{name}=", assignment_value)
end

#new_row?Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/sheets_db/worksheet/row.rb', line 120

def new_row?
  row_position.nil?
end

#reload!Object



172
173
174
175
# File 'lib/sheets_db/worksheet/row.rb', line 172

def reload!
  worksheet.reload!
  reset_attributes_and_associations_cache
end

#remove_element_from_attribute(name, value) ⇒ Object



168
169
170
# File 'lib/sheets_db/worksheet/row.rb', line 168

def remove_element_from_attribute(name, value)
  modify_collection_attribute(name, value, remove: true)
end

#reset_attributes_and_associations_cacheObject



192
193
194
195
# File 'lib/sheets_db/worksheet/row.rb', line 192

def reset_attributes_and_associations_cache
  @loaded_attributes = {}
  @loaded_associations = {}
end

#save!Object



177
178
179
180
181
182
# File 'lib/sheets_db/worksheet/row.rb', line 177

def save!
  assign_next_row_position_if_not_set
  worksheet.update_attributes_at_row_position(staged_attributes, row_position: row_position)
  save_changed_foreign_items!
  reset_attributes_and_associations_cache
end

#save_changed_foreign_items!Object



188
189
190
# File 'lib/sheets_db/worksheet/row.rb', line 188

def save_changed_foreign_items!
  changed_foreign_items.each(&:save!)
end

#spreadsheetObject



205
206
207
# File 'lib/sheets_db/worksheet/row.rb', line 205

def spreadsheet
  worksheet.spreadsheet
end

#stage_attribute_modification(name, value) ⇒ Object



135
136
137
138
# File 'lib/sheets_db/worksheet/row.rb', line 135

def stage_attribute_modification(name, value)
  loaded_attributes[name] ||= {}
  loaded_attributes[name][:changed] = value
end

#stage_attributes(new_attribute_set) ⇒ Object



140
141
142
143
144
# File 'lib/sheets_db/worksheet/row.rb', line 140

def stage_attributes(new_attribute_set)
  new_attribute_set.each do |name, value|
    send(:"#{name}=", value)
  end
end

#staged_attributesObject



197
198
199
200
201
202
203
# File 'lib/sheets_db/worksheet/row.rb', line 197

def staged_attributes
  loaded_attributes.each_with_object({}) { |(key, value), hsh|
    next unless value
    hsh[key] = value[:changed] if value[:changed]
    hsh
  }
end

#to_hash(depth: 0) ⇒ Object



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/sheets_db/worksheet/row.rb', line 228

def to_hash(depth: 0)
  hashed_associations = if depth > 0
    Hash[
      associations.map { |name, association|
        association_hash = if association.is_a?(Array)
          association.map { |item| item.to_hash(depth: depth - 1) }
        else
          association.to_hash(depth: depth - 1)
        end
        [name, association_hash]
      }
    ]
  else
    {}
  end
  attributes.merge(hashed_associations)
end

#update_attributes!(new_attribute_set) ⇒ Object



146
147
148
149
# File 'lib/sheets_db/worksheet/row.rb', line 146

def update_attributes!(new_attribute_set)
  stage_attributes(new_attribute_set)
  save!
end