<commit_before>require 'parse/protocol'
require 'parse/client'
require 'parse/error'

module Parse

  # Represents an individual Parse API object.
  class Object < Hash
    attr_reader :parse_object_id
    attr_reader :class_name
    attr_reader :created_at
    attr_reader :updated_at
    alias :id :parse_object_id

    def initialize(class_name, data = nil)
      @class_name = class_name
      @op_fields = {}
      if data
        parse data
      end
    end

    def eql?(other)
      Parse.object_pointer_equality?(self, other)
    end

    alias == eql?

    def hash
      Parse.object_pointer_hash(self)
    end

    def uri
      Protocol.class_uri @class_name, @parse_object_id
    end

    def pointer
      Parse::Pointer.new(rest_api_hash) unless new?
    end

    # make it easier to deal with the ambiguity of whether you're passed a pointer or object
    def get
      self
    end

    def new?
      self["objectId"].nil?
    end

    # Write the current state of the local object to the API.
    # If the object has never been saved before, this will create
    # a new object, otherwise it will update the existing stored object.
    def save
      if @parse_object_id
        method = :put
        self.merge!(@op_fields) # use operations instead of our own view of the columns
      else
        method = :post
      end

      body = safe_hash.to_json
      data = Parse.client.request(self.uri, method, body)

      if data
        # array operations can return mutated view of array which needs to be parsed
        parse Parse.parse_json(class_name, data)
      end

      if @class_name == Parse::Protocol::CLASS_USER
        self.delete("password")
        self.delete(:username)
        self.delete(:password)
      end

      self
    end

    # representation of object to send on saves
    def safe_hash
      Hash[self.map do |key, value|
        if Protocol::RESERVED_KEYS.include?(key)
          nil
        elsif value.is_a?(Hash) && value[Protocol::KEY_TYPE] == Protocol::TYPE_RELATION
          nil
        elsif value.nil?
          [key, Protocol::DELETE_OP]
        else
          [key, Parse.pointerize_value(value)]
        end
      end.compact]
    end

    # full REST api representation of object
    def rest_api_hash
      self.merge(Parse::Protocol::KEY_CLASS_NAME => class_name)
    end

    def to_h(*a)
      Hash[rest_api_hash.map do |key, value|
        [key, value.respond_to?(:to_h) ? value.to_h : value]
      end]
    end
    alias :as_json :to_h

    def to_json(*a)
      to_h.to_json(*a)
    end

    def to_s
      "#{@class_name}:#{@parse_object_id} #{super}"
    end

    def inspect
      "#{@class_name}:#{@parse_object_id} #{super}"
    end

    # Update the fields of the local Parse object with the current
    # values from the API.
    def refresh
      if @parse_object_id
        data = Parse.get @class_name, @parse_object_id
        clear
        if data
          parse data
        end
      end

      self
    end

    # Delete the remote Parse API object.
    def parse_delete
      if @parse_object_id<commit_msg>don't just return self from to_hash<commit_after>require 'parse/protocol'
require 'parse/client'
require 'parse/error'

module Parse

  # Represents an individual Parse API object.
  class Object < Hash
    attr_reader :parse_object_id
    attr_reader :class_name
    attr_reader :created_at
    attr_reader :updated_at
    alias :id :parse_object_id

    def initialize(class_name, data = nil)
      @class_name = class_name
      @op_fields = {}
      if data
        parse data
      end
    end

    def eql?(other)
      Parse.object_pointer_equality?(self, other)
    end

    alias == eql?

    def hash
      Parse.object_pointer_hash(self)
    end

    def uri
      Protocol.class_uri @class_name, @parse_object_id
    end

    def pointer
      Parse::Pointer.new(rest_api_hash) unless new?
    end

    # make it easier to deal with the ambiguity of whether you're passed a pointer or object
    def get
      self
    end

    def new?
      self["objectId"].nil?
    end

    # Write the current state of the local object to the API.
    # If the object has never been saved before, this will create
    # a new object, otherwise it will update the existing stored object.
    def save
      if @parse_object_id
        method = :put
        self.merge!(@op_fields) # use operations instead of our own view of the columns
      else
        method = :post
      end

      body = safe_hash.to_json
      data = Parse.client.request(self.uri, method, body)

      if data
        # array operations can return mutated view of array which needs to be parsed
        parse Parse.parse_json(class_name, data)
      end

      if @class_name == Parse::Protocol::CLASS_USER
        self.delete("password")
        self.delete(:username)
        self.delete(:password)
      end

      self
    end

    # representation of object to send on saves
    def safe_hash
      Hash[self.map do |key, value|
        if Protocol::RESERVED_KEYS.include?(key)
          nil
        elsif value.is_a?(Hash) && value[Protocol::KEY_TYPE] == Protocol::TYPE_RELATION
          nil
        elsif value.nil?
          [key, Protocol::DELETE_OP]
        else
          [key, Parse.pointerize_value(value)]
        end
      end.compact]
    end

    # full REST api representation of object
    def rest_api_hash
      self.merge(Parse::Protocol::KEY_CLASS_NAME => class_name)
    end

    def to_h(*a)
      Hash[rest_api_hash.map do |key, value|
        [key, value.respond_to?(:to_h) ? value.to_h : value]
      end]
    end
    alias :as_json :to_h
    alias :to_hash :to_h

    def to_json(*a)
      to_h.to_json(*a)
    end

    def to_s
      "#{@class_name}:#{@parse_object_id} #{super}"
    end

    def inspect
      "#{@class_name}:#{@parse_object_id} #{super}"
    end

    # Update the fields of the local Parse object with the current
    # values from the API.
    def refresh
      if @parse_object_id
        data = Parse.get @class_name, @parse_object_id
        clear
        if data
          parse data
        end
      end

      self
    end

    # Delete the remote Parse API object.
    def parse_delete
      if @parse_object_id
{'fraction_non_alphanumeric': 0.07640557424315234, 'fraction_numerical': 0.0, 'mean_word_length': 2.22687338501292, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3175269', 'n_tokens_mistral': 1921, 'n_tokens_neox': 1879, 'n_words': 585}