<commit_before>require 'sandstorm/records/key'

module Sandstorm

  module Records

    # module renamed to avoid ActiveSupport::Concern deprecation warning
    module InstMethods

      def initialize(attributes = {})
        @is_new = true
        @attributes = {}
        attributes.each_pair do |k, v|
          self.send("#{k}=".to_sym, v)
        end

        @association_keys = {}
      end

      def persisted?
        !@is_new
      end

      def load(id)
        self.id = id
        refresh
      end

      def refresh
        # resets AM::Dirty changed state
        @previously_changed.clear unless @previously_changed.nil?
        @changed_attributes.clear unless @changed_attributes.nil?

        attr_types = self.class.attribute_types

        @attributes = {'id' => self.id}

        attrs = nil

        backend.lock(self.class) do
          class_key = self.class.send(:class_key)

          # TODO: check for record existence in backend-agnostic fashion
          @is_new = false

          attr_types = self.class.attribute_types.reject {|k, v| k == :id}

          attrs_to_load = attr_types.collect do |name, type|
            Sandstorm::Records::Key.new(:class => class_key,
              :id => self.id, :name => name, :type => type, :object => :attribute)
          end

          attrs = backend.get_multiple(*attrs_to_load)[class_key][self.id]
        end

        # TODO:? return false unless record_exists

        @attributes.update(attrs) if attrs.present?

        true
      end

      # TODO limit to only those attribute names defined in define_attributes
      def update_attributes(attributes = {})
        attributes.each_pair do |att, v|
          unless value == @attributes[att.to_s]
            @attributes[att.to_s] = v
            send("#{att}_will_change!")
          end
        end
        save
      end

      def save
        return unless self.changed?
        return false unless valid?

        run_callbacks( (self.persisted? ? :update : :create) ) do

          self.id ||= self.class.generate_id

          idx_attrs = self.class.send(:indexed_attributes)

          self.class.transaction do

            self.changes.each_pair do |att, old_new|
              backend.set(attribute_keys[att], old_new.last) unless att.eql?('id')

              next unless idx_attrs.has_key?(att)

              # update indices
              if old_new.first.nil?
                self.class.send("#{att}_index", old_new.last).add_id( @attributes['id'] )
              elsif old_new.last.nil?
                self.class.send("#{att}_index", old_new.first).delete_id( @attributes['id'] )
              else
                self.class.send("#{att}_index", old_new.first).move_id( @attributes['id'],
                                self.class.send("#{att}_index", old_new.last))
              end
            end

            # ids is a set, so update won't create duplicates
            # NB influxdb backend doesn't need this
            self.class.add_id(@attributes['id'])
          end

          @is_new = false
        end

        # AM::Dirty
        @previously_changed = self.changes
        @changed_attributes.clear

        true
      end

      def destroy
        raise "Record was not persisted" if !persisted?

        run_callbacks :destroy do

          assoc_classes = self.class.send(:associated_classes)

          backend.lock(*assoc_classes) do
            self.class.send(:with_associations, self) {|assoc| assoc.send(:on_remove) }
            index_attrs = (self.attributes.keys & self.class.send(:indexed_attributes).keys)<commit_msg>use new AM::Dirty methods if they're available<commit_after>require 'sandstorm/records/key'

module Sandstorm

  module Records

    # module renamed to avoid ActiveSupport::Concern deprecation warning
    module InstMethods

      def initialize(attributes = {})
        @is_new = true
        @attributes = {}
        attributes.each_pair do |k, v|
          self.send("#{k}=".to_sym, v)
        end

        @association_keys = {}
      end

      def persisted?
        !@is_new
      end

      def load(id)
        self.id = id
        refresh
      end

      def refresh
        # AM::Dirty -- private method in 4.1.0+, internal state before that
        if self.respond_to?(:reset_changes, true)
          reset_changes
        else
          @previously_changed.clear unless @previously_changed.nil?
          @changed_attributes.clear
        end

        attr_types = self.class.attribute_types

        @attributes = {'id' => self.id}

        attrs = nil

        backend.lock(self.class) do
          class_key = self.class.send(:class_key)

          # TODO: check for record existence in backend-agnostic fashion
          @is_new = false

          attr_types = self.class.attribute_types.reject {|k, v| k == :id}

          attrs_to_load = attr_types.collect do |name, type|
            Sandstorm::Records::Key.new(:class => class_key,
              :id => self.id, :name => name, :type => type, :object => :attribute)
          end

          attrs = backend.get_multiple(*attrs_to_load)[class_key][self.id]
        end

        # TODO:? return false unless record_exists

        @attributes.update(attrs) if attrs.present?

        true
      end

      # TODO limit to only those attribute names defined in define_attributes
      def update_attributes(attributes = {})
        attributes.each_pair do |att, v|
          unless value == @attributes[att.to_s]
            @attributes[att.to_s] = v
            send("#{att}_will_change!")
          end
        end
        save
      end

      def save
        return unless self.changed?
        return false unless valid?

        run_callbacks( (self.persisted? ? :update : :create) ) do

          self.id ||= self.class.generate_id

          idx_attrs = self.class.send(:indexed_attributes)

          self.class.transaction do

            self.changes.each_pair do |att, old_new|
              backend.set(attribute_keys[att], old_new.last) unless att.eql?('id')

              next unless idx_attrs.has_key?(att)

              # update indices
              if old_new.first.nil?
                self.class.send("#{att}_index", old_new.last).add_id( @attributes['id'] )
              elsif old_new.last.nil?
                self.class.send("#{att}_index", old_new.first).delete_id( @attributes['id'] )
              else
                self.class.send("#{att}_index", old_new.first).move_id( @attributes['id'],
                                self.class.send("#{att}_index", old_new.last))
              end
            end

            # ids is a set, so update won't create duplicates
            # NB influxdb backend doesn't need this
            self.class.add_id(@attributes['id'])
          end

          @is_new = false
        end

        # AM::Dirty -- private method in 4.1.0+, internal state before that
        if self.respond_to?(:changes_applied, true)
          changes_applied
        else
          @previously_changed = changes
          @changed_attributes.clear
        end

        true
      end

      def destroy
        raise "Record was not persisted" if !persisted?

        run_callbacks :destroy do

          assoc_classes = self.class.send(:associated_classes)

          backend.lock(*assoc_classes) do
            self.class.send(:with_associations, self) {|assoc| assoc.send(:on_remove) }
            index_attrs = (self.attributes.keys & self.class.send(:indexed_attributes).keys)
{'fraction_non_alphanumeric': 0.10193204530313124, 'fraction_numerical': 0.0007994670219853431, 'mean_word_length': 1.916083916083916, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, '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': '4216888', 'n_tokens_mistral': 2174, 'n_tokens_neox': 2071, 'n_words': 494}