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.
463 464 465 466 467 468 469 470 471 | # File 'lib/parse/model/core/properties.rb', line 463 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.
507 508 509 510 511 | # File 'lib/parse/model/core/properties.rb', line 507 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.
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | # File 'lib/parse/model/core/properties.rb', line 488 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
453 454 455 | # File 'lib/parse/model/core/properties.rb', line 453 def attributes {__type: :string, :className => :string}.merge!(self.class.attributes) end |
#attributes=(hash) ⇒ Hash
Supports mass assignment of attributes
475 476 477 478 479 480 | # File 'lib/parse/model/core/properties.rb', line 475 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.
442 443 444 | # File 'lib/parse/model/core/properties.rb', line 442 def field_map self.class.field_map end |
#fields(type = nil) ⇒ Object
Returns the list of fields
447 448 449 | # File 'lib/parse/model/core/properties.rb', line 447 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.
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 | # File 'lib/parse/model/core/properties.rb', line 519 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.
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 603 604 605 606 607 608 609 610 611 612 613 614 615 | # File 'lib/parse/model/core/properties.rb', line 549 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 |