parse-stack 1.5.1 → 1.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|