lockstep_rails 0.3.22 → 0.3.28

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,16 @@
1
- require "rubygems"
2
- require "bundler/setup"
3
- require "active_model"
4
- require "erb"
5
- require "dry-types"
6
- require "json"
7
- require "active_support/hash_with_indifferent_access"
8
- require "lockstep/query"
9
- require "lockstep/query_methods"
10
- require "lockstep/error"
11
- require "lockstep/exceptions"
12
- require "lockstep/relation_array"
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'active_model'
4
+ require 'erb'
5
+ require 'dry-types'
6
+ require 'json'
7
+ require 'active_support/hash_with_indifferent_access'
8
+ require 'lockstep/query'
9
+ require 'lockstep/query_methods'
10
+ require 'lockstep/error'
11
+ require 'lockstep/exceptions'
12
+ require 'lockstep/relation_array'
13
+ require 'pry'
13
14
 
14
15
  module Lockstep
15
16
  class ApiRecord
@@ -42,7 +43,7 @@ module Lockstep
42
43
  # @params [Hash], [Boolean] a `Hash` of attributes and a `Boolean` that should be false only if the object already exists
43
44
  # @return [Lockstep::ApiRecord] an object that subclasses `Parseresource::Base`
44
45
  def initialize(attributes = {}, new = true)
45
- #attributes = HashWithIndifferentAccess.new(attributes)
46
+ # attributes = HashWithIndifferentAccess.new(attributes)
46
47
 
47
48
  if new
48
49
  @unsaved_attributes = attributes
@@ -85,7 +86,7 @@ module Lockstep
85
86
  fname = fname.to_sym
86
87
  class_eval do
87
88
  define_method(fname) do
88
- val = get_attribute("#{fname}")
89
+ val = get_attribute(fname.to_s)
89
90
 
90
91
  # If enum, substitute with the enum key
91
92
  if val.present? && (enum = enum_config[fname]).present?
@@ -95,10 +96,10 @@ module Lockstep
95
96
  val
96
97
  end
97
98
  end
98
- unless self.respond_to? "#{fname}="
99
+ unless respond_to? "#{fname}="
99
100
  class_eval do
100
101
  define_method("#{fname}=") do |val|
101
- set_attribute("#{fname}", val)
102
+ set_attribute(fname.to_s, val)
102
103
 
103
104
  val
104
105
  end
@@ -125,7 +126,7 @@ module Lockstep
125
126
  def self.belongs_to(parent, config = {})
126
127
  config = config.with_indifferent_access
127
128
  class_name = config[:class_name]
128
- raise "Class name cannot be empty in #{parent}: #{self.name}" if class_name.blank?
129
+ raise "Class name cannot be empty in #{parent}: #{name}" if class_name.blank?
129
130
 
130
131
  included = config[:included] || false
131
132
  primary_key = config[:primary_key]
@@ -139,7 +140,7 @@ module Lockstep
139
140
  belongs_to_relations[parent] = {
140
141
  name: parent, class_name: class_name,
141
142
  included: included, primary_key: primary_key, foreign_key: foreign_key,
142
- loader: loader, polymorphic: polymorphic,
143
+ loader: loader, polymorphic: polymorphic
143
144
  }
144
145
 
145
146
  # define_method("build_#{parent}") do |attributes_hash|
@@ -156,7 +157,7 @@ module Lockstep
156
157
  def self.has_many(parent, config = {})
157
158
  config = config.with_indifferent_access
158
159
  class_name = config[:class_name]
159
- raise "Class name cannot be empty in #{parent}: #{self.name}" if class_name.blank?
160
+ raise "Class name cannot be empty in #{parent}: #{name}" if class_name.blank?
160
161
 
161
162
  included = config[:included] || false
162
163
  primary_key = config[:primary_key]
@@ -164,13 +165,13 @@ module Lockstep
164
165
  polymorphic = config[:polymorphic]
165
166
  loader = config[:loader]
166
167
 
167
- primary_key ||= self.id_ref
168
- foreign_key ||= self.id_ref
168
+ primary_key ||= id_ref
169
+ foreign_key ||= id_ref
169
170
  field(parent)
170
171
  has_many_relations[parent] = {
171
172
  name: parent, class_name: class_name, included: included,
172
173
  primary_key: primary_key, foreign_key: foreign_key, polymorphic: polymorphic,
173
- loader: loader,
174
+ loader: loader
174
175
  }
175
176
  end
176
177
 
@@ -182,46 +183,48 @@ module Lockstep
182
183
  schema.belongs_to_relations.each do |relation, config|
183
184
  params = {}
184
185
  config.except(:name).each { |k, v| params[k.to_sym] = v }
185
- self.belongs_to(relation, params)
186
+ belongs_to(relation, params)
186
187
  end
187
188
 
188
189
  schema.has_many_relations.each do |relation, config|
189
190
  params = {}
190
191
  config.except(:name).each { |k, v| params[k.to_sym] = v }
191
- self.has_many(relation, params)
192
+ has_many(relation, params)
192
193
  end
193
194
  end
194
195
 
195
196
  def to_pointer
196
197
  klass_name = self.class.model_name.to_s
197
- { "__type" => "Pointer", "className" => klass_name.to_s, self.id_ref => self.id }
198
+ { '__type' => 'Pointer', 'className' => klass_name.to_s, id_ref => id }
198
199
  end
199
200
 
200
201
  def self.to_date_object(date)
201
202
  date = date.to_time if date.respond_to?(:to_time)
202
- { "__type" => "Date", "iso" => date.getutc.iso8601 } if date && (date.is_a?(Date) || date.is_a?(DateTime) || date.is_a?(Time))
203
+ if date && (date.is_a?(Date) || date.is_a?(DateTime) || date.is_a?(Time))
204
+ date.getutc.iso8601(fraction_digits = 3)
205
+ end
203
206
  end
204
207
 
205
208
  # Creates setter methods for model fields
206
- def create_setters!(k, v)
207
- unless self.respond_to? "#{k}="
209
+ def create_setters!(k, _v)
210
+ unless respond_to? "#{k}="
208
211
  self.class.send(:define_method, "#{k}=") do |val|
209
- set_attribute("#{k}", val)
212
+ set_attribute(k.to_s, val)
210
213
 
211
214
  val
212
215
  end
213
216
  end
214
217
  end
215
218
 
216
- def method_missing(method, *args, &block)
217
- raise StandardError.new("#{method} has not been defined for #{self.class.name}")
219
+ def method_missing(method, *_args)
220
+ raise StandardError, "#{method} has not been defined for #{self.class.name}"
218
221
  # super
219
222
  end
220
223
 
221
224
  def self.method_missing(method_name, *args)
222
225
  method_name = method_name.to_s
223
- if method_name.start_with?("find_by_")
224
- attrib = method_name.gsub(/^find_by_/, "")
226
+ if method_name.start_with?('find_by_')
227
+ attrib = method_name.gsub(/^find_by_/, '')
225
228
  finder_name = "find_all_by_#{attrib}"
226
229
 
227
230
  define_singleton_method(finder_name) do |target_value|
@@ -229,8 +232,8 @@ module Lockstep
229
232
  end
230
233
 
231
234
  send(finder_name, args[0])
232
- elsif method_name.start_with?("find_all_by_")
233
- attrib = method_name.gsub(/^find_all_by_/, "")
235
+ elsif method_name.start_with?('find_all_by_')
236
+ attrib = method_name.gsub(/^find_all_by_/, '')
234
237
  finder_name = "find_all_by_#{attrib}"
235
238
 
236
239
  define_singleton_method(finder_name) do |target_value|
@@ -244,10 +247,10 @@ module Lockstep
244
247
  end
245
248
 
246
249
  # Creates getter methods for model fields
247
- def create_getters!(k, v)
248
- unless self.respond_to? "#{k}"
249
- self.class.send(:define_method, "#{k}") do
250
- get_attribute("#{k}")
250
+ def create_getters!(k, _v)
251
+ unless respond_to? k.to_s
252
+ self.class.send(:define_method, k.to_s) do
253
+ get_attribute(k.to_s)
251
254
  end
252
255
  end
253
256
  end
@@ -283,19 +286,19 @@ module Lockstep
283
286
  # end
284
287
  # end
285
288
 
286
- def self.id_ref=(val)
287
- @id_ref = val
289
+ class << self
290
+ attr_writer :id_ref
288
291
  end
289
292
 
290
293
  def self.id_ref
291
- raise StandardError.new("id_ref has not been defined for #{self.name}") if @id_ref.blank?
294
+ raise StandardError, "id_ref has not been defined for #{name}" if @id_ref.blank?
292
295
 
293
296
  @id_ref
294
297
  end
295
298
 
296
299
  # Alias for id_ref. Used by polymorphic association
297
300
  def self.primary_key
298
- self.id_ref
301
+ id_ref
299
302
  end
300
303
 
301
304
  def id_ref
@@ -308,8 +311,8 @@ module Lockstep
308
311
  @model_name_uri
309
312
  end
310
313
 
311
- def self.model_name_uri
312
- @model_name_uri
314
+ class << self
315
+ attr_reader :model_name_uri
313
316
  end
314
317
 
315
318
  def self.config
@@ -318,13 +321,16 @@ module Lockstep
318
321
 
319
322
  # Gets the current class's Lockstep.io base_uri
320
323
  def self.model_base_uri
321
- raise StandardError.new("Cannot establish connection for auto-generated Schema. Create a new model if you want to retrieve data from Lockstep Platform") if self.name.starts_with?("Schema::")
322
- raise StandardError.new("URL Path is not defined for #{self.name}") if model_name_uri.blank?
324
+ if name.starts_with?('Schema::')
325
+ raise StandardError,
326
+ 'Cannot establish connection for auto-generated Schema. Create a new model if you want to retrieve data from Lockstep Platform'
327
+ end
328
+ raise StandardError, "URL Path is not defined for #{name}" if model_name_uri.blank?
323
329
 
324
330
  base_url = config[:base_url]
325
- base_url += "/" unless base_url.ends_with?("/")
331
+ base_url += '/' unless base_url.ends_with?('/')
326
332
  base_url += model_name_uri
327
- base_url += "/" unless base_url.ends_with?("/")
333
+ base_url += '/' unless base_url.ends_with?('/')
328
334
  base_url
329
335
  end
330
336
 
@@ -339,19 +345,19 @@ module Lockstep
339
345
  def self.resource
340
346
  # load_settings
341
347
 
342
- #refactor to settings['app_id'] etc
348
+ # refactor to settings['app_id'] etc
343
349
  # app_id = @@settings['app_id']
344
350
  # master_key = @@settings['master_key']
345
351
  # RestClient::Resource.new(self.model_base_uri, app_id, master_key)
346
- Lockstep::Client.new(self.model_base_uri)
352
+ Lockstep::Client.new(model_base_uri)
347
353
  end
348
354
 
349
- def self.query_path=(value)
350
- @query_path = value
355
+ class << self
356
+ attr_writer :query_path
351
357
  end
352
358
 
353
359
  def self.query_path
354
- @query_path || "query"
360
+ @query_path || 'query'
355
361
  end
356
362
 
357
363
  # Batch requests
@@ -396,6 +402,7 @@ module Lockstep
396
402
  def self.merge_all_attributes(objects, response)
397
403
  objects.each_with_index do |item, index|
398
404
  next unless response[index]
405
+
399
406
  new_attributes = response[index].transform_keys { |key| key.underscore }
400
407
  item.merge_attributes(new_attributes)
401
408
  end
@@ -417,7 +424,7 @@ module Lockstep
417
424
  # end
418
425
 
419
426
  def self.bulk_import(new_objects, slice_size = 20)
420
- return true if new_objects.blank?
427
+ return [] if new_objects.blank?
421
428
 
422
429
  # Batch saves seem to fail if they're too big. We'll slice it up into multiple posts if they are.
423
430
  new_objects.each_slice(slice_size) do |objects|
@@ -425,46 +432,41 @@ module Lockstep
425
432
  batch_json = []
426
433
 
427
434
  objects.each do |item|
428
- raise StandardError.new("Bulk Import cannot only create records at the moment. It cannot update records") unless item.new?
435
+ unless item.new?
436
+ raise StandardError,
437
+ 'Bulk Import cannot only create records at the moment. It cannot update records'
438
+ end
429
439
 
430
440
  batch_json << item.attributes_for_saving.transform_keys { |key| key.camelize(:lower) }
431
441
  end
432
442
 
433
- resp = self.resource.post("", body: batch_json)
434
- # TODO attach errors if resp code is 400
435
-
436
- if resp.code.to_s == "400"
443
+ resp = resource.post('', body: batch_json)
444
+ # TODO: attach errors if resp code is 400
445
+ if resp.code != '200'
437
446
  # Error format in JSON
438
447
  # "errors": {
439
448
  # "[0].EmailAddress": [
440
449
  # "The EmailAddress field is not a valid e-mail address."
441
450
  # ]
442
451
  # }
443
- error_response = JSON.parse(resp.body)
444
- errors = error_response["errors"]
445
- errors.each do |key, messages|
446
- splits = key.split(".")
447
- attribute = splits.last&.underscore
448
- # Remove the [] from the first split to get the position in integer
449
- position = splits.first[1..(splits.first.size - 2)].to_i
450
- messages.each do |message|
451
- new_objects[position].errors.add attribute, ": #{message}"
452
- end
452
+ if resp.code == '401'
453
+ raise Lockstep::Exceptions::UnauthorizedError, 'Unauthorized: Check your App ID & Master Key'
454
+ elsif resp.code == '400'
455
+ raise Lockstep::Exceptions::BadRequestError, JSON.parse(resp.body)
456
+ elsif resp.code == '404'
457
+ raise Lockstep::Exceptions::RecordNotFound, 'Resource not found in the Platfrom'
453
458
  end
454
- return false
455
- elsif resp.code.to_s != "200"
456
- return false
457
459
  end
458
460
 
459
461
  response = JSON.parse(resp.body)
460
- if response && response.is_a?(Array) && response.length == objects.length
461
- # return response.map { |item|
462
- # Lockstep::Contact.new(item.transform_keys { |key| key.underscore }, false)
463
- # }
464
- merge_all_attributes(objects, response)
465
- end
462
+ next unless response && response.is_a?(Array) && response.length == objects.length
463
+
464
+ # return response.map { |item|
465
+ # Lockstep::Contact.new(item.transform_keys { |key| key.underscore }, false)
466
+ # }
467
+ merge_all_attributes(objects, response)
466
468
  end
467
- true
469
+ new_objects
468
470
  end
469
471
 
470
472
  # def self.load_settings
@@ -516,8 +518,10 @@ module Lockstep
516
518
  # @return [Lockstep::ApiRecord] an object that subclasses Lockstep::ApiRecord.
517
519
  def self.find(id)
518
520
  raise Lockstep::Exceptions::RecordNotFound, "Couldn't find #{name} without an ID" if id.blank?
519
- record = where(self.id_ref => id).first
521
+
522
+ record = where(id_ref => id).first
520
523
  raise Lockstep::Exceptions::RecordNotFound, "Couldn't find #{name} with id: #{id}" if record.blank?
524
+
521
525
  record
522
526
  end
523
527
 
@@ -525,13 +529,13 @@ module Lockstep
525
529
  #
526
530
  def self.find_by(*args)
527
531
  raise Lockstep::Exceptions::RecordNotFound, "Couldn't find an object without arguments" if args.blank?
532
+
528
533
  key, value = args.first.first
529
534
  unless valid_attribute?(key, raise_exception: true)
530
- raise StandardError.new("Attribute '#{key}' has not been defined for #{self.name}")
535
+ raise StandardError, "Attribute '#{key}' has not been defined for #{name}"
531
536
  end
532
537
 
533
- record = where(key => value).first
534
- record
538
+ where(key => value).first
535
539
  end
536
540
 
537
541
  # Find a Lockstep::ApiRecord object by chaining #where method calls.
@@ -576,19 +580,17 @@ module Lockstep
576
580
  # Valid only if the record is not an API record.
577
581
  # Default scopes build queries using ApiRecord to avoid conflicts. In this case, the query results in an
578
582
  # exception as the fields wouldn't have been defined in the ApiRecord
579
- return true if self.name == "Lockstep::ApiRecord"
583
+ return true if name == 'Lockstep::ApiRecord'
580
584
 
581
585
  attr = key.to_s
582
586
  Lockstep::Query::PREDICATES.keys.each do |predicate|
583
587
  if attr.end_with?(predicate)
584
- attr = attr.gsub(predicate, "")
588
+ attr = attr.gsub(predicate, '')
585
589
  break
586
590
  end
587
591
  end
588
592
  valid = schema.has_key?(attr)
589
- if raise_exception && !valid
590
- raise StandardError.new("Attribute '#{attr}' has not been defined for #{self.name}")
591
- end
593
+ raise StandardError, "Attribute '#{attr}' has not been defined for #{name}" if raise_exception && !valid
592
594
 
593
595
  valid
594
596
  end
@@ -613,19 +615,19 @@ module Lockstep
613
615
  # create RESTful resource for the specific Parse object
614
616
  # sends requests to [base_uri]/[classname]/[objectId]
615
617
  def instance_resource
616
- self.class.resource["#{self.id}"]
618
+ self.class.resource[id.to_s]
617
619
  end
618
620
 
619
621
  def pointerize(hash)
620
622
  new_hash = {}
621
623
  hash.each do |k, v|
622
- if v.respond_to?(:to_pointer)
623
- new_hash[k] = v.to_pointer
624
- elsif v.is_a?(Date) || v.is_a?(Time) || v.is_a?(DateTime)
625
- new_hash[k] = self.class.to_date_object(v)
626
- else
627
- new_hash[k] = v
628
- end
624
+ new_hash[k] = if v.respond_to?(:to_pointer)
625
+ v.to_pointer
626
+ elsif v.is_a?(Date) || v.is_a?(Time) || v.is_a?(DateTime)
627
+ self.class.to_date_object(v)
628
+ else
629
+ v
630
+ end
629
631
  end
630
632
  new_hash
631
633
  end
@@ -642,13 +644,13 @@ module Lockstep
642
644
  else
643
645
  false
644
646
  end
645
- rescue
647
+ rescue StandardError
646
648
  false
647
649
  end
648
650
 
649
651
  def create
650
652
  attrs = attributes_for_saving.transform_keys { |key| key.camelize(:lower) }
651
- resp = self.resource.post("", body: [attrs])
653
+ resp = resource.post('', body: [attrs])
652
654
  result = post_result(resp)
653
655
  end
654
656
 
@@ -659,7 +661,7 @@ module Lockstep
659
661
  # put_attrs = attributes_for_saving.to_json
660
662
 
661
663
  attrs = attributes_for_saving.transform_keys { |key| key.camelize(:lower) }
662
- resp = self.resource.patch(self.id, body: attrs)
664
+ resp = resource.patch(id, body: attrs)
663
665
  result = post_result(resp)
664
666
  end
665
667
 
@@ -681,40 +683,40 @@ module Lockstep
681
683
  # the object nor the relations it contains. Make another request here.
682
684
  # TODO: @@has_many_relations structure has been changed from array to hash, need to evaluate the impact here
683
685
  if has_many_relations.keys.map { |relation| relation.to_s.to_sym }
684
- #todo: make this a little smarter by checking if there are any Pointer objects in the objects attributes.
686
+ # TODO: make this a little smarter by checking if there are any Pointer objects in the objects attributes.
685
687
  # @attributes = self.class.to_s.constantize.where(:objectId => @attributes[self.id_ref]).first.attributes
686
- @attributes = self.class.to_s.constantize.where(self.id_ref => @attributes[self.id_ref]).first.attributes
688
+ @attributes = self.class.to_s.constantize.where(id_ref => @attributes[id_ref]).first.attributes
687
689
  end
688
690
  end
689
691
 
690
692
  def post_result(resp)
691
- if resp.code.to_s == "200" || resp.code.to_s == "201"
693
+ if resp.code.to_s == '200' || resp.code.to_s == '201'
692
694
  body = JSON.parse(resp.body)
693
695
  # Create method always responds with an array, whereas update responds with the object
694
696
  body = body.first if body.is_a?(Array)
695
697
 
696
698
  merge_attributes(body)
697
699
 
698
- return true
699
- elsif resp.code.to_s == "400"
700
+ true
701
+ elsif resp.code.to_s == '400'
700
702
  error_response = JSON.parse(resp.body)
701
- errors = error_response["errors"]
703
+ errors = error_response['errors']
702
704
  errors.each do |key, messages|
703
- attribute = key.split(".").last&.underscore
705
+ attribute = key.split('.').last&.underscore
704
706
  messages.each do |message|
705
707
  self.errors.add attribute, ": #{message}"
706
708
  end
707
709
  end
708
710
  else
709
711
  error_response = JSON.parse(resp.body)
710
- if error_response["error"]
711
- pe = LockstepError.new(error_response["code"], error_response["error"])
712
- else
713
- pe = LockstepError.new(resp.code.to_s)
714
- end
712
+ pe = if error_response['error']
713
+ LockstepError.new(error_response['code'], error_response['error'])
714
+ else
715
+ LockstepError.new(resp.code.to_s)
716
+ end
715
717
  self.errors.add(pe.code.to_s.to_sym, pe.msg)
716
- self.error_instances << pe
717
- return false
718
+ error_instances << pe
719
+ false
718
720
  end
719
721
  end
720
722
 
@@ -724,9 +726,9 @@ module Lockstep
724
726
 
725
727
  put_attrs = relations_for_saving(put_attrs)
726
728
 
727
- put_attrs.delete(self.id_ref)
728
- put_attrs.delete("created")
729
- put_attrs.delete("modified")
729
+ put_attrs.delete(id_ref)
730
+ put_attrs.delete('created')
731
+ put_attrs.delete('modified')
730
732
  put_attrs
731
733
  end
732
734
 
@@ -734,25 +736,28 @@ module Lockstep
734
736
  all_add_item_queries = {}
735
737
  all_remove_item_queries = {}
736
738
  @unsaved_attributes.each_pair do |key, value|
737
- next if !value.is_a? Array
739
+ next unless value.is_a? Array
738
740
 
739
741
  # Go through the array in unsaved and check if they are in array in attributes (saved stuff)
740
742
  add_item_ops = []
741
743
  @unsaved_attributes[key].each do |item|
742
744
  found_item_in_saved = false
743
745
  @attributes[key].each do |item_in_saved|
744
- if !!(defined? item.attributes) && item.attributes[self.id_ref] == item_in_saved.attributes[self.id_ref]
746
+ if !!(defined? item.attributes) && item.attributes[id_ref] == item_in_saved.attributes[id_ref]
745
747
  found_item_in_saved = true
746
748
  end
747
749
  end
748
750
 
749
- if !found_item_in_saved && !!(defined? item.id)
750
- # need to send additem operation to parse
751
- put_attrs.delete(key) # arrays should not be sent along with REST to parse api
752
- add_item_ops << { "__type" => "Pointer", "className" => item.class.to_s, self.id_ref => item.id }
753
- end
751
+ next unless !found_item_in_saved && !!(defined? item.id)
752
+
753
+ # need to send additem operation to parse
754
+ put_attrs.delete(key) # arrays should not be sent along with REST to parse api
755
+ add_item_ops << { '__type' => 'Pointer', 'className' => item.class.to_s, id_ref => item.id }
756
+ end
757
+ unless add_item_ops.empty?
758
+ all_add_item_queries.merge!({ key => { '__op' => 'Add',
759
+ 'objects' => add_item_ops } })
754
760
  end
755
- all_add_item_queries.merge!({ key => { "__op" => "Add", "objects" => add_item_ops } }) if !add_item_ops.empty?
756
761
 
757
762
  # Go through saved and if it isn't in unsaved perform a removeitem operation
758
763
  remove_item_ops = []
@@ -760,28 +765,31 @@ module Lockstep
760
765
  @attributes[key].each do |item|
761
766
  found_item_in_unsaved = false
762
767
  @unsaved_attributes[key].each do |item_in_unsaved|
763
- if !!(defined? item.attributes) && item.attributes[self.id_ref] == item_in_unsaved.attributes[self.id_ref]
768
+ if !!(defined? item.attributes) && item.attributes[id_ref] == item_in_unsaved.attributes[id_ref]
764
769
  found_item_in_unsaved = true
765
770
  end
766
771
  end
767
772
 
768
773
  if !found_item_in_unsaved && !!(defined? item.id)
769
774
  # need to send removeitem operation to parse
770
- remove_item_ops << { "__type" => "Pointer", "className" => item.class.to_s, self.id_ref => item.id }
775
+ remove_item_ops << { '__type' => 'Pointer', 'className' => item.class.to_s, id_ref => item.id }
771
776
  end
772
777
  end
773
778
  end
774
- all_remove_item_queries.merge!({ key => { "__op" => "Remove", "objects" => remove_item_ops } }) if !remove_item_ops.empty?
779
+ unless remove_item_ops.empty?
780
+ all_remove_item_queries.merge!({ key => { '__op' => 'Remove',
781
+ 'objects' => remove_item_ops } })
782
+ end
775
783
  end
776
784
 
777
- # TODO figure out a more elegant way to get this working. the remove_item merge overwrites the add.
785
+ # TODO: figure out a more elegant way to get this working. the remove_item merge overwrites the add.
778
786
  # Use a seperate query to add objects to the relation.
779
- #if !all_add_item_queries.empty?
787
+ # if !all_add_item_queries.empty?
780
788
  # #result = self.instance_resource.put(all_add_item_queries.to_json, {:content_type => "application/json"}) do |resp, req, res, &block|
781
789
  # # return puts(resp, req, res, false, &block)
782
790
  # #end
783
791
  # puts result
784
- #end
792
+ # end
785
793
 
786
794
  put_attrs.merge!(all_add_item_queries) unless all_add_item_queries.empty?
787
795
  put_attrs.merge!(all_remove_item_queries) unless all_remove_item_queries.empty?
@@ -789,17 +797,17 @@ module Lockstep
789
797
  end
790
798
 
791
799
  def update_attributes(attributes = {})
792
- self.update(attributes)
800
+ update(attributes)
793
801
  end
794
802
 
795
803
  def update_attribute(key, value)
796
- send(key.to_s + "=", value)
804
+ send(key.to_s + '=', value)
797
805
  update
798
806
  end
799
807
 
800
808
  def destroy
801
- resp = self.resource.delete(self.id)
802
- if resp.code.to_s == "200"
809
+ resp = resource.delete(id)
810
+ if resp.code.to_s == '200'
803
811
  @attributes = {}
804
812
  @unsaved_attributes = {}
805
813
  return true
@@ -812,7 +820,7 @@ module Lockstep
812
820
 
813
821
  fresh_object = self.class.find(id)
814
822
  @attributes = {}
815
- @attributes.update(fresh_object.instance_variable_get("@attributes"))
823
+ @attributes.update(fresh_object.instance_variable_get('@attributes'))
816
824
  @unsaved_attributes = {}
817
825
 
818
826
  self
@@ -845,27 +853,30 @@ module Lockstep
845
853
  attrs = @unsaved_attributes[k.to_s] ? @unsaved_attributes : @attributes
846
854
  case attrs[k]
847
855
  when Hash
848
- klass_name = attrs[k]["className"]
849
- klass_name = "User" if klass_name == "_User"
850
- case attrs[k]["__type"]
851
- when "Pointer"
852
- result = klass_name.to_s.constantize.find(attrs[k][self.id_ref])
853
- when "Object"
856
+ klass_name = attrs[k]['className']
857
+ klass_name = 'User' if klass_name == '_User'
858
+ case attrs[k]['__type']
859
+ when 'Pointer'
860
+ result = klass_name.to_s.constantize.find(attrs[k][id_ref])
861
+ when 'Object'
854
862
  result = klass_name.to_s.constantize.new(attrs[k], false)
855
- when "Date"
856
- result = DateTime.parse(attrs[k]["iso"]).in_time_zone
857
- when "File"
858
- result = attrs[k]["url"]
859
- when "Relation"
860
- objects_related_to_self = klass_name.constantize.where("$relatedTo" => { "object" => { "__type" => "Pointer", "className" => self.class.to_s, self.id_ref => self.id }, "key" => k }).all
863
+ when 'Date'
864
+ result = DateTime.parse(attrs[k]['iso']).in_time_zone
865
+ when 'File'
866
+ result = attrs[k]['url']
867
+ when 'Relation'
868
+ objects_related_to_self = klass_name.constantize.where('$relatedTo' => {
869
+ 'object' => { '__type' => 'Pointer',
870
+ 'className' => self.class.to_s, id_ref => id }, 'key' => k
871
+ }).all
861
872
  attrs[k] = Lockstep::RelationArray.new self, objects_related_to_self, k, klass_name
862
873
  @unsaved_attributes[k] = Lockstep::RelationArray.new self, objects_related_to_self, k, klass_name
863
874
  result = @unsaved_attributes[k]
864
875
  end
865
876
  else
866
- # TODO changed from @@has_many_relations to @@has_many_relations.keys as we have changed the has_many_relations
877
+ # TODO: changed from @@has_many_relations to @@has_many_relations.keys as we have changed the has_many_relations
867
878
  # from array to hash to capture more data points. Not sure of the impact of this.
868
- #relation will assign itself if an array, this will add to unsave_attributes
879
+ # relation will assign itself if an array, this will add to unsave_attributes
869
880
  if has_many_relations.keys.index(k.to_s)
870
881
  if attrs[k].nil?
871
882
  # result = nil
@@ -883,7 +894,7 @@ module Lockstep
883
894
  result = @unsaved_attributes[k]
884
895
  end
885
896
  else
886
- result = attrs["#{k}"]
897
+ result = attrs[k.to_s]
887
898
  end
888
899
  end
889
900
  result
@@ -938,24 +949,28 @@ module Lockstep
938
949
  end
939
950
 
940
951
  def primary_key
941
- self.id_ref
952
+ id_ref
942
953
  end
943
954
 
944
955
  # aliasing for idiomatic Ruby
945
956
  def id
946
- get_attribute(self.id_ref) rescue nil
957
+ get_attribute(id_ref)
958
+ rescue StandardError
959
+ nil
947
960
  end
948
961
 
949
962
  def objectId
950
- get_attribute(self.id_ref) rescue nil
963
+ get_attribute(id_ref)
964
+ rescue StandardError
965
+ nil
951
966
  end
952
967
 
953
968
  def created_at
954
- get_attribute("created")
969
+ get_attribute('created')
955
970
  end
956
971
 
957
972
  def updated_at
958
- get_attribute("modified")
973
+ get_attribute('modified')
959
974
  end
960
975
 
961
976
  def self.included(base)
@@ -965,10 +980,10 @@ module Lockstep
965
980
  module ClassMethods
966
981
  end
967
982
 
968
- #if we are comparing objects, use id if they are both Lockstep::ApiRecord objects
969
- def ==(another_object)
970
- if another_object.class <= Lockstep::ApiRecord
971
- self.id == another_object.id
983
+ # if we are comparing objects, use id if they are both Lockstep::ApiRecord objects
984
+ def ==(other)
985
+ if other.class <= Lockstep::ApiRecord
986
+ id == other.id
972
987
  else
973
988
  super
974
989
  end
@@ -989,12 +1004,14 @@ module Lockstep
989
1004
  val = relation_config[:loader].call(self)
990
1005
  else
991
1006
  return val unless relation_config[:foreign_key].present? and relation_config[:primary_key].present?
1007
+
992
1008
  relation_klass = relation_config[:class_name].constantize
993
1009
  return val unless relation_klass.model_name_uri.present?
994
1010
 
995
- query = { relation_config[:foreign_key] => self.send(relation_config[:primary_key]) }
1011
+ query = { relation_config[:foreign_key] => send(relation_config[:primary_key]) }
996
1012
  if relation_config[:polymorphic]
997
- polymorphic_config = Lockstep::RelationArray.has_many_polymorphic_attributes(self, relation_config[:polymorphic])
1013
+ polymorphic_config = Lockstep::RelationArray.has_many_polymorphic_attributes(self,
1014
+ relation_config[:polymorphic])
998
1015
  query.merge!(polymorphic_config)
999
1016
  end
1000
1017
  related_objects = relation_klass.send(:where, query).execute
@@ -1005,7 +1022,8 @@ module Lockstep
1005
1022
  if relation_config[:loader].present?
1006
1023
  val = relation_config[:loader].call(self)
1007
1024
  else
1008
- val = relation_config[:class_name].constantize.send(:find_by, relation_config[:primary_key] => self.send(relation_config[:foreign_key]))
1025
+ val = relation_config[:class_name].constantize.send(:find_by,
1026
+ relation_config[:primary_key] => send(relation_config[:foreign_key]))
1009
1027
  end
1010
1028
  end
1011
1029
 
@@ -1060,7 +1078,7 @@ module Lockstep
1060
1078
  elsif values.is_a?(Hash)
1061
1079
  value_map = values.with_indifferent_access
1062
1080
  else
1063
- raise StandardError.new("Invalid values for enum #{attribute}")
1081
+ raise StandardError, "Invalid values for enum #{attribute}"
1064
1082
  end
1065
1083
 
1066
1084
  # Convert values to string if the value is symbol
@@ -1089,9 +1107,21 @@ module Lockstep
1089
1107
  value = get_attribute(attribute)
1090
1108
  next if value.nil?
1091
1109
 
1092
- unless values_map.values.include?(value)
1093
- errors.add attribute, "has an invalid value"
1094
- end
1110
+ errors.add attribute, 'has an invalid value' unless values_map.values.include?(value)
1111
+ end
1112
+ end
1113
+
1114
+ def self.single_record!
1115
+ define_singleton_method :record do
1116
+ resp = resource.get('')
1117
+
1118
+ return [] if %w(404).include?(resp.code.to_s)
1119
+ # TODO handle non 200 response code. Throwing an exception for now
1120
+ raise StandardError.new("#{resp.code} error while fetching: #{resp.body}") unless %w(201 200).include?(resp.code.to_s)
1121
+
1122
+ result = JSON.parse(resp.body)
1123
+ r = result.transform_keys { |key| key.underscore }
1124
+ model_name.to_s.constantize.new(r, false)
1095
1125
  end
1096
1126
  end
1097
1127
 
@@ -1111,7 +1141,7 @@ module Lockstep
1111
1141
  as_json(options).to_json
1112
1142
  end
1113
1143
 
1114
- def as_json(options = {})
1144
+ def as_json(_options = {})
1115
1145
  @attributes.merge(@unsaved_attributes).as_json
1116
1146
  end
1117
1147
  end