parse-stack 1.8.0 → 1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.solargraph.yml +23 -0
- data/.travis.yml +0 -1
- data/Gemfile +13 -12
- data/Gemfile.lock +88 -51
- data/README.md +2 -4
- data/Rakefile +14 -14
- data/lib/parse/api/aggregate.rb +4 -7
- data/lib/parse/api/all.rb +1 -1
- data/lib/parse/api/analytics.rb +0 -3
- data/lib/parse/api/batch.rb +3 -5
- data/lib/parse/api/cloud_functions.rb +0 -3
- data/lib/parse/api/config.rb +0 -4
- data/lib/parse/api/files.rb +3 -7
- data/lib/parse/api/hooks.rb +4 -8
- data/lib/parse/api/objects.rb +7 -12
- data/lib/parse/api/push.rb +0 -4
- data/lib/parse/api/schema.rb +2 -6
- data/lib/parse/api/server.rb +4 -7
- data/lib/parse/api/sessions.rb +2 -5
- data/lib/parse/api/users.rb +9 -14
- data/lib/parse/client.rb +54 -50
- data/lib/parse/client/authentication.rb +29 -33
- data/lib/parse/client/batch.rb +8 -11
- data/lib/parse/client/body_builder.rb +19 -20
- data/lib/parse/client/caching.rb +23 -28
- data/lib/parse/client/protocol.rb +11 -12
- data/lib/parse/client/request.rb +4 -6
- data/lib/parse/client/response.rb +5 -7
- data/lib/parse/model/acl.rb +14 -12
- data/lib/parse/model/associations/belongs_to.rb +14 -21
- data/lib/parse/model/associations/collection_proxy.rb +328 -329
- data/lib/parse/model/associations/has_many.rb +18 -25
- data/lib/parse/model/associations/has_one.rb +6 -11
- data/lib/parse/model/associations/pointer_collection_proxy.rb +5 -8
- data/lib/parse/model/associations/relation_collection_proxy.rb +5 -9
- data/lib/parse/model/bytes.rb +8 -10
- data/lib/parse/model/classes/installation.rb +2 -4
- data/lib/parse/model/classes/product.rb +2 -5
- data/lib/parse/model/classes/role.rb +3 -5
- data/lib/parse/model/classes/session.rb +2 -5
- data/lib/parse/model/classes/user.rb +20 -16
- data/lib/parse/model/core/actions.rb +31 -46
- data/lib/parse/model/core/builder.rb +6 -6
- data/lib/parse/model/core/errors.rb +0 -1
- data/lib/parse/model/core/fetching.rb +45 -50
- data/lib/parse/model/core/properties.rb +51 -66
- data/lib/parse/model/core/querying.rb +291 -294
- data/lib/parse/model/core/schema.rb +89 -92
- data/lib/parse/model/date.rb +16 -17
- data/lib/parse/model/file.rb +171 -174
- data/lib/parse/model/geopoint.rb +12 -16
- data/lib/parse/model/model.rb +31 -37
- data/lib/parse/model/object.rb +47 -53
- data/lib/parse/model/pointer.rb +177 -176
- data/lib/parse/model/push.rb +8 -10
- data/lib/parse/model/shortnames.rb +1 -2
- data/lib/parse/model/time_zone.rb +3 -5
- data/lib/parse/query.rb +34 -35
- data/lib/parse/query/constraint.rb +4 -6
- data/lib/parse/query/constraints.rb +21 -29
- data/lib/parse/query/operation.rb +8 -11
- data/lib/parse/query/ordering.rb +45 -49
- data/lib/parse/stack.rb +11 -12
- data/lib/parse/stack/generators/rails.rb +28 -30
- data/lib/parse/stack/generators/templates/model.erb +5 -6
- data/lib/parse/stack/generators/templates/model_installation.rb +0 -1
- data/lib/parse/stack/generators/templates/model_role.rb +0 -1
- data/lib/parse/stack/generators/templates/model_session.rb +0 -1
- data/lib/parse/stack/generators/templates/model_user.rb +0 -1
- data/lib/parse/stack/generators/templates/parse.rb +9 -9
- data/lib/parse/stack/generators/templates/webhooks.rb +1 -2
- data/lib/parse/stack/railtie.rb +2 -4
- data/lib/parse/stack/tasks.rb +70 -86
- data/lib/parse/stack/version.rb +1 -1
- data/lib/parse/webhooks.rb +19 -26
- data/lib/parse/webhooks/payload.rb +26 -28
- data/lib/parse/webhooks/registration.rb +23 -31
- data/parse-stack.gemspec +25 -25
- data/parse-stack.png +0 -0
- metadata +13 -7
- data/.github/parse-ruby-sdk.png +0 -0
@@ -1,24 +1,21 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
|
4
|
+
require "active_model"
|
5
|
+
require "active_support"
|
6
|
+
require "active_support/inflector"
|
7
|
+
require "active_support/core_ext"
|
8
|
+
require "time"
|
9
|
+
require "parallel"
|
10
|
+
require_relative "../../client/request"
|
11
|
+
require_relative "fetching"
|
13
12
|
|
14
13
|
module Parse
|
15
|
-
|
16
14
|
class Query
|
17
15
|
|
18
|
-
|
19
16
|
# Supporting the `all` class method to be used in scope chaining with queries.
|
20
17
|
# @!visibility private
|
21
|
-
def all(expressions = {limit: :max})
|
18
|
+
def all(expressions = { limit: :max })
|
22
19
|
conditions(expressions)
|
23
20
|
return results(&Proc.new) if block_given?
|
24
21
|
results
|
@@ -49,7 +46,6 @@ module Parse
|
|
49
46
|
klass.save_all(hash_constraints, &Proc.new) if block_given?
|
50
47
|
klass.save_all(hash_constraints)
|
51
48
|
end
|
52
|
-
|
53
49
|
end
|
54
50
|
|
55
51
|
# A Parse::RelationAction is special operation that adds one object to a relational
|
@@ -80,16 +76,12 @@ module Parse
|
|
80
76
|
|
81
77
|
# @return [Hash] a hash representing a relation operation.
|
82
78
|
def as_json(*args)
|
83
|
-
{ @key =>
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
}
|
88
|
-
}.as_json
|
79
|
+
{ @key => {
|
80
|
+
"__op" => (@polarity == true ? ADD : REMOVE),
|
81
|
+
"objects" => objects.parse_pointers,
|
82
|
+
} }.as_json
|
89
83
|
end
|
90
|
-
|
91
84
|
end
|
92
|
-
|
93
85
|
end
|
94
86
|
|
95
87
|
# This module is mainly all the basic orm operations. To support batching actions,
|
@@ -132,7 +124,7 @@ module Parse
|
|
132
124
|
# @example
|
133
125
|
# # globally across all models
|
134
126
|
# Parse::Model.raise_on_save_failure = true
|
135
|
-
|
127
|
+
# Song.raise_on_save_failure = true # per-model
|
136
128
|
#
|
137
129
|
# # or per-instance raise on failure
|
138
130
|
# song.save!
|
@@ -156,7 +148,6 @@ module Parse
|
|
156
148
|
# @param resource_attrs [Hash] a set of attribute values to be applied if an object was not found.
|
157
149
|
# @return [Parse::Object] a Parse::Object, whether found by the query or newly created.
|
158
150
|
def first_or_create(query_attrs = {}, resource_attrs = {})
|
159
|
-
|
160
151
|
query_attrs = query_attrs.symbolize_keys
|
161
152
|
resource_attrs = resource_attrs.symbolize_keys
|
162
153
|
obj = query(query_attrs).first
|
@@ -205,7 +196,7 @@ module Parse
|
|
205
196
|
def save_all(constraints = {})
|
206
197
|
invalid_constraints = constraints.keys.any? do |k|
|
207
198
|
(k == :updated_at || k == :updatedAt) ||
|
208
|
-
(
|
199
|
+
(k.is_a?(Parse::Operation) && (k.operand == :updated_at || k.operand == :updatedAt))
|
209
200
|
end
|
210
201
|
if invalid_constraints
|
211
202
|
raise ArgumentError,
|
@@ -267,14 +258,12 @@ module Parse
|
|
267
258
|
warn "[#{self}.save_all] Reached anchor date #{anchor_date} < #{cursor.updated_at}"
|
268
259
|
break cursor
|
269
260
|
end
|
270
|
-
|
271
261
|
end
|
272
262
|
|
273
263
|
has_errors ||= batch.error?
|
274
264
|
end
|
275
265
|
not has_errors
|
276
266
|
end
|
277
|
-
|
278
267
|
end # ClassMethods
|
279
268
|
|
280
269
|
# Perform an atomic operation on this field. This operation is done on the
|
@@ -295,7 +284,7 @@ module Parse
|
|
295
284
|
op_hash = { field => op_hash }.as_json
|
296
285
|
end
|
297
286
|
|
298
|
-
response = client.update_object(parse_class, id, op_hash, session_token: _session_token
|
287
|
+
response = client.update_object(parse_class, id, op_hash, session_token: _session_token)
|
299
288
|
if response.error?
|
300
289
|
puts "[#{parse_class}:#{field} Operation] #{response.error}"
|
301
290
|
end
|
@@ -307,7 +296,7 @@ module Parse
|
|
307
296
|
# @param objects [Array] the set of items to add to this field.
|
308
297
|
# @return [Boolean] whether it was successful
|
309
298
|
# @see #operate_field!
|
310
|
-
def op_add!(field,objects)
|
299
|
+
def op_add!(field, objects)
|
311
300
|
operate_field! field, { __op: :Add, objects: objects }
|
312
301
|
end
|
313
302
|
|
@@ -317,7 +306,7 @@ module Parse
|
|
317
306
|
# @param objects [Array] the set of items to add uniquely to this field.
|
318
307
|
# @return [Boolean] whether it was successful
|
319
308
|
# @see #operate_field!
|
320
|
-
def op_add_unique!(field,objects)
|
309
|
+
def op_add_unique!(field, objects)
|
321
310
|
operate_field! field, { __op: :AddUnique, objects: objects }
|
322
311
|
end
|
323
312
|
|
@@ -377,7 +366,7 @@ module Parse
|
|
377
366
|
def destroy_request
|
378
367
|
return nil unless @id.present?
|
379
368
|
uri = self.uri_path
|
380
|
-
r = Request.new(
|
369
|
+
r = Request.new(:delete, uri)
|
381
370
|
r.tag = object_id
|
382
371
|
r
|
383
372
|
end
|
@@ -401,7 +390,7 @@ module Parse
|
|
401
390
|
if attribute_changes? || force
|
402
391
|
# if it's new, then we should call :post for creating the object.
|
403
392
|
method = new? ? :post : :put
|
404
|
-
r = Request.new(
|
393
|
+
r = Request.new(method, uri, body: attribute_updates)
|
405
394
|
r.tag = object_id
|
406
395
|
requests << r
|
407
396
|
end
|
@@ -411,7 +400,7 @@ module Parse
|
|
411
400
|
if @id.present? && relation_changes?
|
412
401
|
relation_change_operations.each do |ops|
|
413
402
|
next if ops.empty?
|
414
|
-
r = Request.new(
|
403
|
+
r = Request.new(:put, uri, body: ops)
|
415
404
|
r.tag = object_id
|
416
405
|
requests << r
|
417
406
|
end
|
@@ -515,7 +504,7 @@ module Parse
|
|
515
504
|
if relation_changes?
|
516
505
|
# get the list of changed keys
|
517
506
|
changed_attribute_keys = changed - relations.keys.map(&:to_s)
|
518
|
-
clear_attribute_changes(
|
507
|
+
clear_attribute_changes(changed_attribute_keys)
|
519
508
|
success = update_relations
|
520
509
|
if success
|
521
510
|
changes_applied!
|
@@ -528,7 +517,6 @@ module Parse
|
|
528
517
|
elsif self.class.raise_on_save_failure || autoraise.present?
|
529
518
|
raise Parse::RecordNotSaved.new(self), "Failed to create or save attributes. #{self.parse_class} was not saved."
|
530
519
|
end
|
531
|
-
|
532
520
|
end #callbacks
|
533
521
|
@_session_token = nil
|
534
522
|
success
|
@@ -543,7 +531,6 @@ module Parse
|
|
543
531
|
save(autoraise: true, session: session)
|
544
532
|
end
|
545
533
|
|
546
|
-
|
547
534
|
# Delete this record from the Parse collection. Only valid if this object has an `id`.
|
548
535
|
# This will run all the `destroy` callbacks.
|
549
536
|
# @param session [String] a session token if you want to apply ACLs for a user in this operation.
|
@@ -577,12 +564,13 @@ module Parse
|
|
577
564
|
def changes_payload
|
578
565
|
h = attribute_updates
|
579
566
|
if relation_changes?
|
580
|
-
r =
|
567
|
+
r = relation_change_operations.select { |s| s.present? }.first
|
581
568
|
h.merge!(r) if r.present?
|
582
569
|
end
|
583
570
|
#h.merge!(className: parse_class) unless h.empty?
|
584
571
|
h.as_json
|
585
572
|
end
|
573
|
+
|
586
574
|
alias_method :update_payload, :changes_payload
|
587
575
|
|
588
576
|
# Generates an array with two entries for addition and removal operations. The first entry
|
@@ -592,12 +580,12 @@ module Parse
|
|
592
580
|
# @return [Array] an array with two hashes; the first is a hash of all the addition operations and
|
593
581
|
# the second hash, all the remove operations.
|
594
582
|
def relation_change_operations
|
595
|
-
return [{},{}] unless relation_changes?
|
583
|
+
return [{}, {}] unless relation_changes?
|
596
584
|
|
597
585
|
additions = []
|
598
586
|
removals = []
|
599
587
|
# go through all the additions of a collection and generate an action to add.
|
600
|
-
relation_updates.each do |field,collection|
|
588
|
+
relation_updates.each do |field, collection|
|
601
589
|
if collection.additions.count > 0
|
602
590
|
additions.push Parse::RelationAction.new(field, objects: collection.additions, polarity: true)
|
603
591
|
end
|
@@ -607,8 +595,8 @@ module Parse
|
|
607
595
|
end
|
608
596
|
end
|
609
597
|
# merge all additions and removals into one large hash
|
610
|
-
additions = additions.reduce({}) { |m,v| m.merge! v.as_json }
|
611
|
-
removals = removals.reduce({}) { |m,v| m.merge! v.as_json }
|
598
|
+
additions = additions.reduce({}) { |m, v| m.merge! v.as_json }
|
599
|
+
removals = removals.reduce({}) { |m, v| m.merge! v.as_json }
|
612
600
|
[additions, removals]
|
613
601
|
end
|
614
602
|
|
@@ -656,7 +644,7 @@ module Parse
|
|
656
644
|
# @return [Hash]
|
657
645
|
def set_attributes!(hash, dirty_track = false)
|
658
646
|
return unless hash.is_a?(Hash)
|
659
|
-
hash.each do |k,v|
|
647
|
+
hash.each do |k, v|
|
660
648
|
next if k == Parse::Model::OBJECT_ID || k == Parse::Model::ID
|
661
649
|
method = "#{k}_set_attribute!"
|
662
650
|
send(method, v, dirty_track) if respond_to?(method)
|
@@ -667,23 +655,20 @@ module Parse
|
|
667
655
|
# local attributes.
|
668
656
|
def changes_applied!
|
669
657
|
# find all fields that are of type :array
|
670
|
-
fields(:array) do |key,v|
|
658
|
+
fields(:array) do |key, v|
|
671
659
|
proxy = send(key)
|
672
660
|
# clear changes
|
673
661
|
proxy.changes_applied! if proxy.respond_to?(:changes_applied!)
|
674
662
|
end
|
675
663
|
|
676
664
|
# for all relational fields,
|
677
|
-
relations.each do |key,v|
|
665
|
+
relations.each do |key, v|
|
678
666
|
proxy = send(key)
|
679
667
|
# clear changes if they support the method.
|
680
668
|
proxy.changes_applied! if proxy.respond_to?(:changes_applied!)
|
681
669
|
end
|
682
670
|
changes_applied
|
683
671
|
end
|
684
|
-
|
685
|
-
|
686
672
|
end
|
687
673
|
end
|
688
|
-
|
689
674
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require_relative
|
4
|
+
require "active_support"
|
5
|
+
require "active_support/inflector"
|
6
|
+
require "active_support/core_ext"
|
7
|
+
require_relative "../object"
|
8
8
|
|
9
9
|
module Parse
|
10
10
|
# Create all Parse::Object subclasses, including their properties and inferred
|
@@ -60,9 +60,9 @@ module Parse
|
|
60
60
|
|
61
61
|
data_type = type[:type].downcase.to_sym
|
62
62
|
if data_type == :pointer
|
63
|
-
klass.belongs_to key, as: type[:targetClass],
|
63
|
+
klass.belongs_to key, as: type[:targetClass], field: field
|
64
64
|
elsif data_type == :relation
|
65
|
-
klass.has_many key, through: :relation, as: type[:targetClass],
|
65
|
+
klass.has_many key, through: :relation, as: type[:targetClass], field: field
|
66
66
|
else
|
67
67
|
klass.property key, data_type, field: field
|
68
68
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require "time"
|
5
|
+
require "parallel"
|
6
6
|
|
7
7
|
module Parse
|
8
8
|
# Combines a set of core functionality for {Parse::Object} and its subclasses.
|
@@ -48,62 +48,57 @@ module Parse
|
|
48
48
|
send :fetch
|
49
49
|
@fetch_lock = false
|
50
50
|
end
|
51
|
-
|
52
51
|
end
|
53
|
-
|
54
52
|
end
|
55
53
|
end
|
56
54
|
end
|
57
55
|
|
58
|
-
|
59
|
-
|
60
56
|
class Array
|
61
57
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
# Perform a threaded map operation on a set of array items.
|
73
|
-
# @param threads [Integer] the maximum number of threads to spawn
|
74
|
-
# @yield the block for the map iteration.
|
75
|
-
# @return [Array] the resultant array from the map.
|
76
|
-
# @see Array#map
|
77
|
-
# @see https://github.com/grosser/parallel Parallel
|
78
|
-
def threaded_map(threads = 2, &block)
|
79
|
-
Parallel.map(self, {in_threads: threads}, &block)
|
80
|
-
end
|
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
|
81
67
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
lookup == :parallel ? items.threaded_each(2,&:fetch!) : items.each(&:fetch!)
|
92
|
-
#self.replace items
|
93
|
-
self #return for chaining.
|
94
|
-
end
|
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
|
95
77
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
108
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
|
109
104
|
end
|
@@ -1,18 +1,17 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
|
4
|
+
require "active_model"
|
5
|
+
require "active_support"
|
6
|
+
require "active_support/inflector"
|
7
|
+
require "active_support/core_ext"
|
8
|
+
require "active_support/core_ext/object"
|
9
|
+
require "active_support/inflector"
|
10
|
+
require "active_model_serializers"
|
11
|
+
require "active_support/inflector"
|
12
|
+
require "active_model_serializers"
|
13
|
+
require "active_support/hash_with_indifferent_access"
|
14
|
+
require "time"
|
16
15
|
|
17
16
|
module Parse
|
18
17
|
|
@@ -22,15 +21,15 @@ module Parse
|
|
22
21
|
# These are the base types supported by Parse.
|
23
22
|
TYPES = [:string, :relation, :integer, :float, :boolean, :date, :array, :file, :geopoint, :bytes, :object, :acl, :timezone].freeze
|
24
23
|
# These are the base mappings of the remote field name types.
|
25
|
-
BASE = {objectId: :string, createdAt: :date, updatedAt: :date, ACL: :acl}.freeze
|
24
|
+
BASE = { objectId: :string, createdAt: :date, updatedAt: :date, ACL: :acl }.freeze
|
26
25
|
# The list of properties that are part of all objects
|
27
26
|
BASE_KEYS = [:id, :created_at, :updated_at].freeze
|
28
27
|
# Default hash map of local attribute name to remote column name
|
29
|
-
BASE_FIELD_MAP = {id: :objectId, created_at: :createdAt, updated_at: :updatedAt, acl: :ACL}.freeze
|
28
|
+
BASE_FIELD_MAP = { id: :objectId, created_at: :createdAt, updated_at: :updatedAt, acl: :ACL }.freeze
|
30
29
|
# The delete operation hash.
|
31
|
-
CORE_FIELDS = {id: :string, created_at: :date, updated_at: :date, acl: :acl}.freeze
|
30
|
+
CORE_FIELDS = { id: :string, created_at: :date, updated_at: :date, acl: :acl }.freeze
|
32
31
|
# The delete operation hash.
|
33
|
-
DELETE_OP = {"__op"=>"Delete"}.freeze
|
32
|
+
DELETE_OP = { "__op" => "Delete" }.freeze
|
34
33
|
# @!visibility private
|
35
34
|
def self.included(base)
|
36
35
|
base.extend(ClassMethods)
|
@@ -49,7 +48,7 @@ module Parse
|
|
49
48
|
@fields ||= (self == Parse::Object ? CORE_FIELDS : Parse::Object.fields).dup
|
50
49
|
if type.present?
|
51
50
|
type = type.to_sym
|
52
|
-
return @fields.select { |k,v| v == type }
|
51
|
+
return @fields.select { |k, v| v == type }
|
53
52
|
end
|
54
53
|
@fields
|
55
54
|
end
|
@@ -101,7 +100,6 @@ module Parse
|
|
101
100
|
# "myDate" (lower-first-camelcase) with a Parse data type of Date.
|
102
101
|
# You can override the implicit naming behavior by passing the option :field to override.
|
103
102
|
def property(key, data_type = :string, **opts)
|
104
|
-
|
105
103
|
key = key.to_sym
|
106
104
|
ivar = :"@#{key}"
|
107
105
|
will_change_method = :"#{key}_will_change!"
|
@@ -125,25 +123,24 @@ module Parse
|
|
125
123
|
|
126
124
|
# set defaults
|
127
125
|
opts = { required: false,
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
}.merge( opts )
|
126
|
+
alias: true,
|
127
|
+
symbolize: false,
|
128
|
+
enum: nil,
|
129
|
+
scopes: true,
|
130
|
+
_prefix: nil,
|
131
|
+
_suffix: false,
|
132
|
+
field: key.to_s.camelize(:lower) }.merge(opts)
|
136
133
|
#By default, the remote field name is a lower-first-camelcase version of the key
|
137
134
|
# it can be overriden by the :field parameter
|
138
135
|
parse_field = opts[:field].to_sym
|
139
136
|
# if this is a custom property that is already defined, OR it is a subclass trying to define a core property
|
140
137
|
# then warn and exit.
|
141
|
-
if (self.fields[key].present? && BASE_FIELD_MAP[key].nil?) || (
|
138
|
+
if (self.fields[key].present? && BASE_FIELD_MAP[key].nil?) || (self < Parse::Object && BASE_FIELD_MAP.has_key?(key))
|
142
139
|
warn "Property #{self}##{key} already defined with data type :#{data_type}. Will be ignored."
|
143
140
|
return false
|
144
141
|
end
|
145
142
|
# We keep the list of fields that are on the remote Parse store
|
146
|
-
if self.fields[parse_field].present? || (
|
143
|
+
if self.fields[parse_field].present? || (self < Parse::Object && BASE.has_key?(parse_field))
|
147
144
|
warn "Alias property #{self}##{parse_field} conflicts with previously defined property. Will be ignored."
|
148
145
|
return false
|
149
146
|
# raise ArgumentError
|
@@ -152,13 +149,13 @@ module Parse
|
|
152
149
|
define_attribute_methods key
|
153
150
|
|
154
151
|
# this hash keeps list of attributes (based on remote fields) and their data types
|
155
|
-
self.attributes.merge!(
|
152
|
+
self.attributes.merge!(parse_field => data_type)
|
156
153
|
# this maps all the possible attribute fields and their data types. We use both local
|
157
154
|
# keys and remote keys because when we receive a remote object that has the remote field name
|
158
155
|
# we need to know what the data type conversion should be.
|
159
|
-
self.fields.merge!(
|
156
|
+
self.fields.merge!(key => data_type, parse_field => data_type)
|
160
157
|
# This creates a mapping between the local field and the remote field name.
|
161
|
-
self.field_map.merge!(
|
158
|
+
self.field_map.merge!(key => parse_field)
|
162
159
|
|
163
160
|
# if the field is marked as required, then add validations
|
164
161
|
if opts[:required]
|
@@ -183,7 +180,6 @@ module Parse
|
|
183
180
|
is_enum_type = opts[:enum].nil? == false
|
184
181
|
|
185
182
|
if is_enum_type
|
186
|
-
|
187
183
|
unless data_type == :string
|
188
184
|
raise ArgumentError, "Property #{self}##{parse_field} :enum option is only supported on :string data types."
|
189
185
|
end
|
@@ -196,7 +192,7 @@ module Parse
|
|
196
192
|
|
197
193
|
enum_values = enum_values.dup.map(&:to_sym).freeze
|
198
194
|
|
199
|
-
self.enums.merge!(
|
195
|
+
self.enums.merge!(key => enum_values)
|
200
196
|
allow_nil = opts[:required] == false
|
201
197
|
validates key, inclusion: { in: enum_values }, allow_nil: allow_nil
|
202
198
|
|
@@ -217,9 +213,7 @@ module Parse
|
|
217
213
|
|
218
214
|
class_method_name = prefix_or_key.to_s.pluralize.to_sym
|
219
215
|
if singleton_class.method_defined?(class_method_name)
|
220
|
-
raise ArgumentError, "You tried to define an enum named `#{key}` for #{self} " +
|
221
|
-
"but this will generate a method `#{self}.#{class_method_name}` " + \
|
222
|
-
" which is already defined. Try using :_suffix or :_prefix options."
|
216
|
+
raise ArgumentError, "You tried to define an enum named `#{key}` for #{self} " + "but this will generate a method `#{self}.#{class_method_name}` " + " which is already defined. Try using :_suffix or :_prefix options."
|
223
217
|
end
|
224
218
|
|
225
219
|
define_singleton_method(class_method_name) { enum_values }
|
@@ -239,18 +233,14 @@ module Parse
|
|
239
233
|
elsif prefix.present?
|
240
234
|
method_name = :"#{prefix}_#{enum}"
|
241
235
|
end
|
242
|
-
self.scope method_name, ->(ex = {}){ ex.merge!(key => enum); query(
|
243
|
-
|
236
|
+
self.scope method_name, ->(ex = {}) { ex.merge!(key => enum); query(ex) }
|
244
237
|
|
245
238
|
define_method("#{method_name}!") { send set_attribute_method, enum, true }
|
246
239
|
define_method("#{method_name}?") { enum == send(key).to_s.to_sym }
|
247
240
|
end
|
248
241
|
end # unless scopes
|
249
|
-
|
250
242
|
end # if is enum
|
251
243
|
|
252
|
-
|
253
|
-
|
254
244
|
symbolize_value = opts[:symbolize]
|
255
245
|
|
256
246
|
#only support symbolization of string data types
|
@@ -271,7 +261,6 @@ module Parse
|
|
271
261
|
# we'll assume it's just a plain literal value
|
272
262
|
default_value.is_a?(Proc) ? default_value.call(self) : default_value
|
273
263
|
end
|
274
|
-
|
275
264
|
end
|
276
265
|
|
277
266
|
# We define a getter with the key
|
@@ -295,12 +284,11 @@ module Parse
|
|
295
284
|
# if value is nil (even after fetching), then lets see if the developer
|
296
285
|
# set a default value for this attribute.
|
297
286
|
if value.nil? && respond_to?("#{key}_default")
|
298
|
-
|
299
|
-
|
300
|
-
value = format_value(key, value, data_type)
|
287
|
+
value = send("#{key}_default")
|
288
|
+
value = format_value(key, value, data_type)
|
301
289
|
# lets set the variable with the updated value
|
302
|
-
|
303
|
-
|
290
|
+
instance_variable_set ivar, value
|
291
|
+
send will_change_method
|
304
292
|
elsif value.nil? && data_type == :array
|
305
293
|
value = Parse::CollectionProxy.new [], delegate: self, key: key
|
306
294
|
instance_variable_set ivar, value
|
@@ -318,12 +306,12 @@ module Parse
|
|
318
306
|
end
|
319
307
|
# finally return the value
|
320
308
|
if symbolize_value
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
309
|
+
if data_type == :string
|
310
|
+
return value.respond_to?(:to_sym) ? value.to_sym : value
|
311
|
+
elsif data_type == :array && value.is_a?(Array)
|
312
|
+
# value.map(&:to_sym)
|
313
|
+
return value.compact.map { |m| m.respond_to?(:to_sym) ? m.to_sym : m }
|
314
|
+
end
|
327
315
|
end
|
328
316
|
|
329
317
|
value
|
@@ -338,7 +326,7 @@ module Parse
|
|
338
326
|
# returns true if set to true, false otherwise
|
339
327
|
define_method("#{key}?") { (send(key) == true) }
|
340
328
|
unless opts[:scopes] == false
|
341
|
-
scope key, ->(opts = {}){ query(
|
329
|
+
scope key, ->(opts = {}) { query(opts.merge(key => true)) }
|
342
330
|
end
|
343
331
|
elsif data_type == :integer || data_type == :float
|
344
332
|
if self.method_defined?("#{key}_increment!")
|
@@ -369,7 +357,6 @@ module Parse
|
|
369
357
|
amount = -amount if amount > 0
|
370
358
|
send("#{key}_increment!", amount)
|
371
359
|
end
|
372
|
-
|
373
360
|
end
|
374
361
|
|
375
362
|
# The second method to be defined is a setter method. This is done by
|
@@ -393,7 +380,7 @@ module Parse
|
|
393
380
|
# this will grab the current value and keep a copy of it - but we only do this if
|
394
381
|
# the new value being set is different from the current value stored.
|
395
382
|
if track == true
|
396
|
-
send will_change_method unless val == instance_variable_get(
|
383
|
+
send will_change_method unless val == instance_variable_get(ivar)
|
397
384
|
end
|
398
385
|
|
399
386
|
if symbolize_value
|
@@ -435,7 +422,6 @@ module Parse
|
|
435
422
|
end
|
436
423
|
true
|
437
424
|
end # property
|
438
|
-
|
439
425
|
end #ClassMethods
|
440
426
|
|
441
427
|
# @return [Hash] a hash mapping of all property fields and their types.
|
@@ -451,7 +437,7 @@ module Parse
|
|
451
437
|
# TODO: We can optimize
|
452
438
|
# @return [Hash] returns the list of property attributes for this class.
|
453
439
|
def attributes
|
454
|
-
{__type: :string, :className => :string}.merge!(self.class.attributes)
|
440
|
+
{ __type: :string, :className => :string }.merge!(self.class.attributes)
|
455
441
|
end
|
456
442
|
|
457
443
|
# support for setting a hash of attributes on the object with a given dirty tracking value
|
@@ -466,7 +452,7 @@ module Parse
|
|
466
452
|
@id ||= hash[Parse::Model::ID] || hash[Parse::Model::OBJECT_ID] || hash[:objectId]
|
467
453
|
hash.each do |key, value|
|
468
454
|
method = "#{key}_set_attribute!".freeze
|
469
|
-
send(method, value, dirty_track) if respond_to?(
|
455
|
+
send(method, value, dirty_track) if respond_to?(method)
|
470
456
|
end
|
471
457
|
end
|
472
458
|
|
@@ -494,7 +480,7 @@ module Parse
|
|
494
480
|
next unless fields[key].present?
|
495
481
|
remote_field = self.field_map[key] || key
|
496
482
|
h[remote_field] = send key
|
497
|
-
h[remote_field] = {__op: :Delete} if h[remote_field].nil?
|
483
|
+
h[remote_field] = { __op: :Delete } if h[remote_field].nil?
|
498
484
|
# in the case that the field is a Parse object, generate a pointer
|
499
485
|
# if it is a Parse::PointerCollectionProxy, then make sure we get a list of pointers.
|
500
486
|
h[remote_field] = h[remote_field].parse_pointers if h[remote_field].is_a?(Parse::PointerCollectionProxy)
|
@@ -509,6 +495,7 @@ module Parse
|
|
509
495
|
fields[key.to_sym].present?
|
510
496
|
end
|
511
497
|
end
|
498
|
+
|
512
499
|
# Returns a formatted value based on the operation hash and data_type of the property.
|
513
500
|
# For some values in Parse, they are specified as operation hashes which could include
|
514
501
|
# Add, Remove, Delete, AddUnique and Increment.
|
@@ -585,7 +572,7 @@ module Parse
|
|
585
572
|
val = val.to_f unless val.blank?
|
586
573
|
when :acl
|
587
574
|
# ACL types go through a special conversion
|
588
|
-
|
575
|
+
val = ACL.typecast(val, self)
|
589
576
|
when :date
|
590
577
|
# if it respond to parse_date, then use that as the conversion.
|
591
578
|
if val.respond_to?(:parse_date) && val.is_a?(Parse::Date) == false
|
@@ -596,9 +583,9 @@ module Parse
|
|
596
583
|
elsif val.is_a?(String)
|
597
584
|
# if it's a string, try parsing the date
|
598
585
|
val = Parse::Date.parse val
|
599
|
-
|
600
|
-
|
601
|
-
|
586
|
+
#elsif val.present?
|
587
|
+
# pus "[Parse::Stack] Invalid date value '#{val}' assigned to #{self.class}##{key}, it should be a Parse::Date or DateTime."
|
588
|
+
# raise ValueError, "Invalid date value '#{val}' assigned to #{self.class}##{key}, it should be a Parse::Date or DateTime."
|
602
589
|
end
|
603
590
|
when :timezone
|
604
591
|
val = Parse::TimeZone.new(val) if val.present?
|
@@ -613,7 +600,5 @@ module Parse
|
|
613
600
|
end
|
614
601
|
val
|
615
602
|
end
|
616
|
-
|
617
603
|
end # Properties
|
618
|
-
|
619
604
|
end # Parse
|