syncano 3.1.4 → 4.0.0.alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -1
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +3 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +25 -1
  7. data/Guardfile +22 -4
  8. data/README.md +68 -447
  9. data/Rakefile +48 -5
  10. data/circle.yml +10 -0
  11. data/lib/active_attr/dirty.rb +3 -17
  12. data/lib/active_attr/typecasting/hash_typecaster.rb +34 -0
  13. data/lib/active_attr/typecasting_override.rb +29 -0
  14. data/lib/syncano.rb +53 -92
  15. data/lib/syncano/api.rb +13 -0
  16. data/lib/syncano/connection.rb +97 -0
  17. data/lib/syncano/model/associations.rb +121 -0
  18. data/lib/syncano/{active_record/association → model/associations}/base.rb +5 -5
  19. data/lib/syncano/{active_record/association → model/associations}/belongs_to.rb +6 -6
  20. data/lib/syncano/{active_record/association → model/associations}/has_many.rb +15 -9
  21. data/lib/syncano/{active_record/association → model/associations}/has_one.rb +4 -4
  22. data/lib/syncano/model/base.rb +257 -0
  23. data/lib/syncano/{active_record → model}/callbacks.rb +16 -13
  24. data/lib/syncano/{active_record → model}/scope_builder.rb +53 -69
  25. data/lib/syncano/query_builder.rb +19 -129
  26. data/lib/syncano/resources.rb +126 -0
  27. data/lib/syncano/resources/base.rb +304 -300
  28. data/lib/syncano/resources/collection.rb +19 -223
  29. data/lib/syncano/resources/space.rb +29 -0
  30. data/lib/syncano/schema.rb +86 -0
  31. data/lib/syncano/schema/attribute_definition.rb +83 -0
  32. data/lib/syncano/schema/resource_definition.rb +36 -0
  33. data/lib/syncano/scope.rb +10 -0
  34. data/lib/syncano/version.rb +3 -4
  35. data/spec/integration/syncano_spec.rb +228 -0
  36. data/spec/spec_helper.rb +15 -9
  37. data/spec/unit/api_spec.rb +5 -0
  38. data/spec/unit/connection_spec.rb +137 -0
  39. data/spec/unit/query_builder_spec.rb +75 -0
  40. data/spec/unit/resources/collection_spec.rb +36 -0
  41. data/spec/unit/resources/space_spec.rb +28 -0
  42. data/spec/unit/resources_base_spec.rb +185 -0
  43. data/spec/unit/schema/attribute_definition_spec.rb +18 -0
  44. data/spec/unit/schema/resource_definition_spec.rb +25 -0
  45. data/spec/unit/schema_spec.rb +3532 -0
  46. data/spec/unit/syncano_spec.rb +63 -0
  47. data/syncano.gemspec +8 -14
  48. metadata +85 -210
  49. data/lib/generators/syncano/install_generator.rb +0 -17
  50. data/lib/generators/syncano/templates/initializers/syncano.rb +0 -7
  51. data/lib/syncano/active_record/associations.rb +0 -112
  52. data/lib/syncano/active_record/base.rb +0 -318
  53. data/lib/syncano/batch_queue.rb +0 -58
  54. data/lib/syncano/batch_queue_element.rb +0 -33
  55. data/lib/syncano/clients/base.rb +0 -123
  56. data/lib/syncano/clients/rest.rb +0 -79
  57. data/lib/syncano/clients/sync.rb +0 -164
  58. data/lib/syncano/errors.rb +0 -17
  59. data/lib/syncano/jimson_client.rb +0 -66
  60. data/lib/syncano/packets/auth.rb +0 -27
  61. data/lib/syncano/packets/base.rb +0 -70
  62. data/lib/syncano/packets/call.rb +0 -34
  63. data/lib/syncano/packets/call_response.rb +0 -33
  64. data/lib/syncano/packets/error.rb +0 -19
  65. data/lib/syncano/packets/message.rb +0 -30
  66. data/lib/syncano/packets/notification.rb +0 -39
  67. data/lib/syncano/packets/ping.rb +0 -12
  68. data/lib/syncano/resources/admin.rb +0 -26
  69. data/lib/syncano/resources/api_key.rb +0 -108
  70. data/lib/syncano/resources/data_object.rb +0 -316
  71. data/lib/syncano/resources/folder.rb +0 -88
  72. data/lib/syncano/resources/notifications/base.rb +0 -103
  73. data/lib/syncano/resources/notifications/create.rb +0 -20
  74. data/lib/syncano/resources/notifications/destroy.rb +0 -20
  75. data/lib/syncano/resources/notifications/message.rb +0 -9
  76. data/lib/syncano/resources/notifications/update.rb +0 -24
  77. data/lib/syncano/resources/project.rb +0 -96
  78. data/lib/syncano/resources/role.rb +0 -11
  79. data/lib/syncano/resources/subscription.rb +0 -12
  80. data/lib/syncano/resources/user.rb +0 -65
  81. data/lib/syncano/response.rb +0 -22
  82. data/lib/syncano/sync_connection.rb +0 -133
  83. data/spec/admins_spec.rb +0 -16
  84. data/spec/api_keys_spec.rb +0 -34
  85. data/spec/collections_spec.rb +0 -67
  86. data/spec/data_objects_spec.rb +0 -113
  87. data/spec/folders_spec.rb +0 -39
  88. data/spec/notifications_spec.rb +0 -43
  89. data/spec/projects_spec.rb +0 -35
  90. data/spec/roles_spec.rb +0 -13
  91. data/spec/sync_resources_spec.rb +0 -35
  92. data/spec/syncano_spec.rb +0 -9
@@ -1,17 +0,0 @@
1
- class Syncano
2
- # Module for generators used implemented in the gem
3
- module Generators
4
- # Install generator used for initializing gem in a Rails application
5
- class InstallGenerator < Rails::Generators::Base
6
- source_root File.expand_path("../templates", __FILE__)
7
-
8
- # Copies templates for initializers
9
- def create_initializers
10
- Dir["#{self.class.source_root}/initializers/*.rb"].each do |filepath|
11
- name = File.basename(filepath)
12
- template "initializers/#{name}", "config/initializers/#{name}"
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,7 +0,0 @@
1
- # Syncano instance name
2
- SYNCANO_INSTANCE_NAME = 'instance_name'
3
- # Syncano api key
4
- SYNCANO_API_KEY = 'api_key'
5
-
6
- # Collection used for Syncano::ActiveRecord
7
- # SYNCANO_ACTIVERECORD_COLLECTION = Syncano.client.projects.first.collections.first
@@ -1,112 +0,0 @@
1
- require 'syncano/active_record/association/belongs_to'
2
- require 'syncano/active_record/association/has_many'
3
- require 'syncano/active_record/association/has_one'
4
-
5
- class Syncano
6
- module ActiveRecord
7
- # Module with associations functionality for Syncano::ActiveRecord
8
- module Associations
9
- extend ActiveSupport::Concern
10
-
11
- included do
12
- private
13
-
14
- class_attribute :_associations
15
- end
16
-
17
- # Class methods for Syncano::ActiveRecord::Associations module
18
- module ClassMethods
19
- # Lists hash with associations
20
- # @return [HashWithIndifferentAccess]
21
- def associations
22
- self._associations ||= HashWithIndifferentAccess.new
23
- end
24
-
25
- private
26
-
27
- # Setter for associations
28
- def associations=(hash)
29
- self._associations = hash
30
- end
31
-
32
- # Defines belongs_to association
33
- # @param [Symbol] object_name
34
- def belongs_to(object_name)
35
- association = Syncano::ActiveRecord::Association::BelongsTo.new(self, object_name)
36
- associations[object_name] = association
37
-
38
- attribute association.foreign_key
39
- validates association.foreign_key, numericality: { only_integer: true, allow_nil: true }
40
-
41
- define_method(object_name) do
42
- id = send(self.class.associations[object_name].foreign_key)
43
- scope = scope_builder(self.class.associations[object_name].associated_model)
44
- scope.find(id) if id.present?
45
- end
46
-
47
- define_method("#{object_name}=") do |object|
48
- unless object.is_a?(self.class.associations[object_name].associated_model)
49
- "Object should be an instance of #{self.class.associations[object_name].associated_model} class"
50
- end
51
- send("#{self.class.associations[object_name].foreign_key}=", object.try(:id))
52
- end
53
- end
54
-
55
- # Defines has_one association
56
- # @param [Symbol] object_name
57
- def has_one(object_name)
58
- association = Syncano::ActiveRecord::Association::HasOne.new(self, object_name)
59
- associations[object_name] = association
60
-
61
- define_method(object_name) do
62
- scope = scope_builder(self.class.associations[object_name].associated_model)
63
- scope.by_parent_id(id).first if id
64
- end
65
-
66
- define_method("#{object_name}=") do |object|
67
- object.send("#{self.class.associations[object_name].foreign_key}=", id)
68
- object.save unless object.new_record?
69
- object
70
- end
71
-
72
- define_method("build_#{object_name}") do |attributes = {}|
73
- self.class.associations[object_name].associated_model.new(attributes)
74
- end
75
-
76
- define_method("create_#{object_name}") do |attributes = {}|
77
- self.class.associations[object_name].associated_model.create(attributes)
78
- end
79
- end
80
-
81
- # Defines has_many association
82
- # @param [Symbol] collection_name
83
- def has_many(collection_name)
84
- association = Syncano::ActiveRecord::Association::HasMany.new(self, collection_name)
85
- associations[collection_name] = association
86
-
87
- define_method(collection_name) do
88
- self.class.associations[collection_name].scope_builder(self)
89
- end
90
-
91
- define_method("#{collection_name}=") do |collection|
92
- association = self.class.associations[collection_name]
93
-
94
- collection.each do |object|
95
- "Object should be an instance of #{association.associated_class} class" unless object.is_a?(association.associated_class)
96
- end
97
-
98
- send(collection_name).all.each do |object|
99
- object.send("#{association.foreign_key}=", nil)
100
- object.save
101
- end
102
-
103
- collection.each do |object|
104
- object.send("#{association.foreign_key}=", id)
105
- object.save
106
- end
107
- end
108
- end
109
- end
110
- end
111
- end
112
- end
@@ -1,318 +0,0 @@
1
- require 'syncano/active_record/scope_builder'
2
- require 'syncano/active_record/associations'
3
- require 'syncano/active_record/callbacks'
4
-
5
- class Syncano
6
- # Scope for modules and classes integrating ActiveRecord functionality
7
- module ActiveRecord
8
- # Class for integrating ActiveRecord functionality
9
- class Base
10
- include ActiveAttr::Model
11
- include ActiveAttr::Dirty
12
- include ActiveModel::ForbiddenAttributesProtection
13
- include Syncano::ActiveRecord::Associations
14
- include Syncano::ActiveRecord::Callbacks
15
-
16
- attribute :id, type: Integer
17
- attribute :created_at, type: DateTime
18
- attribute :updated_at, type: DateTime
19
-
20
- # Gets collection with all objects
21
- # @return [Array]
22
- def self.all
23
- scope_builder.all
24
- end
25
-
26
- # Counts all objects
27
- # @return [Integer]
28
- def self.count
29
- scope_builder.count
30
- end
31
-
32
- # Returns first object or collection of first x objects
33
- # @param [Integer] amount
34
- # @return [Object, Array]
35
- def self.first(amount = nil)
36
- scope_builder.first(amount)
37
- end
38
-
39
- # Returns last object or collection of last x objects
40
- # @param [Integer] amount
41
- # @return [Object, Array]
42
- def self.last(amount = nil)
43
- scope_builder.last(amount)
44
- end
45
-
46
- # Returns scope builder with condition passed as arguments
47
- # @param [String] condition
48
- # @param [Array] params
49
- # @return [Syncano::ActiveRecord::ScopeBuilder]
50
- def self.where(condition, *params)
51
- scope_builder.where(condition, *params)
52
- end
53
-
54
- # Returns scope builder with order passed as first argument
55
- # @param [String] order
56
- # @return [Syncano::ActiveRecord::ScopeBuilder]
57
- def self.order(order)
58
- scope_builder.order(order)
59
- end
60
-
61
- # Returns one object found by id
62
- # @param [Integer] id
63
- # @return [Object]
64
- def self.find(id)
65
- scope_builder.find(id)
66
- end
67
-
68
- # Creates new object with specified attributes
69
- # @param [Hash] attributes
70
- # @return [Object]
71
- def self.create(attributes)
72
- new_object = self.new(attributes)
73
- new_object.save
74
- new_object
75
- end
76
-
77
- # Returns scope builder with filtering by ids newer than provided
78
- # @param [Integer] id
79
- # @return [Syncano::ActiveRecord::ScopeBuilder]
80
- def self.since(id)
81
- scope_builder.since(id)
82
- end
83
-
84
- # Returns scope builder with filtering by ids older than provided
85
- # @param [Integer] id
86
- # @return [Syncano::ActiveRecord::ScopeBuilder]
87
- def self.before(id)
88
- scope_builder.before(id)
89
- end
90
-
91
- # Returns corresponding Syncano folder
92
- # @return [Syncano::Resources::Folder]
93
- def self.folder
94
- begin
95
- folder = collection.folders.find_by_name(folder_name)
96
- rescue Syncano::ApiError => e
97
- if e.message.starts_with?('DoesNotExist')
98
- folder = collection.folders.create(name: folder_name)
99
- else
100
- raise e
101
- end
102
- end
103
- folder
104
- end
105
-
106
- # Returns scope builder with limit parameter set to parameter
107
- # @param [Integer] amount
108
- # @return [Syncano::ActiveRecord::ScopeBuilder]
109
- def self.limit(amount)
110
- scope_builder.limit(amount)
111
- end
112
-
113
- # Returns hash with filterable attributes
114
- # @return [HashWithIndifferentAccess]
115
- def self.filterable_attributes
116
- self._filterable_attributes ||= HashWithIndifferentAccess.new
117
- end
118
-
119
- # Returns hash with scopes
120
- # @return [HashWithIndifferentAccess]
121
- def self.scopes
122
- self._scopes ||= HashWithIndifferentAccess.new
123
- end
124
-
125
- # Maps syncano attributes to corresponding model attributes
126
- # @param [Hash] attributes
127
- # @return [HashWithIndifferentAccess]
128
- def self.map_from_syncano_attributes(attributes = {})
129
- mappings = HashWithIndifferentAccess.new(filterable_attributes.invert)
130
- HashWithIndifferentAccess[attributes.map {|k, v| [mappings[k] || k, v] }]
131
- end
132
-
133
- # Maps model attributes to corresponding syncano attributes
134
- # @param [Hash] attributes
135
- # @return [HashWithIndifferentAccess]
136
- def self.map_to_syncano_attributes(attributes = {})
137
- mappings = filterable_attributes
138
- HashWithIndifferentAccess[attributes.map {|k, v| [mappings[k] || k, v] }]
139
- end
140
-
141
- # Maps one model attribute to corresponding syncano attribute
142
- # @param [Symbol, String] attribute
143
- # @return [String]
144
- def self.map_to_syncano_attribute(attribute)
145
- mappings = filterable_attributes
146
- mappings[attribute] || attribute
147
- end
148
-
149
- # Constructor for model
150
- # @param [Hash] params
151
- def initialize(params = {})
152
- if params.is_a?(Syncano::Resources::DataObject)
153
- super(self.class.map_from_syncano_attributes(params.attributes).merge(id: params.id))
154
- else
155
- params.delete(:id)
156
- super(self.class.map_from_syncano_attributes(params))
157
- end
158
- end
159
-
160
- # Overwritten equality operator
161
- # @param [Object] object
162
- # @return [TrueClass, FalseClass]
163
- def ==(object)
164
- self.class == object.class && self.id == object.id
165
- end
166
-
167
- # Updates object with specified attributes
168
- # @param [Hash] attributes
169
- # @return [TrueClass, FalseClass]
170
- def update_attributes(attributes)
171
- self.attributes = attributes
172
- self.save
173
- end
174
-
175
- # Performs validations
176
- # @return [TrueClass, FalseClass]
177
- def valid?
178
- process_callbacks(:before_validation)
179
- process_callbacks(:after_validation) if result = super
180
- result
181
- end
182
-
183
- # Saves object in Syncano
184
- # @return [TrueClass, FalseClass]
185
- def save
186
- saved = false
187
-
188
- if valid?
189
- process_callbacks(:before_save)
190
- process_callbacks(persisted? ? :before_update : :before_create)
191
-
192
- data_object = persisted? ? self.class.folder.data_objects.find(id) : self.class.folder.data_objects.new
193
- data_object.attributes = self.class.map_to_syncano_attributes(attributes.except(:id, :created_at, :updated_at))
194
- data_object.save
195
-
196
- if data_object.saved?
197
- self.updated_at = data_object[:updated_at]
198
-
199
- if persisted?
200
- process_callbacks(:after_update)
201
- else
202
- self.id = data_object.id
203
- self.created_at = data_object[:created_at]
204
- process_callbacks(:after_create)
205
- end
206
-
207
- self.class.associations.values.select{ |association| association.belongs_to? }.each do |association|
208
- change = changes[association.foreign_key]
209
-
210
- if change.present?
211
- if change.last.nil? || association.associated_model.find(change.last).present?
212
- data_object.remove_parent(change.first) unless change.first.nil?
213
- data_object.add_parent(change.last) unless change.last.nil?
214
- end
215
- end
216
- end
217
-
218
- super
219
-
220
- process_callbacks(:after_save)
221
- saved = true
222
- end
223
- end
224
-
225
- saved
226
- end
227
-
228
- # Deletes object from Syncano
229
- # @return [TrueClass, FalseClass]
230
- def destroy
231
- process_callbacks(:before_destroy)
232
- data_object = self.class.folder.data_objects.find(id)
233
- data_object.destroy
234
- process_callbacks(:after_destroy) if data_object.destroyed
235
- data_object.destroyed
236
- end
237
-
238
- # Checks if object has not been saved in Syncano yet
239
- # @return [TrueClass, FalseClass]
240
- def new_record?
241
- !persisted?
242
- end
243
-
244
- # Checks if object has been already saved in Syncano
245
- # @return [TrueClass, FalseClass]
246
- def persisted?
247
- id.present?
248
- end
249
-
250
- private
251
-
252
- class_attribute :_filterable_attributes, :_scopes
253
-
254
- # Returns Syncano collection for storing Syncano::ActiveRecord objects
255
- # @return [Syncano::Resource::Collection]
256
- def self.collection
257
- SYNCANO_ACTIVERECORD_COLLECTION
258
- end
259
-
260
- # Returns Syncano collection for storing Syncano::ActiveRecord objects
261
- # @return [Syncano::Resource::Collection]
262
- def self.folder_name
263
- name.pluralize
264
- end
265
-
266
- # Setter for filterable_attributes attribute
267
- def self.filterable_attributes=(hash)
268
- self._filterable_attributes = hash
269
- end
270
-
271
- # Setter for scopes attribute
272
- def self.scopes=(hash)
273
- self._scopes = hash
274
- end
275
-
276
- # Returns scope builder for current model
277
- # @return [Syncano::ActiveRecord::ScopeBuilder]
278
- def self.scope_builder
279
- Syncano::ActiveRecord::ScopeBuilder.new(self)
280
- end
281
-
282
- # Defines model attribute
283
- # @param [Symbol] name
284
- # @param [Hash] options
285
- def self.attribute(name, options = {})
286
- if options[:filterable].present?
287
- self.filterable_attributes = HashWithIndifferentAccess.new if filterable_attributes.nil?
288
- filterable_attributes[name] = options.delete(:filterable)
289
- end
290
- super(name, options)
291
- end
292
-
293
- # Defines model scope
294
- # @param [Symbol] name
295
- # @param [Proc] procedure
296
- def self.scope(name, procedure)
297
- scopes[name] = procedure
298
- end
299
-
300
- # Overwritten method_missing for handling calling defined scopes
301
- # @param [String] name
302
- # @param [Array] args
303
- def self.method_missing(name, *args)
304
- if scopes[name].nil?
305
- super
306
- else
307
- scope_builder.send(name.to_sym, *args)
308
- end
309
- end
310
-
311
- # Returns scope builder for specified class
312
- # @return [Syncano::ActiveRecord::ScopeBuilder]
313
- def scope_builder(object_class)
314
- Syncano::ActiveRecord::ScopeBuilder.new(object_class)
315
- end
316
- end
317
- end
318
- end