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,333 +1,330 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require_relative
|
4
|
+
require_relative "../../query"
|
5
5
|
|
6
6
|
module Parse
|
7
7
|
module Core
|
8
8
|
# Defines the querying methods applied to a Parse::Object.
|
9
9
|
module Querying
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
name = name.to_sym
|
70
|
-
if respond_to?(name, true)
|
71
|
-
puts "Creating scope :#{name}. Will overwrite existing method #{self}.#{name}."
|
72
|
-
end
|
11
|
+
# This feature is a small subset of the
|
12
|
+
# {http://guides.rubyonrails.org/active_record_querying.html#scopes
|
13
|
+
# ActiveRecord named scopes} feature. Scoping allows you to specify
|
14
|
+
# commonly-used queries which can be referenced as class method calls and
|
15
|
+
# are chainable with other scopes. You can use every {Parse::Query}
|
16
|
+
# method previously covered such as `where`, `includes` and `limit`.
|
17
|
+
#
|
18
|
+
# class Article < Parse::Object
|
19
|
+
# property :published, :boolean
|
20
|
+
# scope :published, -> { query(published: true) }
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# This is the same as defining your own class method for the query.
|
24
|
+
#
|
25
|
+
# class Article < Parse::Object
|
26
|
+
# def self.published
|
27
|
+
# query(published: true)
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# You can also chain scopes and pass parameters. In addition, boolean and
|
32
|
+
# enumerated properties have automatically generated scopes for you to use.
|
33
|
+
#
|
34
|
+
# class Article < Parse::Object
|
35
|
+
# scope :published, -> { query(published: true) }
|
36
|
+
#
|
37
|
+
# property :comment_count, :integer
|
38
|
+
# property :category
|
39
|
+
# property :approved, :boolean
|
40
|
+
#
|
41
|
+
# scope :published_and_commented, -> { published.where :comment_count.gt => 0 }
|
42
|
+
# scope :popular_topics, ->(name) { published_and_commented.where category: name }
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # simple scope
|
46
|
+
# Article.published # => where published is true
|
47
|
+
#
|
48
|
+
# # chained scope
|
49
|
+
# Article.published_and_commented # published is true and comment_count > 0
|
50
|
+
#
|
51
|
+
# # scope with parameters
|
52
|
+
# Article.popular_topic("music") # => popular music articles
|
53
|
+
# # equivalent: where(published: true, :comment_count.gt => 0, category: name)
|
54
|
+
#
|
55
|
+
# # automatically generated scope
|
56
|
+
# Article.approved(category: "tour") # => where approved: true, category: 'tour'
|
57
|
+
#
|
58
|
+
# If you would like to turn off automatic scope generation for property types,
|
59
|
+
# set the option `:scope` to false when declaring the property.
|
60
|
+
# @param name [Symbol] the name of the scope.
|
61
|
+
# @param body [Proc] the proc related to the scope.
|
62
|
+
# @raise ArgumentError if body parameter does not respond to `call`
|
63
|
+
# @return [Symbol] the name of the singleton method created.
|
64
|
+
def scope(name, body)
|
65
|
+
unless body.respond_to?(:call)
|
66
|
+
raise ArgumentError, "The scope body needs to be callable."
|
67
|
+
end
|
73
68
|
|
74
|
-
|
69
|
+
name = name.to_sym
|
70
|
+
if respond_to?(name, true)
|
71
|
+
puts "Creating scope :#{name}. Will overwrite existing method #{self}.#{name}."
|
72
|
+
end
|
75
73
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
74
|
+
define_singleton_method(name) do |*args, &block|
|
75
|
+
if body.arity.zero?
|
76
|
+
res = body.call
|
77
|
+
res.conditions(*args) if args.present?
|
78
|
+
else
|
79
|
+
res = body.call(*args)
|
80
|
+
end
|
82
81
|
|
83
|
-
|
82
|
+
_q = res || query
|
84
83
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
klass = nil # help clean up ruby gc
|
98
|
-
return klass_scope
|
99
|
-
end
|
84
|
+
if _q.is_a?(Parse::Query)
|
85
|
+
klass = self
|
86
|
+
_q.define_singleton_method(:method_missing) do |m, *args, &chained_block|
|
87
|
+
if klass.respond_to?(m, true)
|
88
|
+
# must be a scope
|
89
|
+
klass_scope = klass.send(m, *args)
|
90
|
+
if klass_scope.is_a?(Parse::Query)
|
91
|
+
# merge constraints
|
92
|
+
add_constraints(klass_scope.constraints)
|
93
|
+
# if a block was passed, execute the query, otherwise return the query
|
94
|
+
return chained_block.present? ? results(&chained_block) : self
|
95
|
+
end # if
|
100
96
|
klass = nil # help clean up ruby gc
|
101
|
-
return
|
97
|
+
return klass_scope
|
102
98
|
end
|
99
|
+
klass = nil # help clean up ruby gc
|
100
|
+
return results.send(m, *args, &chained_block)
|
103
101
|
end
|
104
|
-
|
105
|
-
Parse::Query.apply_auto_introspection!(_q)
|
106
|
-
|
107
|
-
return _q if block.nil?
|
108
|
-
_q.results(&block)
|
109
102
|
end
|
110
103
|
|
111
|
-
|
104
|
+
Parse::Query.apply_auto_introspection!(_q)
|
112
105
|
|
113
|
-
|
114
|
-
|
115
|
-
# @example
|
116
|
-
# # assume Post < Parse::Object
|
117
|
-
# query = Post.query(:updated_at.before => DateTime.now)
|
118
|
-
# @return [Parse::Query] a new query with the given constraints for this
|
119
|
-
# Parse::Object subclass.
|
120
|
-
def query(constraints = {})
|
121
|
-
Parse::Query.new self.parse_class, constraints
|
122
|
-
end; alias_method :where, :query
|
123
|
-
|
124
|
-
# @param conditions (see Parse::Query#where)
|
125
|
-
# @return (see Parse::Query#where)
|
126
|
-
# @see Parse::Query#where
|
127
|
-
def literal_where(conditions = {})
|
128
|
-
query.where(conditions)
|
106
|
+
return _q if block.nil?
|
107
|
+
_q.results(&block)
|
129
108
|
end
|
109
|
+
end
|
130
110
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
#
|
142
|
-
# post = Post.first
|
143
|
-
# # iterate over all comments matching conditions
|
144
|
-
# Comment.each(post: post) do |comment|
|
145
|
-
# # ...
|
146
|
-
# end
|
147
|
-
# @return [Parse::Object] the last Parse::Object record processed.
|
148
|
-
# @note You cannot use *:created_at* as a constraint.
|
149
|
-
# @raise ArgumentError if :created_at is detected in the constraints argument.
|
150
|
-
# @see Parse::Core::Querying.all
|
151
|
-
# @see Parse::Core::Actions.save_all
|
152
|
-
def each(constraints = {}, &block)
|
153
|
-
# verify we don't hvae created at as a constraint, otherwise this will not work
|
154
|
-
invalid_constraints = constraints.keys.any? do |k|
|
155
|
-
(k == :created_at || k == :createdAt) ||
|
156
|
-
( k.is_a?(Parse::Operation) && (k.operand == :created_at || k.operand == :createdAt) )
|
157
|
-
end
|
158
|
-
if invalid_constraints
|
159
|
-
raise ArgumentError, "[#{self.class}.each] Special method each()" \
|
160
|
-
"cannot be used with a :created_at constraint."
|
161
|
-
end
|
162
|
-
batch_size = 250
|
163
|
-
start_cursor = first( order: :created_at.asc, keys: :created_at )
|
164
|
-
constraints.merge! cache: false, limit: batch_size, order: :created_at.asc
|
165
|
-
all_query = query(constraints)
|
166
|
-
cursor = start_cursor
|
167
|
-
# the exclusion set is a set of ids not to include the next query.
|
168
|
-
exclusion_set = []
|
169
|
-
loop do
|
170
|
-
_q = query(constraints.dup)
|
171
|
-
_q.where(:created_at.on_or_after => cursor.created_at)
|
172
|
-
# set of ids not to include in the next query. non-performant, but accurate.
|
173
|
-
_q.where(:id.nin => exclusion_set) unless exclusion_set.empty?
|
174
|
-
results = _q.results # get results
|
111
|
+
# Creates a new {Parse::Query} with the given constraints for this class.
|
112
|
+
# @example
|
113
|
+
# # assume Post < Parse::Object
|
114
|
+
# query = Post.query(:updated_at.before => DateTime.now)
|
115
|
+
# @return [Parse::Query] a new query with the given constraints for this
|
116
|
+
# Parse::Object subclass.
|
117
|
+
def query(constraints = {})
|
118
|
+
Parse::Query.new self.parse_class, constraints
|
119
|
+
end;
|
120
|
+
alias_method :where, :query
|
175
121
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
break next_cursor if cursor.id == next_cursor.id
|
183
|
-
# The exclusion set is used in the case where multiple records have the exact
|
184
|
-
# same created_at date (down to the microsecond). This prevents getting the same
|
185
|
-
# record in the next query request.
|
186
|
-
exclusion_set = results.select { |r| r.created_at == next_cursor.created_at }.map(&:id)
|
187
|
-
results = nil
|
188
|
-
cursor = next_cursor
|
189
|
-
end
|
122
|
+
# @param conditions (see Parse::Query#where)
|
123
|
+
# @return (see Parse::Query#where)
|
124
|
+
# @see Parse::Query#where
|
125
|
+
def literal_where(conditions = {})
|
126
|
+
query.where(conditions)
|
127
|
+
end
|
190
128
|
|
129
|
+
# This methods allow you to efficiently iterate over all the records in the collection
|
130
|
+
# (lower memory cost) at a minor cost of performance. This method utilizes
|
131
|
+
# the `created_at` field of Parse records to order and iterate over *all* matching records,
|
132
|
+
# therefore you should not use this method if you want to perform a query
|
133
|
+
# with constraints against the `created_at` field or need specific type of ordering.
|
134
|
+
# If you need to use `:created_at` in your constraints, consider using {Parse::Core::Querying#all} or
|
135
|
+
# {Parse::Core::Actions::ClassMethods#save_all}
|
136
|
+
# @param constraints [Hash] a set of query constraints.
|
137
|
+
# @yield a block which will iterate through each matching record.
|
138
|
+
# @example
|
139
|
+
#
|
140
|
+
# post = Post.first
|
141
|
+
# # iterate over all comments matching conditions
|
142
|
+
# Comment.each(post: post) do |comment|
|
143
|
+
# # ...
|
144
|
+
# end
|
145
|
+
# @return [Parse::Object] the last Parse::Object record processed.
|
146
|
+
# @note You cannot use *:created_at* as a constraint.
|
147
|
+
# @raise ArgumentError if :created_at is detected in the constraints argument.
|
148
|
+
# @see Parse::Core::Querying.all
|
149
|
+
# @see Parse::Core::Actions.save_all
|
150
|
+
def each(constraints = {}, &block)
|
151
|
+
# verify we don't hvae created at as a constraint, otherwise this will not work
|
152
|
+
invalid_constraints = constraints.keys.any? do |k|
|
153
|
+
(k == :created_at || k == :createdAt) ||
|
154
|
+
(k.is_a?(Parse::Operation) && (k.operand == :created_at || k.operand == :createdAt))
|
191
155
|
end
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
# When no block is passed, all objects are returned. Using a block is more memory
|
196
|
-
# efficient as matching objects are fetched in batches and discarded after the iteration
|
197
|
-
# is completed.
|
198
|
-
# @param constraints [Hash] a set of {Parse::Query} constraints.
|
199
|
-
# @yield a block to iterate with each matching object.
|
200
|
-
# @example
|
201
|
-
#
|
202
|
-
# songs = Song.all( ... expressions ...) # => array of Parse::Objects
|
203
|
-
# # memory efficient for large amounts of records.
|
204
|
-
# Song.all( ... expressions ...) do |song|
|
205
|
-
# # ... do something with song..
|
206
|
-
# end
|
207
|
-
#
|
208
|
-
# @note This method will continually query for records by automatically
|
209
|
-
# incrementing the *:skip* parameter until no more results are returned
|
210
|
-
# by the server.
|
211
|
-
# @return [Array<Parse::Object>] an array of matching objects. If a block is passed,
|
212
|
-
# an empty array is returned.
|
213
|
-
def all(constraints = {limit: :max})
|
214
|
-
constraints = constraints.reverse_merge({limit: :max})
|
215
|
-
prepared_query = query(constraints)
|
216
|
-
return prepared_query.results(&Proc.new) if block_given?
|
217
|
-
prepared_query.results
|
156
|
+
if invalid_constraints
|
157
|
+
raise ArgumentError, "[#{self.class}.each] Special method each()" \
|
158
|
+
"cannot be used with a :created_at constraint."
|
218
159
|
end
|
160
|
+
batch_size = 250
|
161
|
+
start_cursor = first(order: :created_at.asc, keys: :created_at)
|
162
|
+
constraints.merge! cache: false, limit: batch_size, order: :created_at.asc
|
163
|
+
all_query = query(constraints)
|
164
|
+
cursor = start_cursor
|
165
|
+
# the exclusion set is a set of ids not to include the next query.
|
166
|
+
exclusion_set = []
|
167
|
+
loop do
|
168
|
+
_q = query(constraints.dup)
|
169
|
+
_q.where(:created_at.on_or_after => cursor.created_at)
|
170
|
+
# set of ids not to include in the next query. non-performant, but accurate.
|
171
|
+
_q.where(:id.nin => exclusion_set) unless exclusion_set.empty?
|
172
|
+
results = _q.results # get results
|
219
173
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
fetch_count = 1
|
234
|
-
if constraints.is_a?(Numeric)
|
235
|
-
fetch_count = constraints.to_i
|
236
|
-
constraints = {}
|
237
|
-
end
|
238
|
-
constraints.merge!( {limit: fetch_count} )
|
239
|
-
res = query(constraints).results
|
240
|
-
return res.first if fetch_count == 1
|
241
|
-
return res.first fetch_count
|
174
|
+
break cursor if results.empty? # break if no results
|
175
|
+
results.each(&block)
|
176
|
+
next_cursor = results.last
|
177
|
+
# break if we got less than the maximum requested
|
178
|
+
break next_cursor if results.count < batch_size
|
179
|
+
# break if the next object is the same as the current object.
|
180
|
+
break next_cursor if cursor.id == next_cursor.id
|
181
|
+
# The exclusion set is used in the case where multiple records have the exact
|
182
|
+
# same created_at date (down to the microsecond). This prevents getting the same
|
183
|
+
# record in the next query request.
|
184
|
+
exclusion_set = results.select { |r| r.created_at == next_cursor.created_at }.map(&:id)
|
185
|
+
results = nil
|
186
|
+
cursor = next_cursor
|
242
187
|
end
|
188
|
+
end
|
243
189
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
190
|
+
# Fetch all matching objects in this collection matching the constraints.
|
191
|
+
# This will be the most common way when querying Parse objects for a subclass.
|
192
|
+
# When no block is passed, all objects are returned. Using a block is more memory
|
193
|
+
# efficient as matching objects are fetched in batches and discarded after the iteration
|
194
|
+
# is completed.
|
195
|
+
# @param constraints [Hash] a set of {Parse::Query} constraints.
|
196
|
+
# @yield a block to iterate with each matching object.
|
197
|
+
# @example
|
198
|
+
#
|
199
|
+
# songs = Song.all( ... expressions ...) # => array of Parse::Objects
|
200
|
+
# # memory efficient for large amounts of records.
|
201
|
+
# Song.all( ... expressions ...) do |song|
|
202
|
+
# # ... do something with song..
|
203
|
+
# end
|
204
|
+
#
|
205
|
+
# @note This method will continually query for records by automatically
|
206
|
+
# incrementing the *:skip* parameter until no more results are returned
|
207
|
+
# by the server.
|
208
|
+
# @return [Array<Parse::Object>] an array of matching objects. If a block is passed,
|
209
|
+
# an empty array is returned.
|
210
|
+
def all(constraints = { limit: :max })
|
211
|
+
constraints = constraints.reverse_merge({ limit: :max })
|
212
|
+
prepared_query = query(constraints)
|
213
|
+
return prepared_query.results(&Proc.new) if block_given?
|
214
|
+
prepared_query.results
|
215
|
+
end
|
254
216
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
217
|
+
# Returns the first item matching the constraint.
|
218
|
+
# @overload first(count = 1)
|
219
|
+
# @param count [Interger] The number of items to return.
|
220
|
+
# @example
|
221
|
+
# Object.first(2) # => an array of the first 2 objects in the collection.
|
222
|
+
# @return [Parse::Object] if count == 1
|
223
|
+
# @return [Array<Parse::Object>] if count > 1
|
224
|
+
# @overload first(constraints = {})
|
225
|
+
# @param constraints [Hash] a set of {Parse::Query} constraints.
|
226
|
+
# @example
|
227
|
+
# Object.first( :name => "Anthony" )
|
228
|
+
# @return [Parse::Object] the first matching object.
|
229
|
+
def first(constraints = {})
|
230
|
+
fetch_count = 1
|
231
|
+
if constraints.is_a?(Numeric)
|
232
|
+
fetch_count = constraints.to_i
|
233
|
+
constraints = {}
|
266
234
|
end
|
235
|
+
constraints.merge!({ limit: fetch_count })
|
236
|
+
res = query(constraints).results
|
237
|
+
return res.first if fetch_count == 1
|
238
|
+
return res.first fetch_count
|
239
|
+
end
|
267
240
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
241
|
+
# Creates a count request which is more performant when counting objects.
|
242
|
+
# @example
|
243
|
+
# # number of songs with a like count greater than 20.
|
244
|
+
# count = Song.count( :like_count.gt => 20 )
|
245
|
+
# @param constraints (see #all)
|
246
|
+
# @return [Interger] the number of records matching the query.
|
247
|
+
# @see Parse::Query#count
|
248
|
+
def count(constraints = {})
|
249
|
+
query(constraints).count
|
250
|
+
end
|
277
251
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
252
|
+
# Finds the distinct values for a specified field across a single
|
253
|
+
# collection or view and returns the results in an array.
|
254
|
+
# @example
|
255
|
+
# # get a list of unique city names for users who are older than 21.
|
256
|
+
# cities = User.distinct(:city, :age.gt => 21 )
|
257
|
+
# @param field The name of the field to use for unique aggregation.
|
258
|
+
# @param constraints (see #all)
|
259
|
+
# @return [Array] a list of distinct values
|
260
|
+
# @see Parse::Query#distinct
|
261
|
+
def distinct(field, constraints = {})
|
262
|
+
query(constraints).distinct(field)
|
263
|
+
end
|
287
264
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
# - *:batch* : This uses a batch fetch request using a contained_in clause.
|
298
|
-
# @param compact [Boolean] whether to remove nil items from the returned array for objects
|
299
|
-
# that were not found.
|
300
|
-
# @return [Parse::Object] if only one id was provided as a parameter.
|
301
|
-
# @return [Array<Parse::Object>] if more than one id was provided as a parameter.
|
302
|
-
def find(*parse_ids, type: :parallel, compact: true)
|
303
|
-
# flatten the list of Object ids.
|
304
|
-
parse_ids.flatten!
|
305
|
-
parse_ids.compact!
|
306
|
-
# determines if the result back to the call site is an array or a single result
|
307
|
-
as_array = parse_ids.count > 1
|
308
|
-
results = []
|
265
|
+
# Find objects matching the constraint ordered by the descending created_at date.
|
266
|
+
# @param constraints (see #all)
|
267
|
+
# @return [Array<Parse::Object>]
|
268
|
+
def newest(constraints = {})
|
269
|
+
constraints.merge!(order: :created_at.desc)
|
270
|
+
_q = query(constraints)
|
271
|
+
_q.define_singleton_method(:method_missing) { |m, *args, &block| self.results.send(m, *args, &block) }
|
272
|
+
_q
|
273
|
+
end
|
309
274
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
next nil unless parse_id.present?
|
320
|
-
response = client.fetch_object(parse_class, parse_id)
|
321
|
-
next nil if response.error?
|
322
|
-
Parse::Object.build response.result, parse_class
|
323
|
-
end
|
324
|
-
end
|
325
|
-
# removes any nil items in the array
|
326
|
-
results.compact! if compact
|
275
|
+
# Find objects matching the constraint ordered by the ascending created_at date.
|
276
|
+
# @param constraints (see #all)
|
277
|
+
# @return [Array<Parse::Object>]
|
278
|
+
def oldest(constraints = {})
|
279
|
+
constraints.merge!(order: :created_at.asc)
|
280
|
+
_q = query(constraints)
|
281
|
+
_q.define_singleton_method(:method_missing) { |m, *args, &block| self.results.send(m, *args, &block) }
|
282
|
+
_q
|
283
|
+
end
|
327
284
|
|
328
|
-
|
329
|
-
|
285
|
+
# Find objects for a given objectId in this collection.The result is a list
|
286
|
+
# (or single item) of the objects that were successfully found.
|
287
|
+
# @example
|
288
|
+
# Object.find "<objectId>"
|
289
|
+
# Object.find "<objectId>", "<objectId>"....
|
290
|
+
# Object.find ["<objectId>", "<objectId>"]
|
291
|
+
# @param parse_ids [String] the objectId to find.
|
292
|
+
# @param type [Symbol] the fetching methodology to use if more than one id was passed.
|
293
|
+
# - *:parallel* : Utilizes parrallel HTTP requests to fetch all objects requested.
|
294
|
+
# - *:batch* : This uses a batch fetch request using a contained_in clause.
|
295
|
+
# @param compact [Boolean] whether to remove nil items from the returned array for objects
|
296
|
+
# that were not found.
|
297
|
+
# @return [Parse::Object] if only one id was provided as a parameter.
|
298
|
+
# @return [Array<Parse::Object>] if more than one id was provided as a parameter.
|
299
|
+
def find(*parse_ids, type: :parallel, compact: true)
|
300
|
+
# flatten the list of Object ids.
|
301
|
+
parse_ids.flatten!
|
302
|
+
parse_ids.compact!
|
303
|
+
# determines if the result back to the call site is an array or a single result
|
304
|
+
as_array = parse_ids.count > 1
|
305
|
+
results = []
|
306
|
+
|
307
|
+
if type == :batch
|
308
|
+
# use a .in query with the given id as a list
|
309
|
+
results = self.class.all(:id.in => parse_ids)
|
310
|
+
else
|
311
|
+
# use Parallel to make multiple threaded requests for finding these objects.
|
312
|
+
# The benefit of using this as default is that each request goes to a specific URL
|
313
|
+
# which is better than Query request (table scan). This in turn allows for caching of
|
314
|
+
# individual objects.
|
315
|
+
results = parse_ids.threaded_map do |parse_id|
|
316
|
+
next nil unless parse_id.present?
|
317
|
+
response = client.fetch_object(parse_class, parse_id)
|
318
|
+
next nil if response.error?
|
319
|
+
Parse::Object.build response.result, parse_class
|
320
|
+
end
|
321
|
+
end
|
322
|
+
# removes any nil items in the array
|
323
|
+
results.compact! if compact
|
330
324
|
|
325
|
+
as_array ? results : results.first
|
326
|
+
end;
|
327
|
+
alias_method :get, :find
|
331
328
|
end # Querying
|
332
329
|
end
|
333
330
|
end
|