sunstone 7.0.0 → 7.2.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 +4 -4
- data/ext/active_record/associations/collection_association.rb +5 -28
- data/ext/active_record/associations.rb +12 -8
- data/ext/active_record/attribute_methods.rb +14 -13
- data/ext/active_record/callbacks.rb +4 -1
- data/ext/active_record/finder_methods.rb +14 -4
- data/ext/active_record/persistence.rb +58 -20
- data/ext/active_record/relation/calculations.rb +27 -7
- data/ext/active_record/relation/query_methods.rb +6 -4
- data/ext/active_record/transactions.rb +15 -13
- data/lib/active_record/connection_adapters/sunstone/column.rb +10 -0
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +58 -21
- data/lib/active_record/connection_adapters/sunstone/quoting.rb +19 -0
- data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +6 -5
- data/lib/active_record/connection_adapters/sunstone/type/binary.rb +3 -3
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +102 -75
- data/lib/arel/visitors/sunstone.rb +69 -58
- data/lib/sunstone/connection.rb +4 -4
- data/lib/sunstone/version.rb +1 -1
- data/lib/sunstone.rb +2 -14
- metadata +14 -13
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d280487f58777eebd36b07eb69f9492b77370ea3def7b05321bb2d4fd8e55626
         | 
| 4 | 
            +
              data.tar.gz: a34f616483aca20b1207f12538e08fafb19b16ac01db6c19977b902cd1cd1537
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 0211de6c05fded268d04e00af2e0f16e9f4ee0650307288ea890c343e1b20f0a2fcf924631e2c0c3e72b602af7e964c8663a6df51f22cce9bd85798b26d12604
         | 
| 7 | 
            +
              data.tar.gz: 62e9b986925a43ca27c172499bca956ea20e6b8ca237d94dbcb1b07f52772ad1ffc9d5a0fe68d9ef6560e9a3df5ccc7bc27a8a78b56aad4fcccc44604f2a9060
         | 
| @@ -1,14 +1,16 @@ | |
| 1 | 
            +
            # The last ref that this code was synced with Rails
         | 
| 2 | 
            +
            # ref: 9269f634d471ad6ca46752421eabd3e1c26220b5
         | 
| 1 3 | 
             
            module ActiveRecord
         | 
| 2 4 | 
             
              module Associations
         | 
| 3 5 | 
             
                class CollectionAssociation
         | 
| 4 6 |  | 
| 5 7 | 
             
                  def replace(other_array)
         | 
| 6 8 | 
             
                    other_array.each { |val| raise_on_type_mismatch!(val) }
         | 
| 7 | 
            -
                    original_target = load_target.dup
         | 
| 9 | 
            +
                    original_target = skip_strict_loading { load_target }.dup
         | 
| 8 10 |  | 
| 9 11 | 
             
                    if owner.new_record?
         | 
| 10 12 | 
             
                      replace_records(other_array, original_target)
         | 
| 11 | 
            -
                    elsif owner.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && owner.instance_variable_defined?(:@ | 
| 13 | 
            +
                    elsif owner.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && owner.instance_variable_defined?(:@sunstone_updating) && owner.instance_variable_get(:@sunstone_updating)
         | 
| 12 14 | 
             
                      replace_common_records_in_memory(other_array, original_target)
         | 
| 13 15 |  | 
| 14 16 | 
             
                      # Remove from target
         | 
| @@ -41,7 +43,7 @@ module ActiveRecord | |
| 41 43 | 
             
                  end
         | 
| 42 44 |  | 
| 43 45 | 
             
                  def insert_record(record, validate = true, raise = false, &block)
         | 
| 44 | 
            -
                    if record.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && owner.instance_variable_defined?(:@ | 
| 46 | 
            +
                    if record.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && owner.instance_variable_defined?(:@sunstone_updating) && owner.instance_variable_get(:@sunstone_updating)
         | 
| 45 47 | 
             
                      true
         | 
| 46 48 | 
             
                    elsif raise
         | 
| 47 49 | 
             
                      record.save!(validate: validate, &block)
         | 
| @@ -50,7 +52,6 @@ module ActiveRecord | |
| 50 52 | 
             
                    end
         | 
| 51 53 | 
             
                  end
         | 
| 52 54 |  | 
| 53 | 
            -
             | 
| 54 55 | 
             
                end
         | 
| 55 56 |  | 
| 56 57 | 
             
                class HasManyThroughAssociation
         | 
| @@ -70,27 +71,3 @@ module ActiveRecord | |
| 70 71 |  | 
| 71 72 | 
             
              end
         | 
| 72 73 | 
             
            end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
            module ActiveRecord
         | 
| 75 | 
            -
              module Persistence
         | 
| 76 | 
            -
                
         | 
| 77 | 
            -
                # Updates the attributes of the model from the passed-in hash and saves the
         | 
| 78 | 
            -
                # record, all wrapped in a transaction. If the object is invalid, the saving
         | 
| 79 | 
            -
                # will fail and false will be returned.
         | 
| 80 | 
            -
                def update(attributes)
         | 
| 81 | 
            -
                  @updating = :updating
         | 
| 82 | 
            -
                  Thread.current[:sunstone_updating_model] = self
         | 
| 83 | 
            -
                  
         | 
| 84 | 
            -
                  # The following transaction covers any possible database side-effects of the
         | 
| 85 | 
            -
                  # attributes assignment. For example, setting the IDs of a child collection.
         | 
| 86 | 
            -
                  with_transaction_returning_status do
         | 
| 87 | 
            -
                    assign_attributes(attributes)
         | 
| 88 | 
            -
                    save
         | 
| 89 | 
            -
                  end
         | 
| 90 | 
            -
                ensure
         | 
| 91 | 
            -
                  @updating = false
         | 
| 92 | 
            -
                  Thread.current[:sunstone_updating_model] = nil
         | 
| 93 | 
            -
                end
         | 
| 94 | 
            -
                
         | 
| 95 | 
            -
              end
         | 
| 96 | 
            -
            end
         | 
| @@ -1,5 +1,9 @@ | |
| 1 | 
            +
            # The last ref that this code was synced with Rails
         | 
| 2 | 
            +
            # ref: 9269f634d471ad6ca46752421eabd3e1c26220b5
         | 
| 3 | 
            +
             | 
| 1 4 | 
             
            require 'active_record'
         | 
| 2 5 | 
             
            require 'active_record/associations'
         | 
| 6 | 
            +
             | 
| 3 7 | 
             
            module ActiveRecord
         | 
| 4 8 | 
             
              module Associations
         | 
| 5 9 | 
             
                module ClassMethods
         | 
| @@ -21,13 +25,13 @@ module ActiveRecord | |
| 21 25 |  | 
| 22 26 | 
             
                    include Module.new {
         | 
| 23 27 | 
             
                      class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            +
                        def destroy_associations
         | 
| 29 | 
            +
                          if !self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
         | 
| 30 | 
            +
                            association(:#{middle_reflection.name}).delete_all(:delete_all)
         | 
| 31 | 
            +
                            association(:#{name}).reset
         | 
| 32 | 
            +
                          end
         | 
| 33 | 
            +
                          super
         | 
| 28 34 | 
             
                        end
         | 
| 29 | 
            -
                        super
         | 
| 30 | 
            -
                      end
         | 
| 31 35 | 
             
                      RUBY
         | 
| 32 36 | 
             
                    }
         | 
| 33 37 |  | 
| @@ -40,8 +44,8 @@ module ActiveRecord | |
| 40 44 | 
             
                    end
         | 
| 41 45 |  | 
| 42 46 | 
             
                    has_many name, scope, **hm_options, &extension
         | 
| 43 | 
            -
                    _reflections[name | 
| 47 | 
            +
                    _reflections[name].parent_reflection = habtm_reflection
         | 
| 44 48 | 
             
                  end
         | 
| 45 49 | 
             
                end
         | 
| 46 50 | 
             
              end
         | 
| 47 | 
            -
            end
         | 
| 51 | 
            +
            end
         | 
| @@ -1,14 +1,15 @@ | |
| 1 | 
            +
            # The last ref that this code was synced with Rails
         | 
| 2 | 
            +
            # ref: 9269f634d471ad6ca46752421eabd3e1c26220b5
         | 
| 3 | 
            +
             | 
| 1 4 | 
             
            module ActiveRecord
         | 
| 2 5 | 
             
              module AttributeMethods
         | 
| 3 | 
            -
             | 
| 6 | 
            +
             | 
| 4 7 | 
             
                protected
         | 
| 5 | 
            -
             | 
| 8 | 
            +
             | 
| 6 9 | 
             
                # Returns a Hash of the Arel::Attributes and attribute values that have been
         | 
| 7 10 | 
             
                # typecasted for use in an Arel insert/update method.
         | 
| 8 11 | 
             
                def attributes_with_values(attribute_names)
         | 
| 9 | 
            -
                  attrs = attribute_names.index_with  | 
| 10 | 
            -
                    _read_attribute(name)
         | 
| 11 | 
            -
                  end
         | 
| 12 | 
            +
                  attrs = attribute_names.index_with { |name| @attributes[name] }
         | 
| 12 13 |  | 
| 13 14 | 
             
                  if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
         | 
| 14 15 | 
             
                    self.class.reflect_on_all_associations.each do |reflection|
         | 
| @@ -25,17 +26,17 @@ module ActiveRecord | |
| 25 26 | 
             
                      end
         | 
| 26 27 | 
             
                    end
         | 
| 27 28 | 
             
                  end
         | 
| 28 | 
            -
             | 
| 29 | 
            +
             | 
| 29 30 | 
             
                  attrs
         | 
| 30 31 | 
             
                end
         | 
| 31 | 
            -
             | 
| 32 | 
            +
             | 
| 32 33 | 
             
                def add_attributes_for_belongs_to_association(reflection, attrs)
         | 
| 33 34 | 
             
                  key = :"add_attributes_for_belongs_to_association_#{reflection.name}"
         | 
| 34 35 | 
             
                  @_already_called ||= {}
         | 
| 35 36 | 
             
                  return if @_already_called[key]
         | 
| 36 37 | 
             
                  @_already_called[key]=true
         | 
| 37 38 | 
             
                  @_already_called[:"autosave_associated_records_for_#{reflection.name}"] = true
         | 
| 38 | 
            -
             | 
| 39 | 
            +
             | 
| 39 40 | 
             
                  association = association_instance_get(reflection.name)
         | 
| 40 41 | 
             
                  record      = association && association.load_target
         | 
| 41 42 | 
             
                  if record && !record.destroyed?
         | 
| @@ -51,14 +52,14 @@ module ActiveRecord | |
| 51 52 | 
             
                    end
         | 
| 52 53 | 
             
                  end
         | 
| 53 54 | 
             
                end
         | 
| 54 | 
            -
             | 
| 55 | 
            +
             | 
| 55 56 | 
             
                def add_attributes_for_has_one_association(reflection, attrs)
         | 
| 56 57 | 
             
                  key = :"add_attributes_for_has_one_association#{reflection.name}"
         | 
| 57 58 | 
             
                  @_already_called ||= {}
         | 
| 58 59 | 
             
                  return if @_already_called[key]
         | 
| 59 60 | 
             
                  @_already_called[key]=true
         | 
| 60 61 | 
             
                  @_already_called[:"autosave_associated_records_for_#{reflection.name}"] = true
         | 
| 61 | 
            -
             | 
| 62 | 
            +
             | 
| 62 63 | 
             
                  association = association_instance_get(reflection.name)
         | 
| 63 64 | 
             
                  record      = association && association.load_target
         | 
| 64 65 |  | 
| @@ -80,7 +81,7 @@ module ActiveRecord | |
| 80 81 | 
             
                    end
         | 
| 81 82 | 
             
                  end
         | 
| 82 83 | 
             
                end
         | 
| 83 | 
            -
             | 
| 84 | 
            +
             | 
| 84 85 | 
             
                def add_attributes_for_collection_association(reflection, attrs, arel_table=nil)
         | 
| 85 86 | 
             
                  key = :"add_attributes_for_collection_association#{reflection.name}"
         | 
| 86 87 | 
             
                  @_already_called ||= {}
         | 
| @@ -106,7 +107,7 @@ module ActiveRecord | |
| 106 107 | 
             
                            )
         | 
| 107 108 | 
             
                        end
         | 
| 108 109 | 
             
                      end
         | 
| 109 | 
            -
             | 
| 110 | 
            +
             | 
| 110 111 | 
             
                      association.instance_variable_set(:@sunstone_changed, false)
         | 
| 111 112 | 
             
                    end
         | 
| 112 113 |  | 
| @@ -114,6 +115,6 @@ module ActiveRecord | |
| 114 115 | 
             
                    association.reset_scope if association.respond_to?(:reset_scope)
         | 
| 115 116 | 
             
                  end
         | 
| 116 117 | 
             
                end
         | 
| 117 | 
            -
             | 
| 118 | 
            +
             | 
| 118 119 | 
             
              end
         | 
| 119 120 | 
             
            end
         | 
| @@ -1,14 +1,24 @@ | |
| 1 | 
            +
            # The last ref that this code was synced with Rails
         | 
| 2 | 
            +
            # ref: 9269f634d471ad6ca46752421eabd3e1c26220b5
         | 
| 3 | 
            +
             | 
| 1 4 | 
             
            module ActiveRecord
         | 
| 2 5 | 
             
              class PredicateBuilder # :nodoc:
         | 
| 3 6 |  | 
| 4 7 | 
             
                def expand_from_hash(attributes, &block)
         | 
| 5 8 | 
             
                  return ["1=0"] if attributes.empty?
         | 
| 6 | 
            -
             | 
| 9 | 
            +
             | 
| 7 10 | 
             
                  attributes.flat_map do |key, value|
         | 
| 8 | 
            -
                    if  | 
| 11 | 
            +
                    if key.is_a?(Array)
         | 
| 12 | 
            +
                      queries = Array(value).map do |ids_set|
         | 
| 13 | 
            +
                        raise ArgumentError, "Expected corresponding value for #{key} to be an Array" unless ids_set.is_a?(Array)
         | 
| 14 | 
            +
                        expand_from_hash(key.zip(ids_set).to_h)
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                      grouping_queries(queries)
         | 
| 17 | 
            +
                    elsif value.is_a?(Hash) && !table.has_column?(key)
         | 
| 9 18 | 
             
                      ka = table.associated_table(key, &block)
         | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 19 | 
            +
                        .predicate_builder.expand_from_hash(value.stringify_keys)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                      if self.table.instance_variable_get(:@klass).connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
         | 
| 12 22 | 
             
                        ka.each { |k|
         | 
| 13 23 | 
             
                          if k.left.is_a?(Arel::Attributes::Attribute) || k.left.is_a?(Arel::Attributes::Relation)
         | 
| 14 24 | 
             
                            k.left = Arel::Attributes::Relation.new(k.left, key)
         | 
| @@ -6,10 +6,12 @@ module ActiveRecord | |
| 6 6 | 
             
                  def rpc(name)
         | 
| 7 7 | 
             
                    define_method("#{name}!") do
         | 
| 8 8 | 
             
                      req = Net::HTTP::Post.new("/#{self.class.table_name}/#{CGI.escape(id.to_s)}/#{CGI.escape(name.to_s)}")
         | 
| 9 | 
            -
                      self.class.connection. | 
| 10 | 
            -
                         | 
| 11 | 
            -
                           | 
| 12 | 
            -
                             | 
| 9 | 
            +
                      self.class.connection.send(:with_raw_connection) do |conn|
         | 
| 10 | 
            +
                        conn.send_request(req) do |response|
         | 
| 11 | 
            +
                          JSON.parse(response.body).each do |k,v|
         | 
| 12 | 
            +
                            if self.class.column_names.include?(k)
         | 
| 13 | 
            +
                              @attributes.write_from_database(k, v)
         | 
| 14 | 
            +
                            end
         | 
| 13 15 | 
             
                          end
         | 
| 14 16 | 
             
                        end
         | 
| 15 17 | 
             
                      end
         | 
| @@ -17,7 +19,25 @@ module ActiveRecord | |
| 17 19 | 
             
                    end
         | 
| 18 20 | 
             
                  end
         | 
| 19 21 | 
             
                end
         | 
| 20 | 
            -
             | 
| 22 | 
            +
             | 
| 23 | 
            +
                # Updates the attributes of the model from the passed-in hash and saves the
         | 
| 24 | 
            +
                # record, all wrapped in a transaction. If the object is invalid, the saving
         | 
| 25 | 
            +
                # will fail and false will be returned.
         | 
| 26 | 
            +
                def update(attributes)
         | 
| 27 | 
            +
                  @sunstone_updating = :updating
         | 
| 28 | 
            +
                  Thread.current[:sunstone_updating_model] = self
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  # The following transaction covers any possible database side-effects of the
         | 
| 31 | 
            +
                  # attributes assignment. For example, setting the IDs of a child collection.
         | 
| 32 | 
            +
                  with_transaction_returning_status do
         | 
| 33 | 
            +
                    assign_attributes(attributes)
         | 
| 34 | 
            +
                    save
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                ensure
         | 
| 37 | 
            +
                  @sunstone_updating = false
         | 
| 38 | 
            +
                  Thread.current[:sunstone_updating_model] = nil
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 21 41 | 
             
                def update!(attributes)
         | 
| 22 42 | 
             
                  @no_save_transaction = true
         | 
| 23 43 | 
             
                  with_transaction_returning_status do
         | 
| @@ -33,14 +53,14 @@ module ActiveRecord | |
| 33 53 | 
             
                def create_or_update(**, &block)
         | 
| 34 54 | 
             
                  _raise_readonly_record_error if readonly?
         | 
| 35 55 | 
             
                  return false if destroyed?
         | 
| 36 | 
            -
             | 
| 37 | 
            -
                  @ | 
| 56 | 
            +
             | 
| 57 | 
            +
                  @sunstone_updating = new_record? ? :creating : :updating
         | 
| 38 58 | 
             
                  Thread.current[:sunstone_updating_model] = self
         | 
| 39 59 |  | 
| 40 60 | 
             
                  result = new_record? ? _create_record(&block) : _update_record(&block)
         | 
| 41 61 |  | 
| 42 62 | 
             
                  if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && result != 0
         | 
| 43 | 
            -
                    row_hash = result | 
| 63 | 
            +
                    row_hash = result[0]
         | 
| 44 64 |  | 
| 45 65 | 
             
                    seen = Hash.new { |h, parent_klass|
         | 
| 46 66 | 
             
                      h[parent_klass] = Hash.new { |i, parent_id|
         | 
| @@ -51,10 +71,13 @@ module ActiveRecord | |
| 51 71 | 
             
                    model_cache = Hash.new { |h,klass| h[klass] = {} }
         | 
| 52 72 | 
             
                    parents = model_cache[self.class.base_class]
         | 
| 53 73 |  | 
| 54 | 
            -
                     | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
                       | 
| 74 | 
            +
                    row_hash.each do |key, value|
         | 
| 75 | 
            +
                      if self.class.column_names.include?(key.to_s)
         | 
| 76 | 
            +
                        _write_attribute(key, value)
         | 
| 77 | 
            +
                      else
         | 
| 78 | 
            +
                        assc = association(key.to_sym)
         | 
| 79 | 
            +
                        assc.reset if assc.reflection.collection? # TODO: can load here if included
         | 
| 80 | 
            +
                      end
         | 
| 58 81 | 
             
                    end
         | 
| 59 82 |  | 
| 60 83 | 
             
                    construct(self, row_hash.select{|k,v| !self.class.column_names.include?(k.to_s) }, seen, model_cache)
         | 
| @@ -72,39 +95,54 @@ module ActiveRecord | |
| 72 95 | 
             
                  end
         | 
| 73 96 | 
             
                  raise ActiveRecord::RecordInvalid
         | 
| 74 97 | 
             
                ensure
         | 
| 75 | 
            -
                  @ | 
| 98 | 
            +
                  @sunstone_updating = false
         | 
| 76 99 | 
             
                  Thread.current[:sunstone_updating_model] = nil
         | 
| 77 100 | 
             
                end
         | 
| 78 | 
            -
             | 
| 101 | 
            +
             | 
| 79 102 | 
             
                # Creates a record with values matching those of the instance attributes
         | 
| 80 103 | 
             
                # and returns its id.
         | 
| 81 104 | 
             
                def _create_record(attribute_names = self.attribute_names)
         | 
| 82 105 | 
             
                  attribute_names = attributes_for_create(attribute_names)
         | 
| 83 | 
            -
                   | 
| 106 | 
            +
                  attribute_values = attributes_with_values(attribute_names)
         | 
| 107 | 
            +
                  returning_values = nil
         | 
| 84 108 |  | 
| 85 | 
            -
                   | 
| 109 | 
            +
                  self.class.with_connection do |connection|
         | 
| 110 | 
            +
                    returning_columns = self.class._returning_columns_for_insert(connection)
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    returning_values = self.class._insert_record(
         | 
| 113 | 
            +
                      connection,
         | 
| 114 | 
            +
                      attribute_values,
         | 
| 115 | 
            +
                      returning_columns
         | 
| 116 | 
            +
                    )
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                    if !self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
         | 
| 119 | 
            +
                      returning_columns.zip(returning_values).each do |column, value|
         | 
| 120 | 
            +
                        _write_attribute(column, value) if !_read_attribute(column)
         | 
| 121 | 
            +
                      end if returning_values
         | 
| 122 | 
            +
                    end
         | 
| 123 | 
            +
                  end
         | 
| 86 124 |  | 
| 87 | 
            -
                  self.id ||= new_id if @primary_key
         | 
| 88 125 | 
             
                  @new_record = false
         | 
| 89 126 | 
             
                  @previously_new_record = true
         | 
| 90 127 |  | 
| 91 128 | 
             
                  yield(self) if block_given?
         | 
| 92 129 |  | 
| 93 130 | 
             
                  if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
         | 
| 94 | 
            -
                     | 
| 131 | 
            +
                    returning_values
         | 
| 95 132 | 
             
                  else
         | 
| 96 133 | 
             
                    id
         | 
| 97 134 | 
             
                  end
         | 
| 98 135 | 
             
                end
         | 
| 99 | 
            -
             | 
| 136 | 
            +
             | 
| 100 137 | 
             
                def _update_record(attribute_names = self.attribute_names)
         | 
| 138 | 
            +
                  attribute_names = attributes_for_update(attribute_names)
         | 
| 101 139 | 
             
                  attribute_values = attributes_with_values(attribute_names)
         | 
| 102 140 |  | 
| 103 141 | 
             
                  if attribute_values.empty?
         | 
| 104 142 | 
             
                    affected_rows = 0
         | 
| 105 143 | 
             
                    @_trigger_update_callback = true
         | 
| 106 144 | 
             
                  else
         | 
| 107 | 
            -
                    affected_rows = self.class._update_record( | 
| 145 | 
            +
                    affected_rows = self.class._update_record(attribute_values, _query_constraints_hash)
         | 
| 108 146 | 
             
                    @_trigger_update_callback = affected_rows == 1
         | 
| 109 147 | 
             
                  end
         | 
| 110 148 |  | 
| @@ -1,11 +1,27 @@ | |
| 1 | 
            +
            # The last ref that this code was synced with Rails
         | 
| 2 | 
            +
            # ref: 9269f634d471ad6ca46752421eabd3e1c26220b5
         | 
| 3 | 
            +
             | 
| 1 4 | 
             
            module ActiveRecord
         | 
| 2 5 | 
             
              module Calculations
         | 
| 3 | 
            -
             | 
| 6 | 
            +
             | 
| 4 7 | 
             
                def pluck(*column_names)
         | 
| 8 | 
            +
                  if @none
         | 
| 9 | 
            +
                    if @async
         | 
| 10 | 
            +
                      return Promise::Complete.new([])
         | 
| 11 | 
            +
                    else
         | 
| 12 | 
            +
                      return []
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 5 16 | 
             
                  if loaded? && all_attributes?(column_names)
         | 
| 6 | 
            -
                     | 
| 17 | 
            +
                    result = records.pluck(*column_names)
         | 
| 18 | 
            +
                    if @async
         | 
| 19 | 
            +
                      return Promise::Complete.new(result)
         | 
| 20 | 
            +
                    else
         | 
| 21 | 
            +
                      return result
         | 
| 22 | 
            +
                    end
         | 
| 7 23 | 
             
                  end
         | 
| 8 | 
            -
             | 
| 24 | 
            +
             | 
| 9 25 | 
             
                  if has_include?(column_names.first)
         | 
| 10 26 | 
             
                    relation = apply_join_dependency
         | 
| 11 27 | 
             
                    relation.pluck(*column_names)
         | 
| @@ -13,18 +29,22 @@ module ActiveRecord | |
| 13 29 | 
             
                    load
         | 
| 14 30 | 
             
                    return records.pluck(*column_names.map{|n| n.to_s.sub(/^#{klass.table_name}\./, "")})
         | 
| 15 31 | 
             
                  else
         | 
| 16 | 
            -
                    klass.disallow_raw_sql!(column_names)
         | 
| 32 | 
            +
                    klass.disallow_raw_sql!(flattened_args(column_names))
         | 
| 17 33 | 
             
                    columns = arel_columns(column_names)
         | 
| 18 34 | 
             
                    relation = spawn
         | 
| 19 35 | 
             
                    relation.select_values = columns
         | 
| 20 36 | 
             
                    result = skip_query_cache_if_necessary do
         | 
| 21 37 | 
             
                      if where_clause.contradiction?
         | 
| 22 | 
            -
                        ActiveRecord::Result.empty
         | 
| 38 | 
            +
                        ActiveRecord::Result.empty(async: @async)
         | 
| 23 39 | 
             
                      else
         | 
| 24 | 
            -
                        klass. | 
| 40 | 
            +
                        klass.with_connection do |c|
         | 
| 41 | 
            +
                          c.select_all(relation.arel, "#{klass.name} Pluck", async: @async)
         | 
| 42 | 
            +
                        end
         | 
| 25 43 | 
             
                      end
         | 
| 26 44 | 
             
                    end
         | 
| 27 | 
            -
                     | 
| 45 | 
            +
                    result.then do |result|
         | 
| 46 | 
            +
                      type_cast_pluck_values(result, columns)
         | 
| 47 | 
            +
                    end
         | 
| 28 48 | 
             
                  end
         | 
| 29 49 | 
             
                end
         | 
| 30 50 |  | 
| @@ -1,9 +1,11 @@ | |
| 1 1 | 
             
            module ActiveRecord
         | 
| 2 2 | 
             
              module QueryMethods
         | 
| 3 3 | 
             
                private
         | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
                   | 
| 4 | 
            +
             | 
| 5 | 
            +
                def assert_modifiable!
         | 
| 6 | 
            +
                  raise UnmodifiableRelation if @loaded
         | 
| 7 | 
            +
                  raise UnmodifiableRelation if @arel && !klass.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 8 10 | 
             
              end
         | 
| 9 11 | 
             
            end
         | 
| @@ -34,23 +34,25 @@ module ActiveRecord | |
| 34 34 | 
             
                # end
         | 
| 35 35 |  | 
| 36 36 | 
             
                def with_transaction_returning_status
         | 
| 37 | 
            -
                   | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
                  if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && instance_variable_defined?(:@updating) && @updating
         | 
| 41 | 
            -
                    status = yield
         | 
| 42 | 
            -
                  else
         | 
| 43 | 
            -
                    ensure_finalize = !connection.transaction_open?
         | 
| 44 | 
            -
                    connection.transaction do
         | 
| 45 | 
            -
                      add_to_transaction(ensure_finalize || has_transactional_callbacks?)
         | 
| 46 | 
            -
                      remember_transaction_record_state
         | 
| 37 | 
            +
                  self.class.with_connection do |connection|
         | 
| 38 | 
            +
                    status = nil
         | 
| 39 | 
            +
                    # connection = self.class.connection
         | 
| 47 40 |  | 
| 41 | 
            +
                    if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && instance_variable_defined?(:@sunstone_updating) && @sunstone_updating
         | 
| 48 42 | 
             
                      status = yield
         | 
| 49 | 
            -
             | 
| 43 | 
            +
                    else
         | 
| 44 | 
            +
                      ensure_finalize = !connection.transaction_open?
         | 
| 45 | 
            +
                      connection.transaction do
         | 
| 46 | 
            +
                        add_to_transaction(ensure_finalize || has_transactional_callbacks?)
         | 
| 47 | 
            +
                        remember_transaction_record_state
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                        status = yield
         | 
| 50 | 
            +
                        raise ActiveRecord::Rollback unless status
         | 
| 51 | 
            +
                      end
         | 
| 50 52 | 
             
                    end
         | 
| 51 | 
            -
                  end
         | 
| 52 53 |  | 
| 53 | 
            -
             | 
| 54 | 
            +
                    status
         | 
| 55 | 
            +
                  end
         | 
| 54 56 | 
             
                end
         | 
| 55 57 |  | 
| 56 58 |  | 
| @@ -2,6 +2,8 @@ module ActiveRecord | |
| 2 2 | 
             
              module ConnectionAdapters
         | 
| 3 3 | 
             
                # Sunstone-specific extensions to column definitions in a table.
         | 
| 4 4 | 
             
                class SunstoneColumn < Column #:nodoc:
         | 
| 5 | 
            +
                  NONE = Object.new
         | 
| 6 | 
            +
             | 
| 5 7 | 
             
                  attr_reader :array
         | 
| 6 8 |  | 
| 7 9 | 
             
                  def initialize(name, sql_type_metadata, options={})
         | 
| @@ -14,12 +16,20 @@ module ActiveRecord | |
| 14 16 | 
             
                    @table_name = nil
         | 
| 15 17 | 
             
                    @primary_key = (options['primary_key'] == true)
         | 
| 16 18 | 
             
                    @array = options['array']
         | 
| 19 | 
            +
                    @auto_populated = options.has_key?('auto_populated') ? options['auto_populated'] : NONE
         | 
| 17 20 | 
             
                  end
         | 
| 18 21 |  | 
| 19 22 | 
             
                  def primary_key?
         | 
| 20 23 | 
             
                    @primary_key
         | 
| 21 24 | 
             
                  end
         | 
| 22 25 |  | 
| 26 | 
            +
                  def auto_populated?
         | 
| 27 | 
            +
                    # TODO: when retuning is working we can do the following to only
         | 
| 28 | 
            +
                    # return autopulated fields from StandardAPI
         | 
| 29 | 
            +
                    # @auto_populated == NONE ? @primary_key : @auto_populated
         | 
| 30 | 
            +
                    true
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                  
         | 
| 23 33 | 
             
                end
         | 
| 24 34 | 
             
              end
         | 
| 25 35 | 
             
            end
         | 
| @@ -25,22 +25,34 @@ module ActiveRecord | |
| 25 25 | 
             
                      else
         | 
| 26 26 | 
             
                        sar = arel_or_sar_string
         | 
| 27 27 | 
             
                      end
         | 
| 28 | 
            +
             | 
| 28 29 | 
             
                      sar.compile(binds)
         | 
| 29 30 | 
             
                    end
         | 
| 30 31 |  | 
| 31 | 
            -
                    def to_sar_and_binds(arel_or_sar_string, binds = [], preparable = nil | 
| 32 | 
            +
                    def to_sar_and_binds(arel_or_sar_string, binds = [], preparable = nil, allow_retry = false)
         | 
| 32 33 | 
             
                      if arel_or_sar_string.respond_to?(:ast)
         | 
| 34 | 
            +
                        arel_or_sar_string = arel_or_sar_string.ast
         | 
| 35 | 
            +
                      end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                      if Arel.arel_node?(arel_or_sar_string) && !(String === arel_or_sar_string)
         | 
| 33 38 | 
             
                        unless binds.empty?
         | 
| 34 39 | 
             
                          raise "Passing bind parameters with an arel AST is forbidden. " \
         | 
| 35 40 | 
             
                            "The values must be stored on the AST directly"
         | 
| 36 41 | 
             
                        end
         | 
| 37 | 
            -
                         | 
| 38 | 
            -
                         | 
| 42 | 
            +
                        
         | 
| 43 | 
            +
                        sar = visitor.accept(arel_or_sar_string, collector)
         | 
| 44 | 
            +
                        [sar.freeze, sar.binds, false, allow_retry]
         | 
| 39 45 | 
             
                      else
         | 
| 40 | 
            -
                        [arel_or_sar_string.dup.freeze, binds, false]
         | 
| 46 | 
            +
                        [arel_or_sar_string.dup.freeze, binds, false, allow_retry]
         | 
| 41 47 | 
             
                      end
         | 
| 42 48 | 
             
                    end
         | 
| 43 49 |  | 
| 50 | 
            +
                    def sar_for_insert(sql, pk, binds, returning)
         | 
| 51 | 
            +
                      # TODO: when StandardAPI supports returning we can do this; it might
         | 
| 52 | 
            +
                      # already need to investigate
         | 
| 53 | 
            +
                      to_sar_and_binds(sql, binds)
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
                    
         | 
| 44 56 | 
             
                    # This is used in the StatementCache object. It returns an object that
         | 
| 45 57 | 
             
                    # can be used to query the database repeatedly.
         | 
| 46 58 | 
             
                    def cacheable_query(klass, arel) # :nodoc:
         | 
| @@ -77,14 +89,33 @@ module ActiveRecord | |
| 77 89 | 
             
                    end
         | 
| 78 90 |  | 
| 79 91 | 
             
                    # Returns an ActiveRecord::Result instance.
         | 
| 80 | 
            -
                    def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
         | 
| 92 | 
            +
                    def select_all(arel, name = nil, binds = [], preparable: nil, async: false, allow_retry: false)
         | 
| 81 93 | 
             
                      arel = arel_from_relation(arel)
         | 
| 82 | 
            -
                      sar, binds, preparable = to_sar_and_binds(arel, binds, preparable)
         | 
| 83 | 
            -
             | 
| 84 | 
            -
                      select(sar, name, binds, | 
| 94 | 
            +
                      sar, binds, preparable, allow_retry = to_sar_and_binds(arel, binds, preparable, allow_retry)
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                      select(sar, name, binds,
         | 
| 97 | 
            +
                        prepare: prepared_statements && preparable,
         | 
| 98 | 
            +
                        async: async && FutureResult::SelectAll,
         | 
| 99 | 
            +
                        allow_retry: allow_retry
         | 
| 100 | 
            +
                      )
         | 
| 101 | 
            +
                    rescue ::RangeError
         | 
| 102 | 
            +
                      ActiveRecord::Result.empty(async: async)
         | 
| 103 | 
            +
                    end
         | 
| 104 | 
            +
                    
         | 
| 105 | 
            +
                    # Executes insert +sql+ statement in the context of this connection using
         | 
| 106 | 
            +
                    # +binds+ as the bind substitutes. +name+ is logged along with
         | 
| 107 | 
            +
                    # the executed +sql+ statement.
         | 
| 108 | 
            +
                    # Some adapters support the `returning` keyword argument which allows to control the result of the query:
         | 
| 109 | 
            +
                    # `nil` is the default value and maintains default behavior. If an array of column names is passed -
         | 
| 110 | 
            +
                    # the result will contain values of the specified columns from the inserted row.
         | 
| 111 | 
            +
                    #
         | 
| 112 | 
            +
                    # TODO: Add support for returning
         | 
| 113 | 
            +
                    def exec_insert(arel, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil)
         | 
| 114 | 
            +
                      sar, binds = sar_for_insert(arel, pk, binds, returning)
         | 
| 115 | 
            +
                      internal_exec_query(sar, name, binds)
         | 
| 85 116 | 
             
                    end
         | 
| 86 117 |  | 
| 87 | 
            -
                    def  | 
| 118 | 
            +
                    def internal_exec_query(arel, name = 'SAR', binds = [], prepare: false, async: false, allow_retry: false)
         | 
| 88 119 | 
             
                      sars = []
         | 
| 89 120 | 
             
                      multiple_requests = arel.is_a?(Arel::Collectors::Sunstone)
         | 
| 90 121 | 
             
                      type_casted_binds = binds#type_casted_binds(binds)
         | 
| @@ -112,11 +143,13 @@ module ActiveRecord | |
| 112 143 | 
             
                        sars.push(sar)
         | 
| 113 144 | 
             
                        log_mess = sar.path.split('?', 2)
         | 
| 114 145 | 
             
                        log("#{sar.method} #{log_mess[0]} #{(log_mess[1] && !log_mess[1].empty?) ? MessagePack.unpack(CGI.unescape(log_mess[1])) : '' }", name) do
         | 
| 115 | 
            -
                           | 
| 116 | 
            -
             | 
| 117 | 
            -
                             | 
| 118 | 
            -
             | 
| 119 | 
            -
                             | 
| 146 | 
            +
                          with_raw_connection do |conn|
         | 
| 147 | 
            +
                            response = conn.send_request(sar)
         | 
| 148 | 
            +
                            if response.is_a?(Net::HTTPNoContent)
         | 
| 149 | 
            +
                              nil
         | 
| 150 | 
            +
                            else
         | 
| 151 | 
            +
                              JSON.parse(response.body)
         | 
| 152 | 
            +
                            end
         | 
| 120 153 | 
             
                          end
         | 
| 121 154 | 
             
                        end
         | 
| 122 155 | 
             
                      }
         | 
| @@ -141,21 +174,21 @@ module ActiveRecord | |
| 141 174 |  | 
| 142 175 | 
             
                      if sars[0].instance_variable_defined?(:@sunstone_calculation) && sars[0].instance_variable_get(:@sunstone_calculation)
         | 
| 143 176 | 
             
                        # this is a count, min, max.... yea i know..
         | 
| 144 | 
            -
                        ActiveRecord::Result.new(['all'], [result], {:all => type_map.lookup('integer', {})})
         | 
| 177 | 
            +
                        ActiveRecord::Result.new(['all'], [result], {:all => @type_map.lookup('integer', {})})
         | 
| 145 178 | 
             
                      elsif result.is_a?(Array)
         | 
| 146 179 | 
             
                        ActiveRecord::Result.new(result[0] ? result[0].keys : [], result.map{|r| r.values})
         | 
| 147 180 | 
             
                      else
         | 
| 148 | 
            -
                        ActiveRecord::Result.new(result.keys, [result])
         | 
| 181 | 
            +
                        ActiveRecord::Result.new(result.keys, [result.values])
         | 
| 149 182 | 
             
                      end
         | 
| 150 183 | 
             
                    end
         | 
| 151 184 |  | 
| 152 | 
            -
                    def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
         | 
| 185 | 
            +
                    def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
         | 
| 153 186 | 
             
                      sar, binds = to_sar_and_binds(arel, binds)
         | 
| 154 | 
            -
                      value = exec_insert(sar, name, binds, pk, sequence_name)
         | 
| 187 | 
            +
                      value = exec_insert(sar, name, binds, pk, sequence_name, returning: returning)
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                      return returning_column_values(value) unless returning.nil?
         | 
| 190 | 
            +
             | 
| 155 191 | 
             
                      id_value || last_inserted_id(value)
         | 
| 156 | 
            -
                      
         | 
| 157 | 
            -
                      # value = exec_insert(arel, name, binds, pk, sequence_name)
         | 
| 158 | 
            -
                      # id_value || last_inserted_id(value)
         | 
| 159 192 | 
             
                    end
         | 
| 160 193 |  | 
| 161 194 | 
             
                    def update(arel, name = nil, binds = [])
         | 
| @@ -171,6 +204,10 @@ module ActiveRecord | |
| 171 204 | 
             
                      row && row['id']
         | 
| 172 205 | 
             
                    end
         | 
| 173 206 |  | 
| 207 | 
            +
                    def returning_column_values(result)
         | 
| 208 | 
            +
                      result.rows.first
         | 
| 209 | 
            +
                    end
         | 
| 210 | 
            +
             | 
| 174 211 | 
             
                  end
         | 
| 175 212 | 
             
                end
         | 
| 176 213 | 
             
              end
         |