parse-stack 1.3.1 → 1.3.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -1
- data/Changes.md +25 -1
- data/Gemfile +10 -0
- data/Gemfile.lock +10 -9
- data/README.md +593 -254
- data/Rakefile +1 -0
- data/bin/console +5 -0
- data/lib/parse-stack.rb +2 -0
- data/lib/parse/api/batch.rb +2 -1
- data/lib/parse/api/files.rb +2 -0
- data/lib/parse/api/objects.rb +2 -0
- data/lib/parse/client.rb +31 -2
- data/lib/parse/client/authentication.rb +10 -0
- data/lib/parse/client/body_builder.rb +3 -0
- data/lib/parse/client/request.rb +1 -1
- data/lib/parse/client/response.rb +1 -0
- data/lib/parse/model/associations/pointer_collection_proxy.rb +2 -2
- data/lib/parse/model/associations/relation_collection_proxy.rb +1 -0
- data/lib/parse/model/core/actions.rb +8 -8
- data/lib/parse/model/core/properties.rb +9 -0
- data/lib/parse/model/core/schema.rb +9 -0
- data/lib/parse/model/date.rb +4 -0
- data/lib/parse/model/file.rb +17 -2
- data/lib/parse/model/geopoint.rb +39 -2
- data/lib/parse/model/object.rb +2 -1
- data/lib/parse/model/pointer.rb +3 -0
- data/lib/parse/model/push.rb +2 -2
- data/lib/parse/query.rb +33 -17
- data/lib/parse/query/constraint.rb +2 -2
- data/lib/parse/query/constraints.rb +62 -6
- data/lib/parse/query/operation.rb +1 -0
- data/lib/parse/stack.rb +1 -0
- data/lib/parse/stack/tasks.rb +107 -0
- data/lib/parse/stack/version.rb +1 -1
- data/lib/parse/webhooks.rb +2 -2
- data/lib/parse/webhooks/payload.rb +2 -0
- data/lib/parse/webhooks/registration.rb +15 -10
- data/parse-stack.gemspec +8 -15
- metadata +20 -118
data/lib/parse/model/pointer.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'active_model'
|
2
|
+
require 'active_support'
|
2
3
|
require 'active_support/inflector'
|
4
|
+
require 'active_support/core_ext'
|
3
5
|
require 'active_model_serializers'
|
4
6
|
require_relative 'model'
|
7
|
+
require 'active_model_serializers'
|
5
8
|
module Parse
|
6
9
|
|
7
10
|
# A Parse Pointer is the superclass of Parse::Object types. A pointer can be considered
|
data/lib/parse/model/push.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative '../query.rb'
|
2
2
|
require_relative '../client.rb'
|
3
|
-
|
3
|
+
require 'active_model_serializers'
|
4
4
|
module Parse
|
5
5
|
|
6
6
|
class Push
|
@@ -10,7 +10,7 @@ module Parse
|
|
10
10
|
|
11
11
|
alias_method :message, :alert
|
12
12
|
alias_method :message=, :alert=
|
13
|
-
|
13
|
+
|
14
14
|
def self.send(payload)
|
15
15
|
client.push payload.as_json
|
16
16
|
end
|
data/lib/parse/query.rb
CHANGED
@@ -2,7 +2,10 @@ require_relative "client"
|
|
2
2
|
require_relative "query/operation"
|
3
3
|
require_relative "query/constraints"
|
4
4
|
require_relative "query/ordering"
|
5
|
-
|
5
|
+
require 'active_model_serializers'
|
6
|
+
require 'active_support'
|
7
|
+
require 'active_support/inflector'
|
8
|
+
require 'active_support/core_ext'
|
6
9
|
|
7
10
|
module Parse
|
8
11
|
# This is the main engine behind making Parse queries on tables. It takes
|
@@ -23,7 +26,7 @@ module Parse
|
|
23
26
|
# You can modify the default client being used by all Parse::Query objects by setting
|
24
27
|
# Parse::Query.client. You can override individual Parse::Query object clients
|
25
28
|
# by changing their client variable to a different Parse::Client object.
|
26
|
-
attr_accessor :table, :client, :key, :cache, :use_master_key
|
29
|
+
attr_accessor :table, :client, :key, :cache, :use_master_key, :session_token
|
27
30
|
|
28
31
|
# We have a special class method to handle field formatting. This turns
|
29
32
|
# the symbol keys in an operand from one key to another. For example, we can
|
@@ -34,23 +37,17 @@ module Parse
|
|
34
37
|
# in lower case). You can specify a different method to call by setting the Parse::Query.field_formatter
|
35
38
|
# variable with the symbol name of the method to call on the object. You can set this to nil
|
36
39
|
# if you do not want any field formatting to be performed.
|
40
|
+
@field_formatter = :columnize
|
37
41
|
class << self
|
38
42
|
#field formatter getters and setters.
|
39
43
|
attr_accessor :field_formatter
|
40
44
|
|
41
|
-
def field_formatter
|
42
|
-
#default
|
43
|
-
@field_formatter ||= :columnize
|
44
|
-
end
|
45
|
-
|
46
45
|
def format_field(str)
|
47
|
-
res = str.to_s
|
48
|
-
if field_formatter.present?
|
49
|
-
|
50
|
-
# don't format if object d
|
51
|
-
res = res.send(formatter) if res.respond_to?(formatter)
|
46
|
+
res = str.to_s.strip
|
47
|
+
if field_formatter.present? && res.respond_to?(field_formatter)
|
48
|
+
res = res.send(field_formatter)
|
52
49
|
end
|
53
|
-
res
|
50
|
+
res
|
54
51
|
end
|
55
52
|
|
56
53
|
# Simple way to create a query.
|
@@ -78,7 +75,7 @@ module Parse
|
|
78
75
|
when :skip
|
79
76
|
@skip = 0
|
80
77
|
when :limit
|
81
|
-
@limit =
|
78
|
+
@limit = nil
|
82
79
|
when :count
|
83
80
|
@count = 0
|
84
81
|
when :keys
|
@@ -96,7 +93,7 @@ module Parse
|
|
96
93
|
@order = []
|
97
94
|
@keys = []
|
98
95
|
@includes = []
|
99
|
-
@limit =
|
96
|
+
@limit = nil
|
100
97
|
@skip = 0
|
101
98
|
@table = table
|
102
99
|
@cache = true
|
@@ -123,6 +120,10 @@ module Parse
|
|
123
120
|
self.cache = value
|
124
121
|
elsif expression == :use_master_key
|
125
122
|
self.cache = value
|
123
|
+
elsif expression == :session
|
124
|
+
# you can pass a session token or a Parse::Session
|
125
|
+
value = value.is_a?(Parse::Session) ? value.session_token : value
|
126
|
+
self.session_token = value
|
126
127
|
else
|
127
128
|
add_constraint(expression, value)
|
128
129
|
end
|
@@ -176,6 +177,8 @@ module Parse
|
|
176
177
|
@limit = 11_000
|
177
178
|
elsif count.is_a?(Numeric)
|
178
179
|
@limit = [ 0, count.to_i, 11_000].sort[1]
|
180
|
+
else
|
181
|
+
@limit = nil
|
179
182
|
end
|
180
183
|
|
181
184
|
@results = nil
|
@@ -314,6 +317,12 @@ module Parse
|
|
314
317
|
opts = {}
|
315
318
|
opts[:cache] = false unless self.cache
|
316
319
|
opts[:use_mster_key] = self.use_master_key
|
320
|
+
opts[:session_token] = self.session_token
|
321
|
+
# for now, don't cache requests where we disable master_key or provide session token
|
322
|
+
if opts[:use_mster_key] == false || opts[:session_token].present?
|
323
|
+
opts[:cache] = false
|
324
|
+
end
|
325
|
+
|
317
326
|
response = client.find_objects(@table, compiled_query.as_json, opts )
|
318
327
|
if response.error?
|
319
328
|
puts "[ParseQuery] #{response.error}"
|
@@ -323,7 +332,7 @@ module Parse
|
|
323
332
|
|
324
333
|
def results(raw: false)
|
325
334
|
if @results.nil?
|
326
|
-
if @limit <= 1_000
|
335
|
+
if @limit.nil? || @limit.to_i <= 1_000
|
327
336
|
response = fetch!( compile )
|
328
337
|
return [] if response.error?
|
329
338
|
items = raw ? response.results : decode(response.results)
|
@@ -347,7 +356,11 @@ module Parse
|
|
347
356
|
compile.as_json
|
348
357
|
end
|
349
358
|
|
350
|
-
def
|
359
|
+
def prepared(includeClassName: false)
|
360
|
+
compile(encode: false, includeClassName: includeClassName)
|
361
|
+
end
|
362
|
+
|
363
|
+
def compile(encode: true, includeClassName: false)
|
351
364
|
q = {} #query
|
352
365
|
q[:limit] = 11_000 if @limit == :max || @limit == :all
|
353
366
|
q[:limit] = @limit if @limit.is_a?(Numeric) && @limit > 0
|
@@ -366,6 +379,9 @@ module Parse
|
|
366
379
|
q[:limit] = 0
|
367
380
|
q[:count] = 1
|
368
381
|
end
|
382
|
+
if includeClassName
|
383
|
+
q[:className] = @table
|
384
|
+
end
|
369
385
|
q
|
370
386
|
end
|
371
387
|
|
@@ -123,8 +123,8 @@ module Parse
|
|
123
123
|
#d = d.pointer if d.is_a?(Parse::Object) #simplified query object
|
124
124
|
# d = d.compile
|
125
125
|
if d.is_a?(Parse::Query)
|
126
|
-
compiled = d.compile(false)
|
127
|
-
compiled["className"] = d.table
|
126
|
+
compiled = d.compile(encode: false, includeClassName: true)
|
127
|
+
# compiled["className"] = d.table
|
128
128
|
d = compiled
|
129
129
|
end
|
130
130
|
d
|
@@ -24,29 +24,34 @@ module Parse
|
|
24
24
|
class LessOrEqualConstraint < Constraint
|
25
25
|
contraint_keyword :$lte
|
26
26
|
register :lte
|
27
|
+
register :less_than_or_equal
|
27
28
|
register :on_or_before
|
28
29
|
end
|
29
30
|
|
30
31
|
class LessThanConstraint < Constraint
|
31
32
|
contraint_keyword :$lt
|
32
33
|
register :lt
|
34
|
+
register :less_than
|
33
35
|
register :before
|
34
36
|
end
|
35
37
|
|
36
38
|
class GreaterThanConstraint < Constraint
|
37
39
|
contraint_keyword :$gt
|
38
40
|
register :gt
|
41
|
+
register :greater_than
|
39
42
|
register :after
|
40
43
|
end
|
41
44
|
|
42
45
|
class GreaterOrEqualConstraint < Constraint
|
43
46
|
contraint_keyword :$gte
|
44
47
|
register :gte
|
48
|
+
register :greater_than_or_equal
|
45
49
|
register :on_or_after
|
46
50
|
end
|
47
51
|
|
48
52
|
class NotEqualConstraint < Constraint
|
49
53
|
contraint_keyword :$ne
|
54
|
+
register :ne
|
50
55
|
register :not
|
51
56
|
end
|
52
57
|
|
@@ -98,6 +103,7 @@ module Parse
|
|
98
103
|
|
99
104
|
class NotContainedInConstraint < Constraint
|
100
105
|
contraint_keyword :$nin
|
106
|
+
register :nin
|
101
107
|
register :not_in
|
102
108
|
register :not_contained_in
|
103
109
|
end
|
@@ -115,20 +121,53 @@ module Parse
|
|
115
121
|
register :select
|
116
122
|
|
117
123
|
def build
|
118
|
-
|
119
|
-
|
120
|
-
|
124
|
+
|
125
|
+
# if it's a hash, then it should be {:key=>"objectId", :query=>[]}
|
126
|
+
remote_field_name = @operation.operand
|
127
|
+
query = nil
|
128
|
+
if @value.is_a?(Hash)
|
129
|
+
res = @value.symbolize_keys
|
130
|
+
remote_field_name = res[:key] || remote_field_name
|
131
|
+
query = res[:query]
|
132
|
+
unless query.is_a?(Parse::Query)
|
133
|
+
raise "Invalid Parse::Query object provided in :query field of value: #{@operation.operand}.#{$dontSelect} => #{@value}"
|
134
|
+
end
|
135
|
+
query = query.compile(encode: false, includeClassName: true)
|
136
|
+
elsif @value.is_a?(Parse::Query)
|
137
|
+
# if its a query, then assume dontSelect key is the same name as operand.
|
138
|
+
query = @value.compile(encode: false, includeClassName: true)
|
139
|
+
else
|
140
|
+
raise "Invalid `:select` query constraint. It should follow the format: :field.select => { key: 'key', query: '<Parse::Query>' }"
|
141
|
+
end
|
142
|
+
{ @operation.operand => { :$select => { key: remote_field_name, query: query } } }
|
121
143
|
end
|
122
144
|
end
|
123
145
|
|
124
146
|
class RejectionConstraint < Constraint
|
125
147
|
#requires that a key's value not match a value for a key in the result of a different query
|
126
148
|
contraint_keyword :$dontSelect
|
149
|
+
register :dont_select
|
127
150
|
register :reject
|
128
151
|
def build
|
129
|
-
|
130
|
-
|
131
|
-
|
152
|
+
|
153
|
+
# if it's a hash, then it should be {:key=>"objectId", :query=>[]}
|
154
|
+
remote_field_name = @operation.operand
|
155
|
+
query = nil
|
156
|
+
if @value.is_a?(Hash)
|
157
|
+
res = @value.symbolize_keys
|
158
|
+
remote_field_name = res[:key] || remote_field_name
|
159
|
+
query = res[:query]
|
160
|
+
unless query.is_a?(Parse::Query)
|
161
|
+
raise "Invalid Parse::Query object provided in :query field of value: #{@operation.operand}.#{$dontSelect} => #{@value}"
|
162
|
+
end
|
163
|
+
query = query.compile(encode: false, includeClassName: true)
|
164
|
+
elsif @value.is_a?(Parse::Query)
|
165
|
+
# if its a query, then assume dontSelect key is the same name as operand.
|
166
|
+
query = @value.compile(encode: false, includeClassName: true)
|
167
|
+
else
|
168
|
+
raise "Invalid `:reject` query constraint. It should follow the format: :field.reject => { key: 'key', query: '<Parse::Query>' }"
|
169
|
+
end
|
170
|
+
{ @operation.operand => { :$dontSelect => { key: remote_field_name, query: query } } }
|
132
171
|
end
|
133
172
|
end
|
134
173
|
|
@@ -186,4 +225,21 @@ module Parse
|
|
186
225
|
|
187
226
|
end
|
188
227
|
|
228
|
+
class WithinGeoBoxQueryConstraint < Constraint
|
229
|
+
contraint_keyword :$within
|
230
|
+
register :within_box
|
231
|
+
|
232
|
+
def build
|
233
|
+
geopoint_values = formatted_value
|
234
|
+
unless geopoint_values.is_a?(Array) && geopoint_values.count == 2 &&
|
235
|
+
geopoint_values.first.is_a?(Parse::GeoPoint) && geopoint_values.last.is_a?(Parse::GeoPoint)
|
236
|
+
raise( '[Parse::Query] Invalid query value parameter passed to `within_box` constraint. ' +
|
237
|
+
'Values in array must be `Parse::GeoPoint` objects and ' +
|
238
|
+
'it should be in an array format: [southwestPoint, northeastPoint]' )
|
239
|
+
end
|
240
|
+
{ @operation.operand => { :$within => { :$box => geopoint_values } } }
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
|
189
245
|
end
|
data/lib/parse/stack.rb
CHANGED
@@ -0,0 +1,107 @@
|
|
1
|
+
require_relative '../stack.rb'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require 'active_support/core_ext'
|
5
|
+
require 'rake'
|
6
|
+
require 'rake/dsl_definition'
|
7
|
+
|
8
|
+
module Parse
|
9
|
+
|
10
|
+
module Stack
|
11
|
+
|
12
|
+
def self.load_tasks
|
13
|
+
Parse::Stack::Tasks.new.install_tasks
|
14
|
+
end
|
15
|
+
|
16
|
+
class Tasks
|
17
|
+
include Rake::DSL if defined? Rake::DSL
|
18
|
+
|
19
|
+
def install_tasks
|
20
|
+
|
21
|
+
namespace :parse do
|
22
|
+
|
23
|
+
task :env do
|
24
|
+
if Rake::Task.task_defined?('environment')
|
25
|
+
Rake::Task['environment'].invoke
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
task :verify_env => :env do
|
30
|
+
|
31
|
+
unless Parse::Client.session?
|
32
|
+
raise "Please make sure you have setup the Parse.setup configuration before invoking task. Usually done in the :environment task."
|
33
|
+
end
|
34
|
+
|
35
|
+
endpoint = ENV['HOOKS_URL']
|
36
|
+
unless endpoint.empty? || endpoint.starts_with?('https://')
|
37
|
+
raise "The ENV variable HOOKS_URL must be a <https> url : '#{endpoint}'. Ex. https://12345678.ngrok.io/webhooks"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Run auto_upgrade on all of your Parse models."
|
43
|
+
task :upgrade => :env do
|
44
|
+
puts "Auto Upgrading Parse schemas..."
|
45
|
+
Parse.auto_upgrade! do |k|
|
46
|
+
puts "[+] #{k}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
namespace :webhooks do
|
51
|
+
|
52
|
+
desc "Register local webhooks with Parse server"
|
53
|
+
task :register => :verify_env do
|
54
|
+
endpoint = ENV['HOOKS_URL']
|
55
|
+
puts "Registering Parse Webhooks @ #{endpoint}"
|
56
|
+
Rake::Task['parse:webhooks:register:functions'].invoke
|
57
|
+
Rake::Task['parse:webhooks:register:triggers'].invoke
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "Remove all locally registered webhooks from the Parse Application"
|
61
|
+
task :remove => :verify_env do
|
62
|
+
Rake::Task['parse:webhooks:remove:functions'].invoke
|
63
|
+
Rake::Task['parse:webhooks:remove:triggers'].invoke
|
64
|
+
end
|
65
|
+
|
66
|
+
namespace :register do
|
67
|
+
|
68
|
+
task :functions => :verify_env do
|
69
|
+
endpoint = ENV['HOOKS_URL']
|
70
|
+
Parse::Webhooks.register_functions!(endpoint) do |name|
|
71
|
+
puts "[+] function - #{name}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
task :triggers => :verify_env do
|
76
|
+
endpoint = ENV['HOOKS_URL']
|
77
|
+
Parse::Webhooks.register_triggers!(endpoint, {include_wildcard: true}) do |trigger,name|
|
78
|
+
puts "[+] #{trigger.to_s.ljust(12, ' ')} - #{name}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
namespace :remove do
|
85
|
+
|
86
|
+
task :functions => :verify_env do
|
87
|
+
Parse::Webhooks.remove_all_functions! do |name|
|
88
|
+
puts "[-] function - #{name}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
task :triggers => :verify_env do
|
93
|
+
Parse::Webhooks.remove_all_triggers! do |trigger,name|
|
94
|
+
puts "[-] #{trigger.to_s.ljust(12, ' ')} - #{name}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end # webhooks
|
101
|
+
|
102
|
+
end # webhooks namespace
|
103
|
+
end
|
104
|
+
end # Tasks
|
105
|
+
end # Webhooks
|
106
|
+
|
107
|
+
end # Parse
|
data/lib/parse/stack/version.rb
CHANGED
data/lib/parse/webhooks.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
2
1
|
require 'active_model'
|
3
2
|
require 'active_support'
|
4
3
|
require 'active_support/inflector'
|
5
4
|
require 'active_support/core_ext/object'
|
5
|
+
require 'active_support/core_ext'
|
6
6
|
require 'active_model_serializers'
|
7
7
|
require 'rack'
|
8
8
|
require_relative 'client'
|
@@ -90,7 +90,7 @@ module Parse
|
|
90
90
|
class Webhooks
|
91
91
|
|
92
92
|
def self.reload!(args = {})
|
93
|
-
|
93
|
+
|
94
94
|
end
|
95
95
|
|
96
96
|
include Client::Connectable
|