Module: Parse::Properties
- Included in:
- Object
- Defined in:
- lib/parse/model/core/properties.rb
Overview
This module provides support for handling all the different types of column data types supported in Parse and mapping them between their remote names with their local ruby named attributes.
Defined Under Namespace
Modules: ClassMethods
Constant Summary collapse
- TYPES =
These are the base types supported by Parse.
[:string, :relation, :integer, :float, :boolean, :date, :array, :file, :geopoint, :bytes, :object, :acl, :timezone].freeze
- BASE =
These are the base mappings of the remote field name types.
{ objectId: :string, createdAt: :date, updatedAt: :date, ACL: :acl }.freeze
- BASE_KEYS =
The list of properties that are part of all objects
[:id, :created_at, :updated_at].freeze
- BASE_FIELD_MAP =
Default hash map of local attribute name to remote column name
{ id: :objectId, created_at: :createdAt, updated_at: :updatedAt, acl: :ACL }.freeze
- CORE_FIELDS =
The delete operation hash.
{ id: :string, created_at: :date, updated_at: :date, acl: :acl }.freeze
- DELETE_OP =
The delete operation hash.
{ "__op" => "Delete" }.freeze
Instance Method Summary collapse
- #apply_attributes!(hash, dirty_track: false) ⇒ Hash
support for setting a hash of attributes on the object with a given dirty tracking value if dirty_track: is set to false (default), attributes are set without dirty tracking.
- #attribute_changes? ⇒ Boolean
True if any of the attributes have changed.
- #attribute_updates(include_all = false) ⇒ Hash
Returns a hash of attributes for properties that have changed.
- #attributes ⇒ Hash
TODO: We can optimize.
- #attributes=(hash) ⇒ Hash
Supports mass assignment of attributes.
- #field_map ⇒ Hash
A hash mapping of all property fields and their types.
- #fields(type = nil) ⇒ Object
Returns the list of fields.
- #format_operation(key, val, data_type) ⇒ Object
Returns a formatted value based on the operation hash and data_type of the property.
- #format_value(key, val, data_type = nil) ⇒ Object
this method takes an input value and transforms it to the proper local format depending on the data type that was set for a particular property key.
Instance Method Details
#apply_attributes!(hash, dirty_track: false) ⇒ Hash
support for setting a hash of attributes on the object with a given dirty tracking value if dirty_track: is set to false (default), attributes are set without dirty tracking. Allos mass assignment of properties with a provided hash.
449 450 451 452 453 454 455 456 457 | # File 'lib/parse/model/core/properties.rb', line 449 def apply_attributes!(hash, dirty_track: false) return unless hash.is_a?(Hash) @id ||= hash[Parse::Model::ID] || hash[Parse::Model::OBJECT_ID] || hash[:objectId] hash.each do |key, value| method = "#{key}_set_attribute!".freeze send(method, value, dirty_track) if respond_to?(method) end end |
#attribute_changes? ⇒ Boolean
Returns true if any of the attributes have changed.
493 494 495 496 497 | # File 'lib/parse/model/core/properties.rb', line 493 def attribute_changes? changed.any? do |key| fields[key.to_sym].present? end end |
#attribute_updates(include_all = false) ⇒ Hash
Returns a hash of attributes for properties that have changed. This will not include any of the base attributes (ex. id, created_at, etc). This method helps generate the change payload that will be sent when saving objects to Parse.
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | # File 'lib/parse/model/core/properties.rb', line 474 def attribute_updates(include_all = false) # TODO: Replace this algorithm with reduce() h = {} changed.each do |key| key = key.to_sym next if include_all == false && Parse::Properties::BASE_KEYS.include?(key) next unless fields[key].present? remote_field = self.field_map[key] || key h[remote_field] = send key h[remote_field] = { __op: :Delete } if h[remote_field].nil? # in the case that the field is a Parse object, generate a pointer # if it is a Parse::PointerCollectionProxy, then make sure we get a list of pointers. h[remote_field] = h[remote_field].parse_pointers if h[remote_field].is_a?(Parse::PointerCollectionProxy) h[remote_field] = h[remote_field].pointer if h[remote_field].respond_to?(:pointer) end h end |
#attributes ⇒ Hash
TODO: We can optimize
439 440 441 | # File 'lib/parse/model/core/properties.rb', line 439 def attributes { __type: :string, :className => :string }.merge!(self.class.attributes) end |
#attributes=(hash) ⇒ Hash
Supports mass assignment of attributes
461 462 463 464 465 466 | # File 'lib/parse/model/core/properties.rb', line 461 def attributes=(hash) return unless hash.is_a?(Hash) # - [:id, :objectId] # only overwrite @id if it hasn't been set. apply_attributes!(hash, dirty_track: true) end |
#field_map ⇒ Hash
Returns a hash mapping of all property fields and their types.
428 429 430 | # File 'lib/parse/model/core/properties.rb', line 428 def field_map self.class.field_map end |
#fields(type = nil) ⇒ Object
Returns the list of fields
433 434 435 | # File 'lib/parse/model/core/properties.rb', line 433 def fields(type = nil) self.class.fields(type) end |
#format_operation(key, val, data_type) ⇒ Object
Returns a formatted value based on the operation hash and data_type of the property. For some values in Parse, they are specified as operation hashes which could include Add, Remove, Delete, AddUnique and Increment.
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | # File 'lib/parse/model/core/properties.rb', line 506 def format_operation(key, val, data_type) return val unless val.is_a?(Hash) && val["__op"].present? op = val["__op"] ivar = :"@#{key}" #handles delete case otherwise 'null' shows up in column if "Delete" == op val = nil elsif "Add" == op && data_type == :array val = (instance_variable_get(ivar) || []).to_a + (val["objects"] || []) elsif "Remove" == op && data_type == :array val = (instance_variable_get(ivar) || []).to_a - (val["objects"] || []) elsif "AddUnique" == op && data_type == :array objects = (val["objects"] || []).uniq original_items = (instance_variable_get(ivar) || []).to_a objects.reject! { |r| original_items.include?(r) } val = original_items + objects elsif "Increment" == op && data_type == :integer || data_type == :integer # for operations that increment by a certain amount, they come as a hash val = (instance_variable_get(ivar) || 0) + (val["amount"] || 0).to_i end val end |
#format_value(key, val, data_type = nil) ⇒ Object
this method takes an input value and transforms it to the proper local format depending on the data type that was set for a particular property key. Return the internal representation of a property value for a given data type.
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 | # File 'lib/parse/model/core/properties.rb', line 536 def format_value(key, val, data_type = nil) # if data_type wasn't passed, then get the data_type from the fields hash data_type ||= self.fields[key] val = format_operation(key, val, data_type) case data_type when :object val = val.with_indifferent_access if val.is_a?(Hash) when :array # All "array" types use a collection proxy val = val.to_a if val.is_a?(Parse::CollectionProxy) #all objects must be in array form val = [val] unless val.is_a?(Array) #all objects must be in array form val.compact! #remove any nil val = Parse::CollectionProxy.new val, delegate: self, key: key when :geopoint val = Parse::GeoPoint.new(val) unless val.blank? when :file val = Parse::File.new(val) unless val.blank? when :bytes val = Parse::Bytes.new(val) unless val.blank? when :integer if val.nil? || val.respond_to?(:to_i) == false val = nil else val = val.to_i end when :boolean if val.nil? val = nil else val = val ? true : false end when :string val = val.to_s unless val.blank? when :float val = val.to_f unless val.blank? when :acl # ACL types go through a special conversion val = ACL.typecast(val, self) when :date # if it respond to parse_date, then use that as the conversion. if val.respond_to?(:parse_date) && val.is_a?(Parse::Date) == false val = val.parse_date # if the value is a hash, then it may be the Parse hash format for an iso date. elsif val.is_a?(Hash) # val.respond_to?(:iso8601) val = Parse::Date.parse(val["iso"] || val[:iso]) elsif val.is_a?(String) # if it's a string, try parsing the date val = Parse::Date.parse val #elsif val.present? # pus "[Parse::Stack] Invalid date value '#{val}' assigned to #{self.class}##{key}, it should be a Parse::Date or DateTime." # raise ValueError, "Invalid date value '#{val}' assigned to #{self.class}##{key}, it should be a Parse::Date or DateTime." end when :timezone val = Parse::TimeZone.new(val) if val.present? else # You can provide a specific class instead of a symbol format if data_type.respond_to?(:typecast) val = data_type.typecast(val) else warn "Property :#{key}: :#{data_type} has no valid data type" val = val #default end end val end |