parse-stack-next 4.5.0
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 +7 -0
- data/.bundle/config +2 -0
- data/.env.sample +112 -0
- data/.env.test +10 -0
- data/.github/workflows/ruby.yml +36 -0
- data/.gitignore +49 -0
- data/.ruby-version +1 -0
- data/.solargraph.yml +22 -0
- data/CHANGELOG.md +5816 -0
- data/Gemfile +30 -0
- data/Gemfile.lock +175 -0
- data/LICENSE.txt +23 -0
- data/Makefile +63 -0
- data/README.md +5655 -0
- data/Rakefile +573 -0
- data/bin/console +38 -0
- data/bin/parse-console +136 -0
- data/bin/server +17 -0
- data/bin/setup +7 -0
- data/config/parse-config.json +12 -0
- data/docs/TEST_SERVER.md +271 -0
- data/docs/_config.yml +1 -0
- data/docs/mcp_guide.md +3484 -0
- data/docs/mongodb_direct_guide.md +1348 -0
- data/docs/mongodb_index_optimization_guide.md +631 -0
- data/examples/transaction_example.rb +219 -0
- data/lib/parse/acl_scope.rb +728 -0
- data/lib/parse/agent/cancellation_token.rb +80 -0
- data/lib/parse/agent/constraint_translator.rb +480 -0
- data/lib/parse/agent/describe.rb +420 -0
- data/lib/parse/agent/errors.rb +133 -0
- data/lib/parse/agent/mcp_client.rb +557 -0
- data/lib/parse/agent/mcp_dispatcher.rb +1023 -0
- data/lib/parse/agent/mcp_rack_app.rb +1143 -0
- data/lib/parse/agent/mcp_server.rb +376 -0
- data/lib/parse/agent/metadata_audit.rb +259 -0
- data/lib/parse/agent/metadata_dsl.rb +733 -0
- data/lib/parse/agent/metadata_registry.rb +794 -0
- data/lib/parse/agent/pipeline_validator.rb +82 -0
- data/lib/parse/agent/prompts.rb +351 -0
- data/lib/parse/agent/rate_limiter.rb +158 -0
- data/lib/parse/agent/relation_graph.rb +162 -0
- data/lib/parse/agent/result_formatter.rb +453 -0
- data/lib/parse/agent/tools.rb +5489 -0
- data/lib/parse/agent.rb +3249 -0
- data/lib/parse/api/aggregate.rb +79 -0
- data/lib/parse/api/all.rb +26 -0
- data/lib/parse/api/analytics.rb +18 -0
- data/lib/parse/api/batch.rb +33 -0
- data/lib/parse/api/cloud_functions.rb +58 -0
- data/lib/parse/api/config.rb +125 -0
- data/lib/parse/api/files.rb +29 -0
- data/lib/parse/api/hooks.rb +117 -0
- data/lib/parse/api/objects.rb +146 -0
- data/lib/parse/api/path_segment.rb +75 -0
- data/lib/parse/api/push.rb +20 -0
- data/lib/parse/api/schema.rb +49 -0
- data/lib/parse/api/server.rb +50 -0
- data/lib/parse/api/sessions.rb +24 -0
- data/lib/parse/api/users.rb +250 -0
- data/lib/parse/atlas_search/index_manager.rb +353 -0
- data/lib/parse/atlas_search/result.rb +204 -0
- data/lib/parse/atlas_search/search_builder.rb +604 -0
- data/lib/parse/atlas_search/session.rb +253 -0
- data/lib/parse/atlas_search.rb +995 -0
- data/lib/parse/client/authentication.rb +97 -0
- data/lib/parse/client/batch.rb +234 -0
- data/lib/parse/client/body_builder.rb +240 -0
- data/lib/parse/client/caching.rb +203 -0
- data/lib/parse/client/logging.rb +293 -0
- data/lib/parse/client/profiling.rb +181 -0
- data/lib/parse/client/protocol.rb +91 -0
- data/lib/parse/client/request.rb +233 -0
- data/lib/parse/client/response.rb +208 -0
- data/lib/parse/client.rb +1104 -0
- data/lib/parse/clp_scope.rb +361 -0
- data/lib/parse/live_query/circuit_breaker.rb +256 -0
- data/lib/parse/live_query/client.rb +1001 -0
- data/lib/parse/live_query/configuration.rb +224 -0
- data/lib/parse/live_query/event.rb +115 -0
- data/lib/parse/live_query/event_queue.rb +272 -0
- data/lib/parse/live_query/health_monitor.rb +214 -0
- data/lib/parse/live_query/logging.rb +149 -0
- data/lib/parse/live_query/subscription.rb +294 -0
- data/lib/parse/live_query.rb +163 -0
- data/lib/parse/lookup_rewriter.rb +445 -0
- data/lib/parse/model/acl.rb +968 -0
- data/lib/parse/model/associations/belongs_to.rb +275 -0
- data/lib/parse/model/associations/collection_proxy.rb +435 -0
- data/lib/parse/model/associations/has_many.rb +597 -0
- data/lib/parse/model/associations/has_one.rb +158 -0
- data/lib/parse/model/associations/pointer_collection_proxy.rb +134 -0
- data/lib/parse/model/associations/relation_collection_proxy.rb +177 -0
- data/lib/parse/model/bytes.rb +62 -0
- data/lib/parse/model/classes/audience.rb +262 -0
- data/lib/parse/model/classes/installation.rb +363 -0
- data/lib/parse/model/classes/job_schedule.rb +153 -0
- data/lib/parse/model/classes/job_status.rb +264 -0
- data/lib/parse/model/classes/product.rb +75 -0
- data/lib/parse/model/classes/push_status.rb +263 -0
- data/lib/parse/model/classes/role.rb +751 -0
- data/lib/parse/model/classes/session.rb +201 -0
- data/lib/parse/model/classes/user.rb +943 -0
- data/lib/parse/model/clp.rb +544 -0
- data/lib/parse/model/core/actions.rb +1268 -0
- data/lib/parse/model/core/builder.rb +139 -0
- data/lib/parse/model/core/create_lock.rb +386 -0
- data/lib/parse/model/core/describe.rb +382 -0
- data/lib/parse/model/core/enhanced_change_tracking.rb +159 -0
- data/lib/parse/model/core/errors.rb +38 -0
- data/lib/parse/model/core/fetching.rb +566 -0
- data/lib/parse/model/core/field_guards.rb +220 -0
- data/lib/parse/model/core/indexing.rb +382 -0
- data/lib/parse/model/core/parse_reference.rb +407 -0
- data/lib/parse/model/core/properties.rb +809 -0
- data/lib/parse/model/core/querying.rb +491 -0
- data/lib/parse/model/core/schema.rb +202 -0
- data/lib/parse/model/core/search_indexing.rb +174 -0
- data/lib/parse/model/date.rb +88 -0
- data/lib/parse/model/email.rb +213 -0
- data/lib/parse/model/file.rb +527 -0
- data/lib/parse/model/geojson.rb +271 -0
- data/lib/parse/model/geopoint.rb +261 -0
- data/lib/parse/model/model.rb +260 -0
- data/lib/parse/model/object.rb +2068 -0
- data/lib/parse/model/phone.rb +520 -0
- data/lib/parse/model/pointer.rb +443 -0
- data/lib/parse/model/polygon.rb +406 -0
- data/lib/parse/model/push.rb +975 -0
- data/lib/parse/model/shortnames.rb +8 -0
- data/lib/parse/model/time_zone.rb +141 -0
- data/lib/parse/model/validations/uniqueness_validator.rb +97 -0
- data/lib/parse/model/validations.rb +96 -0
- data/lib/parse/mongodb.rb +2300 -0
- data/lib/parse/pipeline_security.rb +554 -0
- data/lib/parse/query/constraint.rb +198 -0
- data/lib/parse/query/constraints.rb +3279 -0
- data/lib/parse/query/cursor.rb +434 -0
- data/lib/parse/query/n_plus_one_detector.rb +445 -0
- data/lib/parse/query/operation.rb +104 -0
- data/lib/parse/query/ordering.rb +66 -0
- data/lib/parse/query.rb +7028 -0
- data/lib/parse/schema/index_migrator.rb +291 -0
- data/lib/parse/schema/search_index_migrator.rb +289 -0
- data/lib/parse/schema.rb +494 -0
- data/lib/parse/stack/generators/rails.rb +40 -0
- data/lib/parse/stack/generators/templates/model.erb +51 -0
- data/lib/parse/stack/generators/templates/model_installation.rb +4 -0
- data/lib/parse/stack/generators/templates/model_role.rb +4 -0
- data/lib/parse/stack/generators/templates/model_session.rb +4 -0
- data/lib/parse/stack/generators/templates/model_user.rb +11 -0
- data/lib/parse/stack/generators/templates/parse.rb +12 -0
- data/lib/parse/stack/generators/templates/webhooks.rb +10 -0
- data/lib/parse/stack/railtie.rb +18 -0
- data/lib/parse/stack/tasks.rb +563 -0
- data/lib/parse/stack/version.rb +11 -0
- data/lib/parse/stack.rb +455 -0
- data/lib/parse/two_factor_auth/user_extension.rb +449 -0
- data/lib/parse/two_factor_auth.rb +310 -0
- data/lib/parse/webhooks/payload.rb +360 -0
- data/lib/parse/webhooks/registration.rb +199 -0
- data/lib/parse/webhooks/replay_protection.rb +189 -0
- data/lib/parse/webhooks.rb +510 -0
- data/lib/parse-stack-next.rb +5 -0
- data/lib/parse-stack.rb +5 -0
- data/parse-stack-next.gemspec +82 -0
- data/parse-stack.png +0 -0
- data/scripts/debug-ips.js +35 -0
- data/scripts/docker/Dockerfile.parse +13 -0
- data/scripts/docker/atlas-init.js +284 -0
- data/scripts/docker/docker-compose.atlas.yml +76 -0
- data/scripts/docker/docker-compose.test.yml +106 -0
- data/scripts/docker/mongo-init.js +21 -0
- data/scripts/eval_mcp_with_lm_studio.rb +274 -0
- data/scripts/start-parse.sh +90 -0
- data/scripts/start_mcp_server.rb +78 -0
- data/scripts/test_server_connection.rb +82 -0
- metadata +377 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "../pointer"
|
|
5
|
+
require_relative "collection_proxy"
|
|
6
|
+
require_relative "pointer_collection_proxy"
|
|
7
|
+
require_relative "relation_collection_proxy"
|
|
8
|
+
|
|
9
|
+
module Parse
|
|
10
|
+
# Defines all the types of Parse object associations.
|
|
11
|
+
module Associations
|
|
12
|
+
# This association creates a one-to-one association with another Parse model.
|
|
13
|
+
# BelongsTo relation is the simplies association in which the local
|
|
14
|
+
# Parse table constrains a column that has a Parse::Pointer to a foreign table record.
|
|
15
|
+
#
|
|
16
|
+
# This association says that this class contains a foreign pointer column
|
|
17
|
+
# which references a different class. Utilizing the `belongs_to` method in
|
|
18
|
+
# defining a property in a Parse::Object subclass sets up an association
|
|
19
|
+
# between the local table and a foreign table. Specifying the `belongs_to`
|
|
20
|
+
# in the class, tells the framework that the Parse table contains a local
|
|
21
|
+
# column in its schema that has a reference to a record in a foreign table.
|
|
22
|
+
# The argument to `belongs_to` should be the singularized version of the
|
|
23
|
+
# foreign Parse::Object class. you should specify the foreign table as the
|
|
24
|
+
# snake_case singularized version of the foreign table class.
|
|
25
|
+
#
|
|
26
|
+
# Note that the reverse relationship on the foreign class is not generated automatically.
|
|
27
|
+
# You can use a `has_one` on the foreign model to create it.
|
|
28
|
+
# @example
|
|
29
|
+
# class Author < Parse::Object
|
|
30
|
+
# property :name
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
#
|
|
34
|
+
# class Post < Parse::Object
|
|
35
|
+
# belongs_to :author
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# Post.references # => {:author=>"Author"}
|
|
39
|
+
#
|
|
40
|
+
# post = Post.first
|
|
41
|
+
# post.author? # => true if has a pointer
|
|
42
|
+
#
|
|
43
|
+
# # Follow the author pointer and get name
|
|
44
|
+
# post.author.name
|
|
45
|
+
#
|
|
46
|
+
# other_author = Author.first
|
|
47
|
+
# # change author by setting new pointer
|
|
48
|
+
# post.author = other_author
|
|
49
|
+
# post.save
|
|
50
|
+
#
|
|
51
|
+
# @see Parse::Associations::HasOne
|
|
52
|
+
# @see Parse::Associations::HasMany
|
|
53
|
+
module BelongsTo
|
|
54
|
+
|
|
55
|
+
# @!attribute [rw] self.references
|
|
56
|
+
# A hash mapping of all belongs_to associations for this model.
|
|
57
|
+
# @return [Hash]
|
|
58
|
+
|
|
59
|
+
# @!method self.belongs_to(key, opts = {})
|
|
60
|
+
# Creates a one-to-one association with another Parse model.
|
|
61
|
+
# @param [Symbol] key The singularized version of the foreign class and the name of the
|
|
62
|
+
# local column in the remote Parse table where the pointer is stored.
|
|
63
|
+
# @option opts [Symbol] :field override the name of the remote column
|
|
64
|
+
# where the pointer is stored. By default this is inferred as
|
|
65
|
+
# the columnized of the key parameter.
|
|
66
|
+
# @option opts [Symbol] :as override the inferred Parse::Object subclass.
|
|
67
|
+
# By default this is inferred as the singularized camel case version of
|
|
68
|
+
# the key parameter. This option allows you to override the typecast of
|
|
69
|
+
# foreign Parse model of the association, while allowing you to have a
|
|
70
|
+
# different accessor name.
|
|
71
|
+
# @option opts [Boolean] :required Setting to `true`, automatically creates
|
|
72
|
+
# an ActiveModel validation of `validates_presence_of` for the
|
|
73
|
+
# association. This will not prevent the save, but affects the validation
|
|
74
|
+
# check when `valid?` is called on an instance. Default is false.
|
|
75
|
+
# @example
|
|
76
|
+
# # Assumes 'Artist' is foreign class.
|
|
77
|
+
# belongs_to :artist
|
|
78
|
+
#
|
|
79
|
+
# # uses Parse::User as foreign class
|
|
80
|
+
# belongs_to :manager, as: :user
|
|
81
|
+
#
|
|
82
|
+
# # sets attribute name to `featured_song` for foreign class Song with the remote
|
|
83
|
+
# # column name in Parse as 'theFeaturedSong'.
|
|
84
|
+
# belongs_to :featured_song, as: :song, field: :theFeaturedSong
|
|
85
|
+
#
|
|
86
|
+
# @see String#columnize
|
|
87
|
+
# @see #key?
|
|
88
|
+
# @return [Parse::Object] a Parse::Object subclass when using the accessor
|
|
89
|
+
# when fetching the association.
|
|
90
|
+
|
|
91
|
+
# @!method key?
|
|
92
|
+
# A dynamically generated method based on the value of `key` passed to the
|
|
93
|
+
# belongs_to method, which returns true if this instance has a pointer for
|
|
94
|
+
# this field.
|
|
95
|
+
# @example
|
|
96
|
+
#
|
|
97
|
+
# class Post < Parse::Object
|
|
98
|
+
# belongs_to :author # generates 'author?'
|
|
99
|
+
# end
|
|
100
|
+
#
|
|
101
|
+
# post = Post.new
|
|
102
|
+
# post.author? # => false
|
|
103
|
+
# post.author = Author.new
|
|
104
|
+
# post.author? # => true
|
|
105
|
+
# @return [Boolean] true if field contains a Parse::Pointer or subclass.
|
|
106
|
+
|
|
107
|
+
# @!visibility private
|
|
108
|
+
def self.included(base)
|
|
109
|
+
base.extend(ClassMethods)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# @!visibility private
|
|
113
|
+
module ClassMethods
|
|
114
|
+
attr_writer :references
|
|
115
|
+
# We can keep references to all "belong_to" properties
|
|
116
|
+
def references
|
|
117
|
+
@references ||= {}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# These items are added as attributes with the special data type of :pointer
|
|
121
|
+
def belongs_to(key, opts = {})
|
|
122
|
+
opts = { as: key, field: key.to_s.camelize(:lower), required: false }.merge(opts)
|
|
123
|
+
# `opts[:class_name]` is the explicit target Parse class name; it takes
|
|
124
|
+
# precedence over the legacy `as: :symbol` shorthand (where the
|
|
125
|
+
# symbol is converted to a class name via `.to_parse_class`). The
|
|
126
|
+
# references map needs the real target class so `RelationGraph` and
|
|
127
|
+
# `Parse::Agent::Tools.assert_include_paths_accessible!` can resolve
|
|
128
|
+
# pointer paths to their model classes.
|
|
129
|
+
klassName = opts[:class_name] || opts[:as].to_parse_class
|
|
130
|
+
parse_field = opts[:field].to_sym
|
|
131
|
+
|
|
132
|
+
ivar = :"@#{key}"
|
|
133
|
+
will_change_method = :"#{key}_will_change!"
|
|
134
|
+
set_attribute_method = :"#{key}_set_attribute!"
|
|
135
|
+
|
|
136
|
+
if self.fields[key].present? && Parse::Properties::BASE_FIELD_MAP[key].nil?
|
|
137
|
+
warn "Belongs relation #{self}##{key} already defined with type #{klassName}"
|
|
138
|
+
return false
|
|
139
|
+
end
|
|
140
|
+
if self.fields[parse_field].present?
|
|
141
|
+
warn "Alias belongs_to #{self}##{parse_field} conflicts with previously defined property."
|
|
142
|
+
return false
|
|
143
|
+
end
|
|
144
|
+
# store this attribute in the attributes hash with the proper remote column name.
|
|
145
|
+
# we know the type is pointer.
|
|
146
|
+
self.attributes.merge!(parse_field => :pointer)
|
|
147
|
+
# Add them to our list of pointer references
|
|
148
|
+
self.references.merge!(parse_field => klassName)
|
|
149
|
+
# Add them to the list of fields in our class model
|
|
150
|
+
self.fields.merge!(key => :pointer, parse_field => :pointer)
|
|
151
|
+
# Mapping between local attribute name and the remote column name
|
|
152
|
+
self.field_map.merge!(key => parse_field)
|
|
153
|
+
|
|
154
|
+
# used for dirty tracking
|
|
155
|
+
define_attribute_methods key
|
|
156
|
+
|
|
157
|
+
# validations
|
|
158
|
+
validates_presence_of(key) if opts[:required]
|
|
159
|
+
|
|
160
|
+
# We generate the getter method
|
|
161
|
+
# Store the key and class name for N+1 detection
|
|
162
|
+
association_key = key
|
|
163
|
+
owner_class_name = self.name
|
|
164
|
+
|
|
165
|
+
define_method(key) do
|
|
166
|
+
val = instance_variable_get ivar
|
|
167
|
+
# We provide autofetch functionality. If the value is nil and the
|
|
168
|
+
# current Parse::Object is a pointer, or if this is a selectively fetched
|
|
169
|
+
# object and this field wasn't included in the fetch, then auto fetch it.
|
|
170
|
+
should_autofetch = val.nil? && (pointer? || (has_selective_keys? && !field_was_fetched?(association_key)))
|
|
171
|
+
if should_autofetch
|
|
172
|
+
# If autofetch is disabled and we're accessing an unfetched field on a
|
|
173
|
+
# selectively fetched object, raise an error to make the issue explicit
|
|
174
|
+
if autofetch_disabled? && has_selective_keys? && !field_was_fetched?(association_key)
|
|
175
|
+
raise Parse::UnfetchedFieldAccessError.new(association_key, self.class.name)
|
|
176
|
+
end
|
|
177
|
+
autofetch!(association_key)
|
|
178
|
+
val = instance_variable_get ivar
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# if for some reason we retrieved either from store or fetching a
|
|
182
|
+
# hash, lets try to build a Pointer of that type.
|
|
183
|
+
|
|
184
|
+
if val.is_a?(Hash) && (val["__type"] == "Pointer" || val["__type"] == "Object")
|
|
185
|
+
# Get nested fetched keys for this field if available
|
|
186
|
+
nested_keys = nested_keys_for(association_key)
|
|
187
|
+
# Always trust the declared klassName — never the className the
|
|
188
|
+
# server (or attacker-controlled mass assignment) supplied. This
|
|
189
|
+
# prevents type confusion where a pointer to a different class
|
|
190
|
+
# (e.g. _Session or _Role) gets shoved into a typed slot.
|
|
191
|
+
incoming_class = val[Parse::Model::KEY_CLASS_NAME]
|
|
192
|
+
if incoming_class && incoming_class != klassName
|
|
193
|
+
warn "[#{self.class}] belongs_to :#{association_key} expected className=#{klassName.inspect}, ignoring incoming className=#{incoming_class.inspect}"
|
|
194
|
+
end
|
|
195
|
+
val = Parse::Object.build val, klassName, fetched_keys: nested_keys
|
|
196
|
+
instance_variable_set ivar, val
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Track association source for N+1 detection when returning an unfetched pointer
|
|
200
|
+
# Uses a registry instead of setting instance variables on the pointer object
|
|
201
|
+
if val.is_a?(Parse::Pointer) && val.pointer? && Parse.warn_on_n_plus_one
|
|
202
|
+
Parse::NPlusOneDetector.register_source(val,
|
|
203
|
+
source_class: owner_class_name,
|
|
204
|
+
association: association_key)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
val
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
if self.method_defined?("#{key}?")
|
|
211
|
+
warn "Creating belongs_to helper :#{key}?. Will overwrite existing method #{self}##{key}?."
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
define_method("#{key}?") do
|
|
215
|
+
self.send(key).is_a?(Parse::Pointer)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# A proxy setter method that has dirty tracking enabled.
|
|
219
|
+
define_method("#{key}=") do |val|
|
|
220
|
+
send set_attribute_method, val, true
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# We only support pointers, either by object or by transforming a hash.
|
|
224
|
+
define_method(set_attribute_method) do |val, track = true|
|
|
225
|
+
if val == Parse::Properties::DELETE_OP
|
|
226
|
+
val = nil
|
|
227
|
+
elsif val.is_a?(Hash) && (val["__type"] == "Pointer" || val["__type"] == "Object")
|
|
228
|
+
# Get nested fetched keys for this field if available
|
|
229
|
+
nested_keys = nested_keys_for(key)
|
|
230
|
+
# Always trust declared klassName over incoming hash className.
|
|
231
|
+
incoming_class = val[Parse::Model::KEY_CLASS_NAME]
|
|
232
|
+
if incoming_class && incoming_class != klassName
|
|
233
|
+
warn "[#{self.class}] belongs_to :#{key} expected className=#{klassName.inspect}, ignoring incoming className=#{incoming_class.inspect}"
|
|
234
|
+
end
|
|
235
|
+
val = Parse::Object.build val, klassName, fetched_keys: nested_keys
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
if track == true
|
|
239
|
+
prepare_for_dirty_tracking!(key)
|
|
240
|
+
send will_change_method unless val == instance_variable_get(ivar)
|
|
241
|
+
else
|
|
242
|
+
# During fetch (track=false), preserve existing embedded objects if the server
|
|
243
|
+
# only returned a pointer. This prevents autofetch from wiping out nested
|
|
244
|
+
# fetched data (e.g., user.first_name) when fetching unfetched fields.
|
|
245
|
+
existing = instance_variable_get(ivar)
|
|
246
|
+
if existing.is_a?(Parse::Pointer) && val.is_a?(Parse::Pointer) &&
|
|
247
|
+
existing.id == val.id && !existing.pointer? && val.pointer?
|
|
248
|
+
# Existing object has embedded data, new value is just a pointer with same ID
|
|
249
|
+
# Preserve the existing richer object
|
|
250
|
+
val = existing
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Never set an object that is not a Parse::Pointer
|
|
255
|
+
if val.nil? || val.is_a?(Parse::Pointer)
|
|
256
|
+
instance_variable_set(ivar, val)
|
|
257
|
+
else
|
|
258
|
+
warn "[#{self.class}] Invalid value #{val} set for belongs_to field #{key}"
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
# don't create method aliases if the fields are the same
|
|
262
|
+
return if parse_field.to_sym == key.to_sym
|
|
263
|
+
|
|
264
|
+
if self.method_defined?(parse_field) == false
|
|
265
|
+
alias_method parse_field, key
|
|
266
|
+
alias_method "#{parse_field}=", "#{key}="
|
|
267
|
+
alias_method "#{parse_field}_set_attribute!", set_attribute_method
|
|
268
|
+
elsif parse_field.to_sym != :objectId
|
|
269
|
+
warn "Alias belongs_to method #{self}##{parse_field} already defined."
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end # ClassMethod
|
|
273
|
+
end #BelongsTo
|
|
274
|
+
end #Associations
|
|
275
|
+
end
|