parse-stack 1.5.1 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Changes.md +15 -1
- data/Gemfile.lock +10 -10
- data/README.md +23 -9
- data/bin/console +3 -0
- data/lib/parse/api/analytics.rb +1 -1
- data/lib/parse/api/objects.rb +1 -1
- data/lib/parse/api/users.rb +1 -1
- data/lib/parse/client.rb +77 -40
- data/lib/parse/client/caching.rb +9 -5
- data/lib/parse/client/protocol.rb +47 -0
- data/lib/parse/client/request.rb +66 -37
- data/lib/parse/client/response.rb +39 -21
- data/lib/parse/model/acl.rb +4 -9
- data/lib/parse/model/associations/belongs_to.rb +97 -9
- data/lib/parse/model/associations/collection_proxy.rb +89 -29
- data/lib/parse/model/associations/has_many.rb +301 -28
- data/lib/parse/model/associations/has_one.rb +98 -4
- data/lib/parse/model/associations/pointer_collection_proxy.rb +48 -16
- data/lib/parse/model/associations/relation_collection_proxy.rb +61 -36
- data/lib/parse/model/bytes.rb +11 -5
- data/lib/parse/model/classes/installation.rb +50 -3
- data/lib/parse/model/classes/role.rb +7 -2
- data/lib/parse/model/classes/session.rb +21 -4
- data/lib/parse/model/classes/user.rb +122 -22
- data/lib/parse/model/core/actions.rb +7 -3
- data/lib/parse/model/core/properties.rb +14 -13
- data/lib/parse/model/core/querying.rb +16 -10
- data/lib/parse/model/core/schema.rb +2 -3
- data/lib/parse/model/date.rb +18 -12
- data/lib/parse/model/file.rb +77 -19
- data/lib/parse/model/geopoint.rb +70 -12
- data/lib/parse/model/model.rb +84 -8
- data/lib/parse/model/object.rb +225 -94
- data/lib/parse/model/pointer.rb +94 -13
- data/lib/parse/model/push.rb +76 -4
- data/lib/parse/query.rb +356 -41
- data/lib/parse/query/constraints.rb +399 -29
- data/lib/parse/query/ordering.rb +21 -8
- data/lib/parse/stack.rb +1 -0
- data/lib/parse/stack/version.rb +2 -1
- data/lib/parse/webhooks.rb +0 -24
- data/lib/parse/webhooks/payload.rb +54 -1
- data/lib/parse/webhooks/registration.rb +13 -2
- metadata +2 -2
@@ -2,10 +2,9 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require_relative "properties"
|
5
|
-
# This class adds methods to Parse::Objects in order to create a JSON Parse schema
|
6
|
-
# in order to support table creation and table alterations.
|
7
|
-
module Parse
|
8
5
|
|
6
|
+
module Parse
|
7
|
+
# Upgrade all
|
9
8
|
def self.auto_upgrade!
|
10
9
|
klassModels = Parse::Object.descendants
|
11
10
|
klassModels.sort_by { |c| c.parse_class }.each do |klass|
|
data/lib/parse/model/date.rb
CHANGED
@@ -13,38 +13,42 @@ require 'active_support/core_ext/time/calculations'
|
|
13
13
|
require 'active_model_serializers'
|
14
14
|
require_relative 'model'
|
15
15
|
|
16
|
-
# Parse has a specific date format. One of the supported types is a date string in
|
17
|
-
# ISO 8601 format (including milliseconds). The other is a hash object that contains
|
18
|
-
# the similar information. When sending data to Parse, we need to use the hash object,
|
19
|
-
# but when receiving data from Parse, we may either get the string version or the hash version.
|
20
|
-
# To make things easier to use in ruby, th Parse::Date class inherits from the DateTime class.
|
21
|
-
# This will allow us to use all the great ActiveSupport methods for date (ex. 3.days.ago) while
|
22
|
-
# providing our own encoding for sending to Parse.
|
23
16
|
module Parse
|
17
|
+
# This class manages dates in the special JSON format it requires for
|
18
|
+
# properties of type _:date_. One important note with dates, is that 'created_at' and 'updated_at'
|
19
|
+
# columns do not follow this convention all the time. Depending on the
|
20
|
+
# Cloud Code SDK, they can be the Parse ISO hash date format or the `iso8601`
|
21
|
+
# string format. By default, these are serialized as `iso8601` when sent as
|
22
|
+
# responses to Parse for backwards compatibility with some clients. To use
|
23
|
+
# the Parse ISO hash format for these fields instead, set
|
24
|
+
# `Parse::Object.disable_serialized_string_date = true`.
|
24
25
|
class Date < ::DateTime
|
25
26
|
ATTRIBUTES = { __type: :string, iso: :string }.freeze
|
26
27
|
include ::ActiveModel::Model
|
27
28
|
include ::ActiveModel::Serializers::JSON
|
29
|
+
|
30
|
+
# @return [Parse::Model::TYPE_DATE]
|
28
31
|
def self.parse_class; Parse::Model::TYPE_DATE; end;
|
32
|
+
# @return [Parse::Model::TYPE_DATE]
|
29
33
|
def parse_class; self.class.parse_class; end;
|
30
34
|
alias_method :__type, :parse_class
|
31
35
|
|
32
|
-
#
|
36
|
+
# @return [Hash]
|
33
37
|
def attributes
|
34
38
|
ATTRIBUTES
|
35
39
|
end
|
36
40
|
|
37
|
-
#
|
41
|
+
# @return [String] the ISO8601 time string including milliseconds
|
38
42
|
def iso
|
39
|
-
to_time.utc.iso8601(3)
|
43
|
+
to_time.utc.iso8601(3)
|
40
44
|
end
|
41
45
|
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
45
|
-
|
46
|
-
# Time and DateTime objects to Parse::Date objects
|
49
|
+
|
47
50
|
class Time
|
51
|
+
# @return [Parse::Date] Converts object to Parse::Date
|
48
52
|
def parse_date
|
49
53
|
Parse::Date.parse iso8601(3)
|
50
54
|
end
|
@@ -52,6 +56,7 @@ class Time
|
|
52
56
|
end
|
53
57
|
|
54
58
|
class DateTime
|
59
|
+
# @return [Parse::Date] Converts object to Parse::Date
|
55
60
|
def parse_date
|
56
61
|
Parse::Date.parse iso8601(3)
|
57
62
|
end
|
@@ -59,6 +64,7 @@ end
|
|
59
64
|
|
60
65
|
module ActiveSupport
|
61
66
|
class TimeWithZone
|
67
|
+
# @return [Parse::Date] Converts object to Parse::Date
|
62
68
|
def parse_date
|
63
69
|
Parse::Date.parse iso8601(3)
|
64
70
|
end
|
data/lib/parse/model/file.rb
CHANGED
@@ -5,30 +5,61 @@ require 'active_support'
|
|
5
5
|
require 'active_support/core_ext/object'
|
6
6
|
require_relative "model"
|
7
7
|
require 'open-uri'
|
8
|
-
# Parse File objects are the only non Parse::Object subclass that has a save method.
|
9
|
-
# In general, a Parse File needs content and a specific mime-type to be created. When it is saved, it
|
10
|
-
# is sent to AWS/S3 to be saved (by Parse), and the result is a new URL pointing to that file.
|
11
|
-
# This however is return as a type of File pointer object (hash format)
|
12
|
-
# It only has two fields, the absolute URL of the file and the basename of the file.
|
13
|
-
# The contents and mime_type are only present when creating a new file locally and are not
|
14
|
-
# stored as part of the parse pointer.
|
15
|
-
module Parse
|
16
8
|
|
9
|
+
module Parse
|
10
|
+
# This class represents a Parse file pointer. `Parse::File` has helper
|
11
|
+
# methods to upload Parse files directly to Parse and manage file
|
12
|
+
# associations with your classes.
|
13
|
+
# @example
|
14
|
+
# file = File.open("file_path.jpg")
|
15
|
+
# contents = file.read
|
16
|
+
# file = Parse::File.new("myimage.jpg", contents , "image/jpeg")
|
17
|
+
# file.saved? # => false
|
18
|
+
# file.save
|
19
|
+
#
|
20
|
+
# file.url # https://files.parsetfss.com/....
|
21
|
+
#
|
22
|
+
# # or create and upload a remote file (auto-detected mime type)
|
23
|
+
# file = Parse::File.create(some_url)
|
24
|
+
#
|
25
|
+
#
|
26
|
+
# @note The default MIME type for all files is _image/jpeg_. This can be default
|
27
|
+
# can be changed by setting a value to `Parse::File.default_mime_type`.
|
17
28
|
class File < Model
|
18
29
|
ATTRIBUTES = { __type: :string, name: :string, url: :string }.freeze
|
19
|
-
|
20
|
-
attr_accessor :
|
30
|
+
# @return [String] the name of the file including extension (if any)
|
31
|
+
attr_accessor :name
|
32
|
+
# @return [String] the url resource of the file.
|
33
|
+
attr_accessor :url
|
34
|
+
|
35
|
+
# You may set the contents of the file.
|
36
|
+
attr_accessor :contents
|
37
|
+
|
38
|
+
# @return [String] the mime-type of the file whe
|
39
|
+
attr_accessor :mime_type
|
40
|
+
# @return [Model::TYPE_FILE]
|
21
41
|
def self.parse_class; TYPE_FILE; end;
|
42
|
+
# @return [Model::TYPE_FILE]
|
22
43
|
def parse_class; self.class.parse_class; end;
|
23
44
|
alias_method :__type, :parse_class
|
24
45
|
FIELD_NAME = "name"
|
25
46
|
FIELD_URL = "url"
|
26
47
|
class << self
|
48
|
+
|
27
49
|
attr_accessor :default_mime_type
|
28
50
|
|
51
|
+
attr_accessor :force_ssl
|
52
|
+
|
53
|
+
# @return [String] The default mime type for created instances. Default: _'image/jpeg'_
|
29
54
|
def default_mime_type
|
30
55
|
@default_mime_type ||= "image/jpeg"
|
31
56
|
end
|
57
|
+
|
58
|
+
# @return [Boolean] When set to true, it will make all calls to File#url
|
59
|
+
def force_ssl
|
60
|
+
@force_ssl ||= false
|
61
|
+
end
|
62
|
+
|
32
63
|
end
|
33
64
|
# The initializer to create a new file supports different inputs.
|
34
65
|
# If the first paramter is a string which starts with 'http', we then download
|
@@ -36,6 +67,9 @@ module Parse
|
|
36
67
|
# If the first parameter is a hash, we assume it might be the Parse File hash format which contains url and name fields only.
|
37
68
|
# If the first paramter is a Parse::File, then we copy fields over
|
38
69
|
# Otherwise, creating a new file requires a name, the actual contents (usually from a File.open("local.jpg").read ) and the mime-type
|
70
|
+
# @param name [String]
|
71
|
+
# @param contents [Object]
|
72
|
+
# @param mime_type [String] Default see default_mime_type
|
39
73
|
def initialize(name, contents = nil, mime_type = nil)
|
40
74
|
mime_type ||= Parse::File.default_mime_type
|
41
75
|
|
@@ -65,6 +99,8 @@ module Parse
|
|
65
99
|
end
|
66
100
|
|
67
101
|
# This creates a new Parse File Object with from a URL, saves it and returns it
|
102
|
+
# @param url [String] A url which will be used to create the file and automatically save it.
|
103
|
+
# @return [Parse::File] A newly saved file based on contents of _url_
|
68
104
|
def self.create(url)
|
69
105
|
url = url.url if url.is_a?(Parse::File)
|
70
106
|
file = self.new(url)
|
@@ -72,16 +108,28 @@ module Parse
|
|
72
108
|
file
|
73
109
|
end
|
74
110
|
|
75
|
-
# A File object is considered saved if the basename of the URL and the name parameters are equal
|
76
|
-
#
|
111
|
+
# A File object is considered saved if the basename of the URL and the name parameters are equal
|
112
|
+
# @return [Boolean] true if this file has already been saved.
|
77
113
|
def saved?
|
78
|
-
@url.present? && @name.present? && @name == File.basename(@url)
|
114
|
+
@url.present? && @name.present? && @name == File.basename(@url)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns the url string for this Parse::File pointer. If the *force_ssl* option is
|
118
|
+
# set to true, it will make sure it returns a secure url.
|
119
|
+
# @return [String] the url string for the file.
|
120
|
+
def url
|
121
|
+
if @url.present? && Parse::File.force_ssl && @url.starts_with?('http://')
|
122
|
+
return @url.sub('http://', 'https://')
|
123
|
+
end
|
124
|
+
@url
|
79
125
|
end
|
80
126
|
|
127
|
+
# @return [Hash]
|
81
128
|
def attributes
|
82
129
|
ATTRIBUTES
|
83
130
|
end
|
84
131
|
|
132
|
+
# @return [Boolean] Two files are equal if they have the same url
|
85
133
|
def ==(u)
|
86
134
|
return false unless u.is_a?(self.class)
|
87
135
|
@url == u.url
|
@@ -97,7 +145,11 @@ module Parse
|
|
97
145
|
end
|
98
146
|
end
|
99
147
|
|
100
|
-
#
|
148
|
+
# A proxy method for ::File.basename
|
149
|
+
# @param file_name [String]
|
150
|
+
# @param suffix [String]
|
151
|
+
# @return [String] File.basename(file_name)
|
152
|
+
# @see ::File.basename
|
101
153
|
def self.basename(file_name, suffix = nil)
|
102
154
|
if suffix.nil?
|
103
155
|
::File.basename(file_name)
|
@@ -106,7 +158,8 @@ module Parse
|
|
106
158
|
end
|
107
159
|
end
|
108
160
|
|
109
|
-
#
|
161
|
+
# Save the file by uploading it to Parse and creating a file pointer.
|
162
|
+
# @return [Boolean] true if successfully uploaded and saved.
|
110
163
|
def save
|
111
164
|
unless saved? || @contents.nil? || @name.nil?
|
112
165
|
response = client.create_file(@name, @contents, @mime_type)
|
@@ -119,10 +172,13 @@ module Parse
|
|
119
172
|
saved?
|
120
173
|
end
|
121
174
|
|
175
|
+
# @!visibility private
|
122
176
|
def inspect
|
123
177
|
"<Parse::File @name='#{@name}' @mime_type='#{@mime_type}' @contents=#{@contents.nil?} @url='#{@url}'>"
|
124
178
|
end
|
125
179
|
|
180
|
+
# @return [String] the url
|
181
|
+
# @see #url
|
126
182
|
def to_s
|
127
183
|
@url
|
128
184
|
end
|
@@ -133,13 +189,15 @@ end
|
|
133
189
|
|
134
190
|
|
135
191
|
class Hash
|
136
|
-
#
|
137
|
-
#
|
192
|
+
# Determines if the hash contains Parse File json metadata fields. This is determined whether
|
193
|
+
# the key `__type` exists and is of type `__File` and whether the `name` field matches the File.basename
|
194
|
+
# of the `url` field.
|
195
|
+
#
|
196
|
+
# @return [Boolean] True if this hash contains Parse file metadata.
|
138
197
|
def parse_file?
|
139
198
|
url = self[Parse::File::FIELD_URL]
|
140
199
|
name = self[Parse::File::FIELD_NAME]
|
141
200
|
(count == 2 || self["__type"] == Parse::File.parse_class) &&
|
142
|
-
url.present? && name.present? &&
|
143
|
-
name == ::File.basename(url) && name.start_with?("tfss")
|
201
|
+
url.present? && name.present? && name == ::File.basename(url)
|
144
202
|
end
|
145
203
|
end
|
data/lib/parse/model/geopoint.rb
CHANGED
@@ -5,31 +5,54 @@ require_relative "model"
|
|
5
5
|
|
6
6
|
module Parse
|
7
7
|
|
8
|
-
#
|
9
|
-
#
|
8
|
+
# This class manages the GeoPoint data type that Parse provides to support
|
9
|
+
# geo-queries. To define a GeoPoint property, use the `:geopoint` data type.
|
10
|
+
# Please note that latitudes should not be between -90.0 and 90.0, and
|
11
|
+
# longitudes should be between -180.0 and 180.0.
|
12
|
+
# @example
|
13
|
+
# class PlaceObject < Parse::Object
|
14
|
+
# property :location, :geopoint
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# san_diego = Parse::GeoPoint.new(32.8233, -117.6542)
|
18
|
+
# los_angeles = Parse::GeoPoint.new [34.0192341, -118.970792]
|
19
|
+
# san_diego == los_angeles # false
|
20
|
+
#
|
21
|
+
# place = PlaceObject.new
|
22
|
+
# place.location = san_diego
|
23
|
+
# place.save
|
24
|
+
#
|
10
25
|
class GeoPoint < Model
|
11
26
|
ATTRIBUTES = { __type: :string, latitude: :float, longitude: :float }.freeze
|
12
|
-
|
27
|
+
|
28
|
+
# @return [Float] latitude value between -90.0 and 90.0
|
29
|
+
attr_accessor :latitude
|
30
|
+
# @return [Float] longitude value between -180.0 and 180.0
|
31
|
+
attr_accessor :longitude
|
13
32
|
FIELD_LAT = "latitude"
|
14
33
|
FIELD_LNG = "longitude"
|
15
|
-
|
16
|
-
# Longitude should not be -180.0 or 180.0.
|
34
|
+
|
17
35
|
LAT_MIN = -90.0
|
18
36
|
LAT_MAX = 90.0
|
19
37
|
LNG_MIN = -180.0
|
20
38
|
LNG_MAX = 180.0
|
39
|
+
|
21
40
|
alias_method :lat, :latitude
|
22
41
|
alias_method :lng, :longitude
|
42
|
+
# @return [Model::TYPE_GEOPOINT]
|
23
43
|
def self.parse_class; TYPE_GEOPOINT; end;
|
44
|
+
# @return [Model::TYPE_GEOPOINT]
|
24
45
|
def parse_class; self.class.parse_class; end;
|
25
46
|
alias_method :__type, :parse_class
|
26
|
-
# To create a GeoPoint, you can either pass a hash (ex. {latitude: 32, longitue: -117})
|
27
|
-
# or an array (ex. [32,-117]) as the first parameter.
|
28
|
-
# You may also pass a GeoPoint object or both a lat/lng pair (Ex. GeoPoint.new(32, -117) )
|
29
|
-
# Points should not equal or exceed the extreme ends of the ranges.
|
30
|
-
|
31
|
-
# Attempting to use GeoPoint’s with latitude and/or longitude outside these ranges will cause an error.
|
32
47
|
|
48
|
+
# The initializer can create a GeoPoint with a hash, array or values.
|
49
|
+
# @example
|
50
|
+
# san_diego = Parse::GeoPoint.new(32.8233, -117.6542)
|
51
|
+
# san_diego = Parse::GeoPoint.new [32.8233, -117.6542]
|
52
|
+
# san_diego = Parse::GeoPoint.new { latitude: 32.8233, longitude: -117.6542}
|
53
|
+
#
|
54
|
+
# @param latitude [Numeric] The latitude value between LAT_MIN and LAT_MAX.
|
55
|
+
# @param longitude [Numeric] The longitude value between LNG_MIN and LNG_MAX.
|
33
56
|
def initialize(latitude = nil, longitude = nil)
|
34
57
|
@latitude = @longitude = 0.0
|
35
58
|
if latitude.is_a?(Hash) || latitude.is_a?(Array)
|
@@ -45,6 +68,7 @@ module Parse
|
|
45
68
|
_validate_point
|
46
69
|
end
|
47
70
|
|
71
|
+
# @!visibility private
|
48
72
|
def _validate_point
|
49
73
|
|
50
74
|
unless @latitude.nil? || @latitude.between?(LAT_MIN, LAT_MAX)
|
@@ -59,10 +83,13 @@ module Parse
|
|
59
83
|
|
60
84
|
end
|
61
85
|
|
86
|
+
# @return [Hash]
|
62
87
|
def attributes
|
63
88
|
ATTRIBUTES
|
64
89
|
end
|
65
90
|
|
91
|
+
# Helper method for performing geo-queries with radial miles constraints
|
92
|
+
# @return [Array] containing [lat,lng,miles]
|
66
93
|
def max_miles(m)
|
67
94
|
m = 0 if m.nil?
|
68
95
|
[@latitude,@longitude,m]
|
@@ -92,24 +119,55 @@ module Parse
|
|
92
119
|
_validate_point
|
93
120
|
end
|
94
121
|
|
122
|
+
# @return [Boolean] true if two geopoints are equal based on lat and lng.
|
95
123
|
def ==(g)
|
96
124
|
return false unless g.is_a?(GeoPoint)
|
97
125
|
@latitude == g.latitude && @longitude == g.longitude
|
98
126
|
end
|
99
127
|
|
128
|
+
# Helper method for reducing the precision of a geopoint.
|
129
|
+
# @param precision [Integer] The number of floating digits to keep.
|
130
|
+
# @return [GeoPoint] Reduces the precision of a geopoint.
|
131
|
+
def estimated(precision = 2)
|
132
|
+
Parse::GeoPoint.new(@latitude.to_f.round(precision), @longitude.round(precision))
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns a tuple containing latitude and longitude
|
136
|
+
# @return [Array]
|
100
137
|
def to_a
|
101
138
|
[@latitude,@longitude]
|
102
139
|
end
|
103
140
|
|
141
|
+
# @!visibility private
|
104
142
|
def inspect
|
105
143
|
"#<GeoPoint [#{@latitude},#{@longitude}]>"
|
106
144
|
end
|
107
145
|
|
108
|
-
#
|
146
|
+
# Calculate the distance in miles to another GeoPoint using Haversine.
|
147
|
+
# You may also call this method with a latitude and longitude.
|
148
|
+
# @example
|
149
|
+
# point.distance_in_miles(geotpoint)
|
150
|
+
# point.distance_in_miles(lat, lng)
|
151
|
+
#
|
152
|
+
# @param geopoint [GeoPoint]
|
153
|
+
# @param lng [Float] Longitude assuming that the first parameter
|
154
|
+
# is longitude instead of a GeoPoint.
|
155
|
+
# @return [Float] number of miles between geopoints.
|
156
|
+
# @see #distance_in_km
|
109
157
|
def distance_in_miles(geopoint,lng = nil)
|
110
158
|
distance_in_km(geopoint, lng) * 0.621371
|
111
159
|
end
|
112
160
|
|
161
|
+
# Calculate the distance in kilometers to another GeoPoint using Haversine
|
162
|
+
# method. You may also call this method with a latitude and longitude.
|
163
|
+
# @example
|
164
|
+
# point.distance_in_km(geotpoint)
|
165
|
+
# point.distance_in_km(lat, lng)
|
166
|
+
#
|
167
|
+
# @param geopoint [GeoPoint]
|
168
|
+
# @param lng [Float] Longitude assuming that the first parameter is a latitude instead of a GeoPoint.
|
169
|
+
# @return [Float] number of miles between geopoints.
|
170
|
+
# @see #distance_in_miles
|
113
171
|
def distance_in_km(geopoint,lng = nil)
|
114
172
|
unless geopoint.is_a?(Parse::GeoPoint)
|
115
173
|
geopoint = Parse::GeoPoint.new(geopoint, lng)
|
data/lib/parse/model/model.rb
CHANGED
@@ -8,10 +8,18 @@ require 'active_support/core_ext/object'
|
|
8
8
|
require 'active_model_serializers'
|
9
9
|
require_relative '../client'
|
10
10
|
|
11
|
-
# This is the base model for all Parse object-type classes.
|
12
|
-
|
13
11
|
module Parse
|
12
|
+
# Find a corresponding Parse::Object subclass for this string or symbol
|
13
|
+
# @param className [String] The name of the Parse class as string (ex. "_User")
|
14
|
+
# @return [Class] The proper subclass matching the className.
|
15
|
+
def self.classify(className)
|
16
|
+
Parse::Model.find_class className.to_parse_class
|
17
|
+
end
|
14
18
|
|
19
|
+
# The core model of all Parse-Stack classes. This class works by providing a
|
20
|
+
# baseline for all subclass objects to support ActiveModel features such as
|
21
|
+
# serialization, dirty tracking, callbacks, etc.
|
22
|
+
# @see ActiveModel
|
15
23
|
class Model
|
16
24
|
|
17
25
|
include Client::Connectable # allows easy default Parse::Client access
|
@@ -22,7 +30,6 @@ module Parse
|
|
22
30
|
extend ::ActiveModel::Callbacks # callback support on save, update, delete, etc.
|
23
31
|
extend ::ActiveModel::Naming # provides the methods for getting class names from Model classes
|
24
32
|
|
25
|
-
# General Parse constants
|
26
33
|
ID = "id".freeze
|
27
34
|
OBJECT_ID = 'objectId'.freeze
|
28
35
|
KEY_CLASS_NAME = 'className'.freeze
|
@@ -48,15 +55,40 @@ module Parse
|
|
48
55
|
# which Parse::Object subclass is responsible for handling this Parse table class.
|
49
56
|
# we use @@model_cache to cache the results of the algorithm since we do this frequently
|
50
57
|
# when encoding and decoding objects.
|
58
|
+
# @!visibility private
|
51
59
|
@@model_cache = {}
|
60
|
+
|
61
|
+
# If set to true, a call to first_or_create will automatically save the object.
|
62
|
+
# @return [Boolean]
|
52
63
|
def self.autosave_on_create
|
53
64
|
@@autosave_on_create ||= false
|
54
65
|
end
|
66
|
+
|
55
67
|
def self.autosave_on_create=(bool)
|
56
68
|
@@autosave_on_create = bool
|
57
69
|
end
|
58
70
|
|
59
71
|
class << self
|
72
|
+
# By default, we return `true` or `false` for save and destroy operations.
|
73
|
+
# If you prefer to have `Parse::Object` raise an exception instead, you
|
74
|
+
# can tell to do so either globally or on a per-model basis. When a save
|
75
|
+
# fails, it will raise a `Parse::SaveFailureError`.
|
76
|
+
#
|
77
|
+
# @example
|
78
|
+
# Parse::Model.raise_on_save_failure = true # globally across all models
|
79
|
+
# Song.raise_on_save_failure = true # per-model
|
80
|
+
#
|
81
|
+
# # or per-instance raise on failure
|
82
|
+
# song.save!
|
83
|
+
#
|
84
|
+
# When enabled, if an error is returned by Parse due to saving or
|
85
|
+
# destroying a record, due to your `before_save` or `before_delete`
|
86
|
+
# validation cloud code triggers, `Parse::Object` will return the a
|
87
|
+
# `Parse::SaveFailureError` exception type. This exception has an
|
88
|
+
# instance method of `#object` which contains the object that failed to save.
|
89
|
+
#
|
90
|
+
# @return [Boolean]
|
91
|
+
attr_accessor :raise_on_save_failure
|
60
92
|
|
61
93
|
def raise_on_save_failure
|
62
94
|
@global_raise_on_save_failure ||= false
|
@@ -67,8 +99,23 @@ module Parse
|
|
67
99
|
|
68
100
|
end
|
69
101
|
|
70
|
-
#
|
71
|
-
# the
|
102
|
+
# Find a Parse::Model subclass matching this type or Pares collection name.
|
103
|
+
# This helper method is useful to find the corresponding class ruby Parse::Object subclass that handles
|
104
|
+
# the provided parse class.
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# Parse::Model.find_class('_User') # => Parse::User
|
108
|
+
# Parse::Model.find_class('_Date') # => Parse::Date
|
109
|
+
# Parse::Model.find_class('Installation') # => Parse::Installation
|
110
|
+
#
|
111
|
+
# class Artist < Parse::Object
|
112
|
+
# parse_class "Musician"
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# Parse::Model.find_class("Musician") # => Artist
|
116
|
+
#
|
117
|
+
# @param str [String] the class name
|
118
|
+
# @return [Parse::Object] a Parse::Object subclass or a specific Parse type.
|
72
119
|
def self.find_class(str)
|
73
120
|
return Parse::File if str == TYPE_FILE
|
74
121
|
return Parse::GeoPoint if str == TYPE_GEOPOINT
|
@@ -92,14 +139,39 @@ end
|
|
92
139
|
|
93
140
|
|
94
141
|
class String
|
95
|
-
#
|
142
|
+
# This method returns a camel-cased version of the string with the first letter
|
143
|
+
# of the string in lower case. This is the standard naming convention for Parse columns
|
144
|
+
# and property fields. This has special exception to the string "id", which returns
|
145
|
+
# "objectId". This is the default name filtering method for all defined properties and
|
146
|
+
# query keys in Parse::Query.
|
147
|
+
#
|
148
|
+
# @example
|
149
|
+
# "my_field".columnize # => "myField"
|
150
|
+
# "MyDataColumn".columnize # => "myDataColumn"
|
151
|
+
# "id".columnize # => "objectId" (special)
|
152
|
+
#
|
153
|
+
# @return [String]
|
154
|
+
# @see Parse::Query.field_formatter
|
96
155
|
def columnize
|
97
156
|
return Parse::Model::OBJECT_ID if self == Parse::Model::ID
|
98
157
|
u = '_'.freeze
|
99
158
|
(first == u ? sub(u,'') : self).camelize(:lower)
|
100
159
|
end
|
101
160
|
|
102
|
-
#
|
161
|
+
# Convert a string to a Parse class name. This method tries to find a
|
162
|
+
# responsible Parse::Object subclass that potentially matches the given string.
|
163
|
+
# If no match is found, it returns the camelized version of the string. This method
|
164
|
+
# is used internally for matching association attributes to registered
|
165
|
+
# Parse::Object subclasses. The method can also singularize the name before
|
166
|
+
# performing conversion.
|
167
|
+
#
|
168
|
+
# @example
|
169
|
+
# "users".to_parse_class(singularize: true) # => "_User"
|
170
|
+
# "users".to_parse_class # => "Users"
|
171
|
+
# "song_data".to_parse_class # => "SongData"
|
172
|
+
#
|
173
|
+
# @param singularize [Boolean] whether the string should be singularized first before performing conversion.
|
174
|
+
# @return [String] the matching Parse class for this string.
|
103
175
|
def to_parse_class(singularize: false)
|
104
176
|
final_class = singularize ? self.singularize.camelize : self.camelize
|
105
177
|
klass = Parse::Model.find_class(final_class) || Parse::Model.find_class(self)
|
@@ -110,19 +182,23 @@ class String
|
|
110
182
|
end
|
111
183
|
|
112
184
|
class Symbol
|
113
|
-
#
|
185
|
+
# @return [String] a lower-first-camelcased version of the symbol
|
186
|
+
# @see String#columnize
|
114
187
|
def columnize
|
115
188
|
to_s.columnize.to_sym
|
116
189
|
end
|
117
190
|
|
191
|
+
# @see String#singularize
|
118
192
|
def singularize
|
119
193
|
to_s.singularize
|
120
194
|
end
|
121
195
|
|
196
|
+
# @see String#camelize
|
122
197
|
def camelize
|
123
198
|
to_s.camelize
|
124
199
|
end
|
125
200
|
|
201
|
+
# @see String#to_parse_class
|
126
202
|
def to_parse_class(singularize: false)
|
127
203
|
to_s.to_parse_class(singularize: singularize)
|
128
204
|
end
|