parse-stack 1.8.0 → 1.8.1
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/.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
|