parse-stack 1.5.2 → 1.5.3
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.
- checksums.yaml +4 -4
- data/Changes.md +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +40 -80
- data/lib/parse/api/all.rb +7 -0
- data/lib/parse/api/analytics.rb +8 -3
- data/lib/parse/api/apps.rb +29 -1
- data/lib/parse/api/batch.rb +14 -129
- data/lib/parse/api/cloud_functions.rb +9 -0
- data/lib/parse/api/config.rb +10 -1
- data/lib/parse/api/files.rb +7 -2
- data/lib/parse/api/hooks.rb +45 -2
- data/lib/parse/api/objects.rb +43 -6
- data/lib/parse/api/push.rb +6 -1
- data/lib/parse/api/schemas.rb +15 -1
- data/lib/parse/api/sessions.rb +5 -0
- data/lib/parse/api/users.rb +64 -5
- data/lib/parse/client/authentication.rb +25 -8
- data/lib/parse/client/batch.rb +206 -0
- data/lib/parse/client/body_builder.rb +12 -6
- data/lib/parse/client/caching.rb +42 -10
- data/lib/parse/client/protocol.rb +51 -46
- data/lib/parse/client/response.rb +1 -47
- data/lib/parse/client.rb +171 -42
- data/lib/parse/model/acl.rb +184 -39
- data/lib/parse/model/associations/belongs_to.rb +1 -0
- data/lib/parse/model/classes/role.rb +7 -1
- data/lib/parse/model/classes/session.rb +7 -3
- data/lib/parse/model/classes/user.rb +107 -0
- data/lib/parse/model/core/actions.rb +166 -115
- data/lib/parse/model/core/fetching.rb +105 -0
- data/lib/parse/model/core/properties.rb +40 -13
- data/lib/parse/model/core/querying.rb +123 -39
- data/lib/parse/model/core/schema.rb +22 -32
- data/lib/parse/model/object.rb +26 -20
- data/lib/parse/model/pointer.rb +1 -0
- data/lib/parse/query/constraint.rb +65 -27
- data/lib/parse/query/constraints.rb +0 -3
- data/lib/parse/query/operation.rb +33 -22
- data/lib/parse/query/ordering.rb +10 -5
- data/lib/parse/stack/generators/rails.rb +5 -1
- data/lib/parse/stack/generators/templates/model_installation.rb +1 -1
- data/lib/parse/stack/generators/templates/model_role.rb +1 -1
- data/lib/parse/stack/generators/templates/model_session.rb +2 -2
- data/lib/parse/stack/generators/templates/model_user.rb +1 -1
- data/lib/parse/stack/generators/templates/parse.rb +0 -1
- data/lib/parse/stack/railtie.rb +1 -0
- data/lib/parse/stack/tasks.rb +3 -1
- data/lib/parse/stack/version.rb +3 -1
- data/lib/parse/webhooks/registration.rb +3 -3
- data/lib/parse/webhooks.rb +88 -7
- metadata +5 -3
@@ -8,26 +8,34 @@ require 'active_support/core_ext'
|
|
8
8
|
require 'time'
|
9
9
|
require 'parallel'
|
10
10
|
require_relative '../../client/request'
|
11
|
+
require_relative 'fetching'
|
11
12
|
|
12
|
-
|
13
|
-
# A Parse::RelationAction is special operation that adds one object to a relational
|
14
|
-
# table as to another. Depending on the polarity of the action, the objects are
|
15
|
-
# either added or removed from the relation. This class is used to generate the proper
|
16
|
-
# hash request format Parse needs in order to modify relational information for classes.
|
17
13
|
module Parse
|
14
|
+
# A Parse::RelationAction is special operation that adds one object to a relational
|
15
|
+
# table as to another. Depending on the polarity of the action, the objects are
|
16
|
+
# either added or removed from the relation. This class is used to generate the proper
|
17
|
+
# hash request formats Parse needs in order to modify relational information for classes.
|
18
18
|
class RelationAction
|
19
19
|
ADD = "AddRelation"
|
20
20
|
REMOVE = "RemoveRelation"
|
21
|
+
# @!attribute polarity
|
22
|
+
# @return [Boolean] whether it is an addition (true) or removal (false) action.
|
23
|
+
# @!attribute key
|
24
|
+
# @return [String] the name of the Parse field (column).
|
25
|
+
# @!attribute objects
|
26
|
+
# @return [Array<Parse::Object>] the set of objects in this relation action.
|
21
27
|
attr_accessor :polarity, :key, :objects
|
22
|
-
|
23
|
-
#
|
28
|
+
|
29
|
+
# @param field [String] the name of the Parse field tied to this relation.
|
30
|
+
# @param polarity [Boolean] whether this is an addition (true) or removal (false) action.
|
31
|
+
# @param objects [Array<Parse::Object>] the set of objects tied to this relation action.
|
24
32
|
def initialize(field, polarity: true, objects: [])
|
25
33
|
@key = field.to_s
|
26
34
|
self.polarity = polarity
|
27
|
-
@objects =
|
35
|
+
@objects = Array.wrap(objects).compact
|
28
36
|
end
|
29
37
|
|
30
|
-
#
|
38
|
+
# @return [Hash] a hash representing a relation operation.
|
31
39
|
def as_json(*args)
|
32
40
|
{ @key =>
|
33
41
|
{
|
@@ -57,13 +65,36 @@ module Parse
|
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
68
|
+
# Defines some of the save, update and destroy operations for Parse objects.
|
60
69
|
module Actions
|
61
|
-
|
70
|
+
# @!visibility private
|
62
71
|
def self.included(base)
|
63
72
|
base.extend(ClassMethods)
|
64
73
|
end
|
65
74
|
|
75
|
+
# Class methods applied to Parse::Object subclasses.
|
66
76
|
module ClassMethods
|
77
|
+
# @!attribute raise_on_save_failure
|
78
|
+
# By default, we return `true` or `false` for save and destroy operations.
|
79
|
+
# If you prefer to have `Parse::Object` raise an exception instead, you
|
80
|
+
# can tell to do so either globally or on a per-model basis. When a save
|
81
|
+
# fails, it will raise a {Parse::SaveFailureError}.
|
82
|
+
#
|
83
|
+
# When enabled, if an error is returned by Parse due to saving or
|
84
|
+
# destroying a record, due to your `before_save` or `before_delete`
|
85
|
+
# validation cloud code triggers, `Parse::Object` will return the a
|
86
|
+
# {Parse::SaveFailureError} exception type. This exception has an instance
|
87
|
+
# method of `#object` which contains the object that failed to save.
|
88
|
+
# @example
|
89
|
+
# # globally across all models
|
90
|
+
# Parse::Model.raise_on_save_failure = true
|
91
|
+
# Song.raise_on_save_failure = true # per-model
|
92
|
+
#
|
93
|
+
# # or per-instance raise on failure
|
94
|
+
# song.save!
|
95
|
+
#
|
96
|
+
# @return [Boolean] whether to raise a {Parse::SaveFailureError}
|
97
|
+
# when an object fails to save.
|
67
98
|
attr_accessor :raise_on_save_failure
|
68
99
|
|
69
100
|
def raise_on_save_failure
|
@@ -71,8 +102,14 @@ module Parse
|
|
71
102
|
Parse::Model.raise_on_save_failure
|
72
103
|
end
|
73
104
|
|
105
|
+
# Finds the first object matching the query conditions, or creates a new
|
106
|
+
# unsaved object with the attributes.
|
107
|
+
# the provided query attributes, otherwise create
|
108
|
+
# @param query_attrs [Hash] a set of query constraints that also are applied.
|
109
|
+
# @param resource_attrs [Hash] a set of attribute values to be applied if an object was not found.
|
110
|
+
# @return [Parse::Object] a Parse::Object, whether found by the query or newly created.
|
74
111
|
def first_or_create(query_attrs = {}, resource_attrs = {})
|
75
|
-
|
112
|
+
|
76
113
|
query_attrs.symbolize_keys!
|
77
114
|
resource_attrs.symbolize_keys!
|
78
115
|
obj = query(query_attrs).first
|
@@ -85,7 +122,20 @@ module Parse
|
|
85
122
|
obj
|
86
123
|
end
|
87
124
|
|
88
|
-
#
|
125
|
+
# Auto save all objects matching the query constraints. This method is
|
126
|
+
# meant to be used with a block. Any objects that are modified in the block
|
127
|
+
# will be batched for a save operation. This uses the `updated_at` field to
|
128
|
+
# continue to query for all matching objects that have not been updated.
|
129
|
+
# @param constraints [Hash] a set of query constraints.
|
130
|
+
# @yield a block which will iterate through each matching object.
|
131
|
+
# @example
|
132
|
+
#
|
133
|
+
# post = Post.first
|
134
|
+
# Comments.save_all( post: post) do |comment|
|
135
|
+
# # .. modify comment ...
|
136
|
+
# # it will automatically be saved
|
137
|
+
# end
|
138
|
+
# @return [Boolean] whether there were any errors.
|
89
139
|
def save_all(constraints = {})
|
90
140
|
force = false
|
91
141
|
|
@@ -151,6 +201,15 @@ module Parse
|
|
151
201
|
|
152
202
|
end # ClassMethods
|
153
203
|
|
204
|
+
# Perform an atomic operation on this field. This operation is done on the
|
205
|
+
# Parse server which guarantees the atomicity of the operation. This is the low-level
|
206
|
+
# API on performing atomic operations on properties for classes. These methods do not
|
207
|
+
# update the current instance with any changes the server may have made to satisfy this
|
208
|
+
# operation.
|
209
|
+
#
|
210
|
+
# @param field [String] the name of the field in the Parse collection.
|
211
|
+
# @param op_hash [Hash] The operation hash. It may also be of type {Parse::RelationAction}.
|
212
|
+
# @return [Boolean] whether the operation was successful.
|
154
213
|
def operate_field!(field, op_hash)
|
155
214
|
field = field.to_sym
|
156
215
|
field = self.field_map[field] || field
|
@@ -167,22 +226,47 @@ module Parse
|
|
167
226
|
response.success?
|
168
227
|
end
|
169
228
|
|
229
|
+
# Perform an atomic add operation to the array field.
|
230
|
+
# @param field [String] the name of the field in the Parse collection.
|
231
|
+
# @param objects [Array] the set of items to add to this field.
|
232
|
+
# @return [Boolean] whether it was successful
|
233
|
+
# @see #operate_field!
|
170
234
|
def op_add!(field,objects)
|
171
235
|
operate_field! field, { __op: :Add, objects: objects }
|
172
236
|
end
|
173
237
|
|
238
|
+
# Perform an atomic add unique operation to the array field. The objects will
|
239
|
+
# only be added if they don't already exists in the array for that particular field.
|
240
|
+
# @param field [String] the name of the field in the Parse collection.
|
241
|
+
# @param objects [Array] the set of items to add uniquely to this field.
|
242
|
+
# @return [Boolean] whether it was successful
|
243
|
+
# @see #operate_field!
|
174
244
|
def op_add_unique!(field,objects)
|
175
245
|
operate_field! field, { __op: :AddUnique, objects: objects }
|
176
246
|
end
|
177
247
|
|
248
|
+
# Perform an atomic remove operation to the array field.
|
249
|
+
# @param field [String] the name of the field in the Parse collection.
|
250
|
+
# @param objects [Array] the set of items to remove to this field.
|
251
|
+
# @return [Boolean] whether it was successful
|
252
|
+
# @see #operate_field!
|
178
253
|
def op_remove!(field, objects)
|
179
254
|
operate_field! field, { __op: :Remove, objects: objects }
|
180
255
|
end
|
181
256
|
|
257
|
+
# Perform an atomic delete operation on this field.
|
258
|
+
# @param field [String] the name of the field in the Parse collection.
|
259
|
+
# @return [Boolean] whether it was successful
|
260
|
+
# @see #operate_field!
|
182
261
|
def op_destroy!(field)
|
183
|
-
operate_field! field, { __op: :Delete }
|
262
|
+
operate_field! field, { __op: :Delete }.freeze
|
184
263
|
end
|
185
264
|
|
265
|
+
# Perform an atomic add operation on this relational field.
|
266
|
+
# @param field [String] the name of the field in the Parse collection.
|
267
|
+
# @param objects [Array<Parse::Object>] the set of objects to add to this relational field.
|
268
|
+
# @return [Boolean] whether it was successful
|
269
|
+
# @see #operate_field!
|
186
270
|
def op_add_relation!(field, objects = [])
|
187
271
|
objects = [objects] unless objects.is_a?(Array)
|
188
272
|
return false if objects.empty?
|
@@ -190,6 +274,11 @@ module Parse
|
|
190
274
|
operate_field! field, relation_action
|
191
275
|
end
|
192
276
|
|
277
|
+
# Perform an atomic remove operation on this relational field.
|
278
|
+
# @param field [String] the name of the field in the Parse collection.
|
279
|
+
# @param objects [Array<Parse::Object>] the set of objects to remove to this relational field.
|
280
|
+
# @return [Boolean] whether it was successful
|
281
|
+
# @see #operate_field!
|
193
282
|
def op_remove_relation!(field, objects = [])
|
194
283
|
objects = [objects] unless objects.is_a?(Array)
|
195
284
|
return false if objects.empty?
|
@@ -197,7 +286,18 @@ module Parse
|
|
197
286
|
operate_field! field, relation_action
|
198
287
|
end
|
199
288
|
|
200
|
-
#
|
289
|
+
# Atomically increment or decrement a specific field.
|
290
|
+
# @param field [String] the name of the field in the Parse collection.
|
291
|
+
# @param amount [Integer] the amoun to increment. Use negative values to decrement.
|
292
|
+
# @see #operate_field!
|
293
|
+
def op_increment!(field, amount = 1)
|
294
|
+
unless amount.is_a?(Numeric)
|
295
|
+
raise ArgumentError, "Amount should be numeric"
|
296
|
+
end
|
297
|
+
operate_field! field, { __op: :Increment, amount: amount.to_i }.freeze
|
298
|
+
end
|
299
|
+
|
300
|
+
# @return [Parse::Request] a destroy_request for the current object.
|
201
301
|
def destroy_request
|
202
302
|
return nil unless @id.present?
|
203
303
|
uri = self.uri_path
|
@@ -206,13 +306,16 @@ module Parse
|
|
206
306
|
r
|
207
307
|
end
|
208
308
|
|
309
|
+
# @return [String] the API uri path for this class.
|
209
310
|
def uri_path
|
210
311
|
self.client.url_prefix.path + Client.uri_path(self)
|
211
312
|
end
|
212
|
-
|
213
|
-
#
|
214
|
-
#
|
215
|
-
#
|
313
|
+
|
314
|
+
# Creates an array of all possible operations that need to be performed
|
315
|
+
# on this object. This includes all property and relational operation changes.
|
316
|
+
# @param force [Boolean] whether this object should be saved even if does not have
|
317
|
+
# pending changes.
|
318
|
+
# @return [Array<Parse::Request>] the list of API requests.
|
216
319
|
def change_requests(force = false)
|
217
320
|
requests = []
|
218
321
|
# get the URI path for this object.
|
@@ -244,6 +347,9 @@ module Parse
|
|
244
347
|
# information based on its local attributes. The bang implies that it will send
|
245
348
|
# the request even though it is possible no changes were performed. This is useful
|
246
349
|
# in kicking-off an beforeSave / afterSave hooks
|
350
|
+
# Save the object regardless of whether there are changes. This would call
|
351
|
+
# any beforeSave and afterSave cloud code hooks you have registered for this class.
|
352
|
+
# @return [Boolean] true/false whether it was successful.
|
247
353
|
def update!(raw: false)
|
248
354
|
if valid? == false
|
249
355
|
errors.full_messages.each do |msg|
|
@@ -262,13 +368,15 @@ module Parse
|
|
262
368
|
response.success?
|
263
369
|
end
|
264
370
|
|
265
|
-
#
|
371
|
+
# Save all the changes related to this object.
|
372
|
+
# @return [Boolean] true/false whether it was successful.
|
266
373
|
def update
|
267
374
|
return true unless attribute_changes?
|
268
375
|
update!
|
269
376
|
end
|
270
377
|
|
271
|
-
#
|
378
|
+
# Save the object as a new record, running all callbacks.
|
379
|
+
# @return [Boolean] true/false whether it was successful.
|
272
380
|
def create
|
273
381
|
run_callbacks :create do
|
274
382
|
res = client.create_object(parse_class, attribute_updates, session_token: _session_token)
|
@@ -287,6 +395,7 @@ module Parse
|
|
287
395
|
end
|
288
396
|
end
|
289
397
|
|
398
|
+
# @!visibility private
|
290
399
|
def _session_token
|
291
400
|
if @_session_token.respond_to?(:session_token)
|
292
401
|
@_session_token = @_session_token.session_token
|
@@ -298,6 +407,10 @@ module Parse
|
|
298
407
|
# we will create the object. If the object has an id, we will update the record.
|
299
408
|
# You can define before and after :save callbacks
|
300
409
|
# autoraise: set to true will automatically raise an exception if the save fails
|
410
|
+
# @raise Parse::SaveFailureError if the save fails
|
411
|
+
# @param autoraise [Boolean] whether to raise an exception if the save fails.
|
412
|
+
# @param session [String] a session token in order to apply ACLs to this operation.
|
413
|
+
# @return [Boolean] whether the save was successful.
|
301
414
|
def save(autoraise: false, session: nil)
|
302
415
|
return true unless changed?
|
303
416
|
success = false
|
@@ -332,13 +445,19 @@ module Parse
|
|
332
445
|
success
|
333
446
|
end
|
334
447
|
|
335
|
-
#
|
448
|
+
# Save this object and raise an exception if it fails.
|
449
|
+
# @raise Parse::SaveFailureError if the save fails
|
450
|
+
# @param session (see #save)
|
451
|
+
# @return (see #save)
|
336
452
|
def save!(session: nil)
|
337
453
|
save(autoraise: true, session: session)
|
338
454
|
end
|
339
455
|
|
340
|
-
|
341
|
-
#
|
456
|
+
|
457
|
+
# Delete this record from the Parse collection. Only valid if this object has an `id`.
|
458
|
+
# This will run all the `destroy` callbacks.
|
459
|
+
# @param session [String] a session token if you want to apply ACLs for a user in this operation.
|
460
|
+
# @return [Boolean] whether the operation was successful.
|
342
461
|
def destroy(session: nil)
|
343
462
|
return false if new?
|
344
463
|
@_session_token = session
|
@@ -358,10 +477,12 @@ module Parse
|
|
358
477
|
success
|
359
478
|
end
|
360
479
|
|
480
|
+
# Runs all the registered `before_save` related callbacks.
|
361
481
|
def prepare_save!
|
362
482
|
run_callbacks(:save) { false }
|
363
483
|
end
|
364
484
|
|
485
|
+
# @return [Hash] a hash of the list of changes made to this instance.
|
365
486
|
def changes_payload
|
366
487
|
h = attribute_updates
|
367
488
|
if relation_changes?
|
@@ -371,11 +492,14 @@ module Parse
|
|
371
492
|
h.merge!(className: parse_class) unless h.empty?
|
372
493
|
h.as_json
|
373
494
|
end
|
374
|
-
|
375
495
|
alias_method :update_payload, :changes_payload
|
376
496
|
|
377
|
-
#
|
378
|
-
#
|
497
|
+
# Generates an array with two entries for addition and removal operations. The first entry
|
498
|
+
# of the array will contain a hash of all the change operations regarding adding new relational
|
499
|
+
# objects. The second entry in the array is a hash of all the change operations regarding removing
|
500
|
+
# relation objects from this field.
|
501
|
+
# @return [Array] an array with two hashes; the first is a hash of all the addition operations and
|
502
|
+
# the second hash, all the remove operations.
|
379
503
|
def relation_change_operations
|
380
504
|
return [{},{}] unless relation_changes?
|
381
505
|
|
@@ -397,7 +521,8 @@ module Parse
|
|
397
521
|
[additions, removals]
|
398
522
|
end
|
399
523
|
|
400
|
-
#
|
524
|
+
# Saves and updates all the relational changes for made to this object.
|
525
|
+
# @return [Boolean] whether all the save or update requests were successful.
|
401
526
|
def update_relations
|
402
527
|
# relational saves require an id
|
403
528
|
return false unless @id.present?
|
@@ -425,6 +550,19 @@ module Parse
|
|
425
550
|
has_error == false
|
426
551
|
end
|
427
552
|
|
553
|
+
# Performs mass assignment using a hash with the ability to modify dirty tracking.
|
554
|
+
# This is an internal method used to set properties on the object while controlling
|
555
|
+
# whether they are dirty tracked. Each defined property has a method defined with the
|
556
|
+
# suffix `_set_attribute!` that can will be called if it is contained in the hash.
|
557
|
+
# @example
|
558
|
+
# object.set_attributes!( {"myField" => value}, false)
|
559
|
+
#
|
560
|
+
# # equivalent to calling the specific method.
|
561
|
+
# object.myField_set_attribute!(value, false)
|
562
|
+
# @param hash [Hash] the hash containing all the attribute names and values.
|
563
|
+
# @param dirty_track [Boolean] whether the assignment should be tracked in the change tracking
|
564
|
+
# system.
|
565
|
+
# @return [Hash]
|
428
566
|
def set_attributes!(hash, dirty_track = false)
|
429
567
|
return unless hash.is_a?(Hash)
|
430
568
|
hash.each do |k,v|
|
@@ -434,7 +572,7 @@ module Parse
|
|
434
572
|
end
|
435
573
|
end
|
436
574
|
|
437
|
-
#
|
575
|
+
# Clears changes information on all collections (array and relations) and all
|
438
576
|
# local attributes.
|
439
577
|
def changes_applied!
|
440
578
|
# find all fields that are of type :array
|
@@ -456,91 +594,4 @@ module Parse
|
|
456
594
|
|
457
595
|
end
|
458
596
|
|
459
|
-
module Fetching
|
460
|
-
|
461
|
-
# force fetches the current object with the data contained in Parse.
|
462
|
-
def fetch!(opts = {})
|
463
|
-
response = client.fetch_object(parse_class, id, opts)
|
464
|
-
if response.error?
|
465
|
-
puts "[Fetch Error] #{response.code}: #{response.error}"
|
466
|
-
end
|
467
|
-
# take the result hash and apply it to the attributes.
|
468
|
-
apply_attributes!(response.result, dirty_track: false)
|
469
|
-
clear_changes!
|
470
|
-
self
|
471
|
-
end
|
472
|
-
|
473
|
-
# fetches the object if needed
|
474
|
-
def fetch
|
475
|
-
# if it is a pointer, then let's go fetch the rest of the content
|
476
|
-
pointer? ? fetch! : self
|
477
|
-
end
|
478
|
-
|
479
|
-
# autofetches the object based on a key. If the key is not a Parse standard
|
480
|
-
# key, the current object is a pointer, then fetch the object - but only if
|
481
|
-
# the current object is currently autofetching.
|
482
|
-
def autofetch!(key)
|
483
|
-
key = key.to_sym
|
484
|
-
@fetch_lock ||= false
|
485
|
-
if @fetch_lock != true && pointer? && key != :acl && Parse::Properties::BASE_KEYS.include?(key) == false && respond_to?(:fetch)
|
486
|
-
#puts "AutoFetching Triggerd by: #{self.class}.#{key} (#{id})"
|
487
|
-
@fetch_lock = true
|
488
|
-
send :fetch
|
489
|
-
@fetch_lock = false
|
490
|
-
end
|
491
|
-
|
492
|
-
end
|
493
|
-
|
494
|
-
end
|
495
|
-
|
496
|
-
end
|
497
|
-
|
498
|
-
class Array
|
499
|
-
|
500
|
-
# Support for threaded operations on array items
|
501
|
-
def threaded_each(threads = 2)
|
502
|
-
Parallel.each(self, {in_threads: threads}, &Proc.new)
|
503
|
-
end
|
504
|
-
|
505
|
-
def threaded_map(threads = 2)
|
506
|
-
Parallel.map(self, {in_threads: threads}, &Proc.new)
|
507
|
-
end
|
508
|
-
|
509
|
-
def self.threaded_select(threads = 2)
|
510
|
-
Parallel.select(self, {in_threads: threads}, &Proc.new)
|
511
|
-
end
|
512
|
-
|
513
|
-
# fetches all the objects in the array (force)
|
514
|
-
# a parameter symbol can be passed indicating the lookup methodology. Default
|
515
|
-
# is parallel which fetches all objects in parallel HTTP requests.
|
516
|
-
# If nil is passed in, then all the fetching happens sequentially.
|
517
|
-
def fetch_objects!(lookup = :parallel)
|
518
|
-
# this gets all valid parse objects from the array
|
519
|
-
items = valid_parse_objects
|
520
|
-
|
521
|
-
# make parallel requests.
|
522
|
-
unless lookup == :parallel
|
523
|
-
# force fetch all objects
|
524
|
-
items.threaded_each { |o| o.fetch! }
|
525
|
-
else
|
526
|
-
# serially fetch each object
|
527
|
-
items.each { |o| o.fetch! }
|
528
|
-
end
|
529
|
-
self #return for chaining.
|
530
|
-
end
|
531
|
-
|
532
|
-
# fetches all pointer objects in the array. You can pass a symbol argument
|
533
|
-
# that provides the lookup methodology, default is :parallel. Objects that have
|
534
|
-
# already been fetched (not in a pointer state) are skipped.
|
535
|
-
def fetch_objects(lookup = :parallel)
|
536
|
-
items = valid_parse_objects
|
537
|
-
if lookup == :parallel
|
538
|
-
items.threaded_each { |o| o.fetch }
|
539
|
-
else
|
540
|
-
items.each { |e| e.fetch }
|
541
|
-
end
|
542
|
-
#self.replace items
|
543
|
-
self
|
544
|
-
end
|
545
|
-
|
546
597
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
|
2
|
+
require 'time'
|
3
|
+
require 'parallel'
|
4
|
+
|
5
|
+
module Parse
|
6
|
+
# Defines the record fetching interface for instances of Parse::Object.
|
7
|
+
module Fetching
|
8
|
+
|
9
|
+
# Force fetches and updates the current object with the data contained in the Parse collection.
|
10
|
+
# The changes applied to the object are not dirty tracked.
|
11
|
+
# @param opts [Hash] a set of options to pass to the client request.
|
12
|
+
# @return [self] the current object, useful for chaining.
|
13
|
+
def fetch!(opts = {})
|
14
|
+
response = client.fetch_object(parse_class, id, opts)
|
15
|
+
if response.error?
|
16
|
+
puts "[Fetch Error] #{response.code}: #{response.error}"
|
17
|
+
end
|
18
|
+
# take the result hash and apply it to the attributes.
|
19
|
+
apply_attributes!(response.result, dirty_track: false)
|
20
|
+
clear_changes!
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
# Fetches the object from the Parse data store if the object is in a Pointer
|
25
|
+
# state. This is similar to the `fetchIfNeeded` action in the standard Parse client SDK.
|
26
|
+
# @return [self] the current object.
|
27
|
+
def fetch
|
28
|
+
# if it is a pointer, then let's go fetch the rest of the content
|
29
|
+
pointer? ? fetch! : self
|
30
|
+
end
|
31
|
+
|
32
|
+
# Autofetches the object based on a key that is not part {Parse::Properties::BASE_KEYS}.
|
33
|
+
# If the key is not a Parse standard key, and the current object is in a
|
34
|
+
# Pointer state, then fetch the data related to this record from the Parse
|
35
|
+
# data store.
|
36
|
+
# @param key [String] the name of the attribute being accessed.
|
37
|
+
# @return [Boolean]
|
38
|
+
def autofetch!(key)
|
39
|
+
key = key.to_sym
|
40
|
+
@fetch_lock ||= false
|
41
|
+
if @fetch_lock != true && pointer? && key != :acl && Parse::Properties::BASE_KEYS.include?(key) == false && respond_to?(:fetch)
|
42
|
+
#puts "AutoFetching Triggerd by: #{self.class}.#{key} (#{id})"
|
43
|
+
@fetch_lock = true
|
44
|
+
send :fetch
|
45
|
+
@fetch_lock = false
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
class Array
|
57
|
+
|
58
|
+
# Perform a threaded each iteration on a set of array items.
|
59
|
+
# @param threads [Integer] the maximum number of threads to spawn/
|
60
|
+
# @yield the block for the each iteration.
|
61
|
+
# @return [self]
|
62
|
+
# @see Array#each
|
63
|
+
# @see https://github.com/grosser/parallel Parallel
|
64
|
+
def threaded_each(threads = 2, &block)
|
65
|
+
Parallel.each(self, {in_threads: threads}, &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Perform a threaded map operation on a set of array items.
|
69
|
+
# @param threads [Integer] the maximum number of threads to spawn
|
70
|
+
# @yield the block for the map iteration.
|
71
|
+
# @return [Array] the resultant array from the map.
|
72
|
+
# @see Array#map
|
73
|
+
# @see https://github.com/grosser/parallel Parallel
|
74
|
+
def threaded_map(threads = 2, &block)
|
75
|
+
Parallel.map(self, {in_threads: threads}, &block)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Fetches all the objects in the array even if they are not in a Pointer state.
|
79
|
+
# @param lookup [Symbol] The methodology to use for HTTP requests. Use :parallel
|
80
|
+
# to fetch all objects in parallel HTTP requests. Set to anything else to
|
81
|
+
# perform requests serially.
|
82
|
+
# @return [Array<Parse::Object>] an array of fetched Parse::Objects.
|
83
|
+
# @see Array#fetch_objects
|
84
|
+
def fetch_objects!(lookup = :parallel)
|
85
|
+
# this gets all valid parse objects from the array
|
86
|
+
items = valid_parse_objects
|
87
|
+
lookup == :parallel ? items.threaded_each(2,&:fetch!) : items.each(&:fetch!)
|
88
|
+
#self.replace items
|
89
|
+
self #return for chaining.
|
90
|
+
end
|
91
|
+
|
92
|
+
# Fetches all the objects in the array that are in Pointer state.
|
93
|
+
# @param lookup [Symbol] The methodology to use for HTTP requests. Use :parallel
|
94
|
+
# to fetch all objects in parallel HTTP requests. Set to anything else to
|
95
|
+
# perform requests serially.
|
96
|
+
# @return [Array<Parse::Object>] an array of fetched Parse::Objects.
|
97
|
+
# @see Array#fetch_objects!
|
98
|
+
def fetch_objects(lookup = :parallel)
|
99
|
+
items = valid_parse_objects
|
100
|
+
lookup == :parallel ? items.threaded_each(2,&:fetch) : items.each(&:fetch)
|
101
|
+
#self.replace items
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -14,18 +14,10 @@ require 'active_support/hash_with_indifferent_access'
|
|
14
14
|
require 'time'
|
15
15
|
|
16
16
|
|
17
|
-
# This module provides support for handling all the different types of column data types
|
18
|
-
# supported in Parse and mapping them between their remote names with their local ruby named attributes.
|
19
|
-
# By default, the convention used for naming parameters is that the remote column should be in lower-first-camelcase, (ex. myField, eventAddress), except for
|
20
|
-
# a few special columns like "id" and "acl".
|
21
|
-
# Properties are defined when creating subclasses of Parse::Object and using the `property` class method.
|
22
|
-
#
|
23
|
-
# By defining properties, dynamic methods are created in order to allow getters and setters to be used. We will go into detail below.
|
24
|
-
#
|
25
|
-
# Each class will have a different copy of attribute mapping and field mappings.
|
26
|
-
|
27
17
|
module Parse
|
28
18
|
|
19
|
+
# This module provides support for handling all the different types of column data types
|
20
|
+
# supported in Parse and mapping them between their remote names with their local ruby named attributes.
|
29
21
|
module Properties
|
30
22
|
# This is an exception that is thrown if there is an issue when creating a specific property for a class.
|
31
23
|
class DefinitionError < StandardError; end;
|
@@ -49,7 +41,10 @@ module Parse
|
|
49
41
|
module ClassMethods
|
50
42
|
|
51
43
|
# The fields method returns a mapping of all local attribute names and their data type.
|
52
|
-
# if type is passed, we return only the fields that matched that data type
|
44
|
+
# if type is passed, we return only the fields that matched that data type. If `type`
|
45
|
+
# is provided, it will only return the fields that match the data type.
|
46
|
+
# @param type [Symbol] a property type.
|
47
|
+
# @return [Hash] the defined fields for this Parse collection with their data type.
|
53
48
|
def fields(type = nil)
|
54
49
|
@fields ||= {id: :string, created_at: :date, updated_at: :date, acl: :acl}
|
55
50
|
if type.present?
|
@@ -59,11 +54,12 @@ module Parse
|
|
59
54
|
@fields
|
60
55
|
end
|
61
56
|
|
62
|
-
#
|
57
|
+
# @return [Hash] the field map for this subclass.
|
63
58
|
def field_map
|
64
59
|
@field_map ||= BASE_FIELD_MAP.dup
|
65
60
|
end
|
66
61
|
|
62
|
+
# @return [Hash] the fields that are marked as enums.
|
67
63
|
def enums
|
68
64
|
@enums ||= {}
|
69
65
|
end
|
@@ -73,6 +69,7 @@ module Parse
|
|
73
69
|
@attributes = BASE.merge(hash)
|
74
70
|
end
|
75
71
|
|
72
|
+
# @return [Hash] the fields that are marked as enums.
|
76
73
|
def attributes
|
77
74
|
@attributes ||= BASE.dup
|
78
75
|
end
|
@@ -303,7 +300,7 @@ module Parse
|
|
303
300
|
# support question mark methods for boolean
|
304
301
|
if data_type == :boolean
|
305
302
|
if self.method_defined?("#{key}?")
|
306
|
-
puts "Creating boolean helper :#{key}?. Will overwrite existing method #{self}##{key}
|
303
|
+
puts "Creating boolean helper :#{key}?. Will overwrite existing method #{self}##{key}_increment!."
|
307
304
|
end
|
308
305
|
|
309
306
|
# returns true if set to true, false otherwise
|
@@ -311,6 +308,36 @@ module Parse
|
|
311
308
|
unless opts[:scopes] == false
|
312
309
|
scope key, ->(opts = {}){ query( opts.merge(key => true) ) }
|
313
310
|
end
|
311
|
+
elsif data_type == :integer || data_type == :float
|
312
|
+
if self.method_defined?("#{key}_increment!")
|
313
|
+
puts "Creating increment helper :#{key}_increment!. Will overwrite existing method #{self}##{key}_increment!."
|
314
|
+
end
|
315
|
+
|
316
|
+
define_method("#{key}_increment!") do |amount = 1|
|
317
|
+
unless amount.is_a?(Numeric)
|
318
|
+
raise ArgumentError, "Amount needs to be an integer"
|
319
|
+
end
|
320
|
+
result = self.op_increment!(key, amount)
|
321
|
+
if result
|
322
|
+
new_value = send(key).to_i + amount
|
323
|
+
# set the updated value, with no dirty tracking
|
324
|
+
self.send set_attribute_method, new_value, false
|
325
|
+
end
|
326
|
+
result
|
327
|
+
end
|
328
|
+
|
329
|
+
if self.method_defined?("#{key}_decrement!")
|
330
|
+
puts "Creating decrement helper :#{key}_decrement!. Will overwrite existing method #{self}##{key}_decrement!."
|
331
|
+
end
|
332
|
+
|
333
|
+
define_method("#{key}_decrement!") do |amount = -1|
|
334
|
+
unless amount.is_a?(Numeric)
|
335
|
+
raise ArgumentError, "Amount needs to be an integer"
|
336
|
+
end
|
337
|
+
amount = -amount if amount > 0
|
338
|
+
send("#{key}_increment!", amount)
|
339
|
+
end
|
340
|
+
|
314
341
|
end
|
315
342
|
|
316
343
|
# The second method to be defined is a setter method. This is done by
|