sunstone 5.1.0.4 → 6.1.0.rc1

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.
Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +28 -15
  3. data/ext/active_record/associations.rb +4 -9
  4. data/ext/active_record/associations/collection_association.rb +25 -18
  5. data/ext/active_record/attribute_methods.rb +14 -42
  6. data/ext/active_record/callbacks.rb +1 -1
  7. data/ext/active_record/finder_methods.rb +164 -106
  8. data/ext/active_record/persistence.rb +35 -13
  9. data/ext/active_record/relation.rb +7 -47
  10. data/ext/active_record/relation/calculations.rb +16 -8
  11. data/ext/active_record/relation/query_methods.rb +9 -0
  12. data/ext/active_record/statement_cache.rb +11 -9
  13. data/ext/active_record/transactions.rb +13 -23
  14. data/ext/arel/attributes/empty_relation.rb +31 -31
  15. data/ext/arel/nodes/select_statement.rb +27 -13
  16. data/lib/active_record/connection_adapters/sunstone/column.rb +2 -2
  17. data/lib/active_record/connection_adapters/sunstone/database_statements.rb +77 -26
  18. data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +18 -8
  19. data/lib/active_record/connection_adapters/sunstone/type/array.rb +9 -8
  20. data/lib/active_record/connection_adapters/sunstone/type/binary.rb +34 -0
  21. data/lib/active_record/connection_adapters/sunstone/type/json.rb +1 -1
  22. data/lib/active_record/connection_adapters/sunstone_adapter.rb +42 -30
  23. data/lib/arel/collectors/sunstone.rb +21 -19
  24. data/lib/arel/visitors/sunstone.rb +56 -35
  25. data/lib/sunstone.rb +2 -4
  26. data/lib/sunstone/connection.rb +13 -11
  27. data/lib/sunstone/exception.rb +11 -1
  28. data/lib/sunstone/version.rb +1 -1
  29. data/sunstone.gemspec +5 -3
  30. data/test/active_record/associations/has_many_test.rb +30 -2
  31. data/test/active_record/eager_loading_test.rb +13 -1
  32. data/test/active_record/persistance_test.rb +38 -13
  33. data/test/active_record/query/count_test.rb +13 -0
  34. data/test/active_record/query_test.rb +7 -7
  35. data/test/active_record/rpc_test.rb +30 -0
  36. data/test/schema_mock.rb +31 -27
  37. data/test/sunstone/connection/column_definition_test.rb +30 -0
  38. data/test/sunstone/connection/configuration_test.rb +13 -13
  39. data/test/sunstone/connection/cookie_store_test.rb +2 -2
  40. data/test/sunstone/connection/request_helper_test.rb +12 -12
  41. data/test/sunstone/connection/send_request_test.rb +13 -13
  42. data/test/sunstone/connection_test.rb +2 -2
  43. data/test/test_helper.rb +1 -1
  44. metadata +38 -22
  45. data/ext/active_record/associations/association.rb +0 -16
  46. data/ext/active_record/batches.rb +0 -12
  47. data/ext/arel/attributes/relation.rb +0 -31
@@ -2,6 +2,22 @@ module ActiveRecord
2
2
  # = Active Record \Persistence
3
3
  module Persistence
4
4
 
5
+ module ClassMethods
6
+ def rpc(name)
7
+ define_method("#{name}!") do
8
+ req = Net::HTTP::Post.new("/#{self.class.table_name}/#{CGI.escape(id.to_s)}/#{CGI.escape(name.to_s)}")
9
+ self.class.connection.instance_variable_get(:@connection).send_request(req) do |response|
10
+ JSON.parse(response.body).each do |k,v|
11
+ if self.class.column_names.include?(k)
12
+ @attributes.write_from_database(k, v)
13
+ end
14
+ end
15
+ end
16
+ true
17
+ end
18
+ end
19
+ end
20
+
5
21
  def update!(attributes)
6
22
  @no_save_transaction = true
7
23
  with_transaction_returning_status do
@@ -14,12 +30,14 @@ module ActiveRecord
14
30
 
15
31
  private
16
32
 
17
- def create_or_update(*args)
33
+ def create_or_update(**, &block)
34
+ _raise_readonly_record_error if readonly?
35
+ return false if destroyed?
36
+
18
37
  @updating = new_record? ? :creating : :updating
19
38
  Thread.current[:sunstone_updating_model] = self
20
39
 
21
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
22
- result = new_record? ? _create_record : _update_record(*args)
40
+ result = new_record? ? _create_record(&block) : _update_record(&block)
23
41
 
24
42
  if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && result != 0
25
43
  row_hash = result.rows.first
@@ -61,9 +79,10 @@ module ActiveRecord
61
79
  # Creates a record with values matching those of the instance attributes
62
80
  # and returns its id.
63
81
  def _create_record(attribute_names = self.attribute_names)
64
- attributes_values = arel_attributes_with_values_for_create(attribute_names)
65
-
66
- new_id = self.class.unscoped.insert attributes_values
82
+ attribute_names &= self.class.column_names
83
+ attributes_values = attributes_with_values(attribute_names)
84
+
85
+ new_id = self.class._insert_record(attributes_values)
67
86
 
68
87
  @new_record = false
69
88
 
@@ -76,20 +95,23 @@ module ActiveRecord
76
95
  end
77
96
 
78
97
  def _update_record(attribute_names = self.attribute_names)
79
- attributes_values = arel_attributes_with_values_for_update(attribute_names)
80
- if attributes_values.empty?
81
- rows_affected = 0
98
+ attribute_values = attributes_with_values(attribute_names)
99
+
100
+ if attribute_values.empty?
101
+ affected_rows = 0
82
102
  @_trigger_update_callback = true
83
103
  else
84
- rows_affected = self.class.unscoped._update_record(attributes_values, id, id_in_database)
85
- @_trigger_update_callback = (rows_affected.is_a?(ActiveRecord::Result) ? rows_affected.rows.size : rows_affected) > 0
104
+ affected_rows = self.class._update_record( attribute_values, self.class.primary_key => id_in_database )
105
+ @_trigger_update_callback = affected_rows == 1
86
106
  end
87
107
 
108
+ @previously_new_record = false
109
+
88
110
  yield(self) if block_given?
89
111
 
90
- rows_affected
112
+ affected_rows
91
113
  end
92
-
114
+
93
115
  #!!!! TODO: I am duplicated from finder_methods.....
94
116
  def construct(parent, relations, seen, model_cache)
95
117
  relations.each do |key, attributes|
@@ -1,59 +1,19 @@
1
1
  module ActiveRecord
2
2
  class Relation
3
3
 
4
- def to_sql
5
- @to_sql ||= begin
6
- relation = self
7
-
8
- if eager_loading?
9
- find_with_associations { |rel| relation = rel }
10
- end
11
-
12
- conn = klass.connection
13
- conn.unprepared_statement {
14
- conn.to_sql(relation.arel, relation.bound_attributes)
15
- }
16
- end
17
- end
18
-
19
4
  def to_sar
20
5
  @to_sar ||= begin
21
- relation = self
22
-
23
6
  if eager_loading?
24
- find_with_associations { |rel| relation = rel }
7
+ apply_join_dependency do |relation, join_dependency|
8
+ relation = join_dependency.apply_column_aliases(relation)
9
+ relation.to_sar
10
+ end
11
+ else
12
+ conn = klass.connection
13
+ conn.unprepared_statement { conn.to_sar(arel) }
25
14
  end
26
-
27
- conn = klass.connection
28
- conn.unprepared_statement {
29
- conn.to_sar(relation.arel, relation.bound_attributes)
30
- }
31
15
  end
32
16
  end
33
17
 
34
- def _update_record(values, id, id_was) # :nodoc:
35
- substitutes, binds = substitute_values values
36
-
37
- scope = @klass.unscoped
38
-
39
- if @klass.finder_needs_type_condition?
40
- scope.unscope!(where: @klass.inheritance_column)
41
- end
42
-
43
- relation = scope.where(@klass.primary_key => (id_was || id))
44
- bvs = binds + relation.bound_attributes
45
- um = relation
46
- .arel
47
- .compile_update(substitutes, @klass.primary_key)
48
- um.table @klass.arel_table
49
-
50
- @klass.connection.update(
51
- um,
52
- 'SQL',
53
- bvs,
54
- )
55
- end
56
-
57
-
58
18
  end
59
19
  end
@@ -2,24 +2,32 @@ module ActiveRecord
2
2
  module Calculations
3
3
 
4
4
  def pluck(*column_names)
5
- if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
5
+ if loaded? && all_attributes?(column_names)
6
6
  return records.pluck(*column_names)
7
7
  end
8
8
 
9
9
  if has_include?(column_names.first)
10
- construct_relation_for_association_calculations.pluck(*column_names)
10
+ relation = apply_join_dependency
11
+ relation.pluck(*column_names)
11
12
  elsif klass.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
12
13
  load
13
14
  return records.pluck(*column_names.map{|n| n.sub(/^#{klass.table_name}\./, "")})
14
15
  else
16
+ klass.disallow_raw_sql!(column_names)
17
+ columns = arel_columns(column_names)
15
18
  relation = spawn
16
- relation.select_values = column_names.map { |cn|
17
- @klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
18
- }
19
- result = klass.connection.select_all(relation.arel, nil, bound_attributes)
20
- result.cast_values(klass.attribute_types)
19
+ relation.select_values = columns
20
+
21
+ result = skip_query_cache_if_necessary do
22
+ if where_clause.contradiction?
23
+ ActiveRecord::Result.new([], [])
24
+ else
25
+ klass.connection.select_all(relation.arel, nil)
26
+ end
27
+ end
28
+ type_cast_pluck_values(result, columns)
21
29
  end
22
30
  end
23
-
31
+
24
32
  end
25
33
  end
@@ -0,0 +1,9 @@
1
+ module ActiveRecord
2
+ module QueryMethods
3
+ private
4
+ def assert_mutability!
5
+ raise ImmutableRelation if @loaded
6
+ raise ImmutableRelation if defined?(@arel) && !klass.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && @arel
7
+ end
8
+ end
9
+ end
@@ -5,24 +5,26 @@ module ActiveRecord
5
5
  def initialize(values, sunstone=false)
6
6
  @values = values
7
7
  @indexes = if sunstone
8
- values.value.find_all { |thing|
9
- Arel::Nodes::BindParam === thing
10
- }
11
8
  else
12
- values.each_with_index.find_all { |thing,i|
13
- Arel::Nodes::BindParam === thing
9
+ values.each_with_index.find_all { |thing, i|
10
+ Substitute === thing
14
11
  }.map(&:last)
15
12
  end
16
13
  end
17
14
 
18
15
  def sql_for(binds, connection)
19
- casted_binds = binds.map(&:value_for_database)
20
-
21
16
  if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
22
- @values.compile(binds)
17
+ binds.map!(&:value_for_database)
18
+ @values
23
19
  else
24
20
  val = @values.dup
25
- @indexes.each { |i| val[i] = connection.quote(casted_binds.shift) }
21
+ @indexes.each do |i|
22
+ value = binds.shift
23
+ if ActiveModel::Attribute === value
24
+ value = value.value_for_database
25
+ end
26
+ val[i] = connection.quote(value)
27
+ end
26
28
  val.join
27
29
  end
28
30
  end
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  # end
21
21
  # end
22
22
  #
23
- def save!(*) #:nodoc:
23
+ def save!(**) #:nodoc:
24
24
  if instance_variable_defined?(:@no_save_transaction) && @no_save_transaction
25
25
  super
26
26
  else
@@ -34,33 +34,23 @@ module ActiveRecord
34
34
  # end
35
35
 
36
36
  def with_transaction_returning_status
37
- if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && instance_variable_defined?(:@updating) && @updating
38
- begin
39
- status = yield
40
- rescue ActiveRecord::Rollback
41
- clear_transaction_record_state
42
- status = nil
43
- end
44
- return status
45
- end
46
-
47
37
  status = nil
48
- self.class.transaction do
49
- add_to_transaction
50
- begin
38
+ connection = self.class.connection
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
47
+
51
48
  status = yield
52
- rescue ActiveRecord::Rollback
53
- clear_transaction_record_state
54
- status = nil
49
+ raise ActiveRecord::Rollback unless status
55
50
  end
56
-
57
- raise ActiveRecord::Rollback unless status
58
51
  end
52
+
59
53
  status
60
- ensure
61
- if @transaction_state && @transaction_state.committed?
62
- clear_transaction_record_state
63
- end
64
54
  end
65
55
 
66
56
 
@@ -1,31 +1,31 @@
1
- module Arel
2
- module Attributes
3
- class EmptyRelation < Attribute
4
-
5
- attr_accessor :collection, :for_write
6
-
7
- def initialize(relation, name, collection = false, for_write=false)
8
- self[:relation] = relation
9
- self[:name] = name
10
- @collection = collection
11
- @for_write = for_write
12
- end
13
-
14
- def able_to_type_cast?
15
- false
16
- end
17
-
18
- def table_name
19
- nil
20
- end
21
-
22
- def eql? other
23
- self.class == other.class &&
24
- self.relation == other.relation &&
25
- self.name == other.name &&
26
- self.collection == other.collection
27
- end
28
-
29
- end
30
- end
31
- end
1
+ # module Arel
2
+ # module Attributes
3
+ # class EmptyRelation < Attribute
4
+ #
5
+ # attr_accessor :collection, :for_write
6
+ #
7
+ # def initialize(relation, name, collection = false, for_write=false)
8
+ # self[:relation] = relation
9
+ # self[:name] = name
10
+ # @collection = collection
11
+ # @for_write = for_write
12
+ # end
13
+ #
14
+ # def able_to_type_cast?
15
+ # false
16
+ # end
17
+ #
18
+ # def table_name
19
+ # nil
20
+ # end
21
+ #
22
+ # def eql? other
23
+ # self.class == other.class &&
24
+ # self.relation == other.relation &&
25
+ # self.name == other.name &&
26
+ # self.collection == other.collection
27
+ # end
28
+ #
29
+ # end
30
+ # end
31
+ # end
@@ -1,27 +1,41 @@
1
1
  module Arel
2
2
  module Nodes
3
- class SelectStatement < Arel::Nodes::Node
3
+ class SelectStatement < Arel::Nodes::NodeExpression
4
4
 
5
5
  attr_accessor :eager_load
6
6
 
7
- def initialize_with_eager_load cores = [SelectCore.new]
8
- initialize_without_eager_load
9
- @eager_load = nil
7
+ def initialize(cores = [SelectCore.new])
8
+ super()
9
+ @cores = cores
10
+ @orders = []
11
+ @limit = nil
12
+ @lock = nil
13
+ @offset = nil
14
+ @with = nil
15
+ @eager_load = nil
10
16
  end
11
-
12
- alias_method :initialize_without_eager_load, :initialize
13
- alias_method :initialize, :initialize_with_eager_load
14
-
17
+
18
+ def initialize_copy other
19
+ super
20
+ @cores = @cores.map { |x| x.clone }
21
+ @orders = @orders.map { |x| x.clone }
22
+ @eager_load = @eager_load&.map { |x| x.clone }
23
+ end
24
+
15
25
  def hash
16
26
  [@cores, @orders, @limit, @lock, @offset, @with, @eager_load].hash
17
27
  end
18
28
 
19
- def eql_with_eager_load? other
20
- eql_without_eager_load?(other) && self.eager_load == other.eager_load
29
+ def eql? other
30
+ self.class == other.class &&
31
+ self.cores == other.cores &&
32
+ self.orders == other.orders &&
33
+ self.limit == other.limit &&
34
+ self.lock == other.lock &&
35
+ self.offset == other.offset &&
36
+ self.with == other.with &&
37
+ self.eager_load == other.eager_load
21
38
  end
22
- alias_method :eql_without_eager_load?, :eql?
23
- alias_method :eql?, :eql_with_eager_load?
24
- alias_method :==, :eql?
25
39
 
26
40
  end
27
41
  end
@@ -2,8 +2,7 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  # Sunstone-specific extensions to column definitions in a table.
4
4
  class SunstoneColumn < Column #:nodoc:
5
- delegate :array, to: :sql_type_metadata
6
- alias :array? :array
5
+ attr_reader :array
7
6
 
8
7
  def initialize(name, sql_type_metadata, options={})
9
8
  @name = name.freeze
@@ -14,6 +13,7 @@ module ActiveRecord
14
13
  @collation = nil
15
14
  @table_name = nil
16
15
  @primary_key = (options['primary_key'] == true)
16
+ @array = options['array']
17
17
  end
18
18
 
19
19
  def primary_key?
@@ -7,49 +7,97 @@ module ActiveRecord
7
7
 
8
8
  def to_sql(arel, binds = [])
9
9
  if arel.respond_to?(:ast)
10
- collected = Arel::Visitors::ToSql.new(self).accept(arel.ast, prepared_statements ? AbstractAdapter::SQLString.new : AbstractAdapter::BindCollector.new)
11
- collected.compile(binds, self).freeze
10
+ unless binds.empty?
11
+ raise "Passing bind parameters with an arel AST is forbidden. " \
12
+ "The values must be stored on the AST directly"
13
+ end
14
+ Arel::Visitors::ToSql.new(self).accept(arel.ast, Arel::Collectors::SubstituteBinds.new(self, Arel::Collectors::SQLString.new)).value
12
15
  else
13
16
  arel.dup.freeze
14
17
  end
15
18
  end
16
19
 
17
20
  # Converts an arel AST to a Sunstone API Request
18
- def to_sar(arel, bvs = [])
19
- if arel.respond_to?(:ast)
20
- collected = visitor.accept(arel.ast, collector)
21
- collected.compile(bvs, self)
21
+ def to_sar(arel_or_sar_string, binds = nil)
22
+ if arel_or_sar_string.respond_to?(:ast)
23
+ sar = visitor.accept(arel_or_sar_string.ast, collector)
24
+ binds = sar.binds if binds.nil?
22
25
  else
23
- arel
26
+ sar = arel_or_sar_string
24
27
  end
28
+ sar.compile(binds)
25
29
  end
26
30
 
31
+ def to_sar_and_binds(arel_or_sar_string, binds = []) # :nodoc:
32
+ if arel_or_sar_string.respond_to?(:ast)
33
+ unless binds.empty?
34
+ raise "Passing bind parameters with an arel AST is forbidden. " \
35
+ "The values must be stored on the AST directly"
36
+ end
37
+ sar = visitor.accept(arel_or_sar_string.ast, collector)
38
+ # puts ['a', sar.freeze, sar.binds].map(&:inspect)
39
+ [sar.freeze, sar.binds]
40
+ else
41
+ # puts ['b',arel_or_sar_string.dup.freeze, binds].map(&:inspect)
42
+ [arel_or_sar_string.dup.freeze, binds]
43
+ end
44
+ end
45
+
46
+ # This is used in the StatementCache object. It returns an object that
47
+ # can be used to query the database repeatedly.
27
48
  def cacheable_query(klass, arel) # :nodoc:
28
- collected = visitor.accept(arel.ast, collector)
29
49
  if prepared_statements
30
- klass.query(collected.value)
50
+ sql, binds = visitor.compile(arel.ast, collector)
51
+ query = klass.query(sql)
52
+ elsif self.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
53
+ collector = SunstonePartialQueryCollector.new(self.collector)
54
+ parts, binds = visitor.compile(arel.ast, collector)
55
+ query = StatementCache::PartialQuery.new(parts, true)
31
56
  else
32
- if self.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
33
- StatementCache::PartialQuery.new(collected, true)
34
- else
35
- StatementCache::PartialQuery.new(collected.value, false)
36
- end
57
+ collector = klass.partial_query_collector
58
+ parts, binds = visitor.compile(arel.ast, collector)
59
+ query = klass.partial_query(parts)
60
+ end
61
+ [query, binds]
62
+ end
63
+
64
+ class SunstonePartialQueryCollector
65
+ delegate_missing_to :@collector
66
+
67
+ def initialize(collector)
68
+ @collector = collector
69
+ @binds = []
70
+ end
71
+
72
+ def add_bind(obj)
73
+ @binds << obj
74
+ end
75
+
76
+ def value
77
+ [@collector, @binds]
37
78
  end
38
79
  end
39
80
 
40
81
  # Returns an ActiveRecord::Result instance.
41
82
  def select_all(arel, name = nil, binds = [], preparable: nil)
42
- arel, binds = binds_from_relation arel, binds
43
- select(arel, name, binds)
83
+ arel = arel_from_relation(arel)
84
+ sar, binds = to_sar_and_binds(arel, binds)
85
+ select(sar, name, binds)
44
86
  end
45
87
 
46
88
  def exec_query(arel, name = 'SAR', binds = [], prepare: false)
47
89
  sars = []
48
- multiple_requests = arel.is_a?(Arel::SelectManager)
49
-
90
+ multiple_requests = arel.is_a?(Arel::Collectors::Sunstone)
91
+ type_casted_binds = binds#type_casted_binds(binds)
92
+
50
93
  if multiple_requests
51
- allowed_limit = limit_definition(arel.source.left.name)
52
- requested_limit = binds.find { |x| x.name == 'LIMIT' }&.value
94
+ allowed_limit = limit_definition(arel.table)
95
+ limit_bind_index = nil#binds.find_index { |x| x.name == 'LIMIT' }
96
+ requested_limit = if limit_bind_index
97
+ type_casted_binds[limit_bind_index]
98
+ else
99
+ arel.limit&.value&.value_for_database
100
+ end
53
101
 
54
102
  if allowed_limit.nil?
55
103
  multiple_requests = false
@@ -61,7 +109,7 @@ module ActiveRecord
61
109
  end
62
110
 
63
111
  send_request = lambda { |req_arel|
64
- sar = to_sar(req_arel, binds)
112
+ sar = to_sar(req_arel, type_casted_binds)
65
113
  sars.push(sar)
66
114
  log_mess = sar.path.split('?', 2)
67
115
  log("#{sar.method} #{log_mess[0]} #{(log_mess[1] && !log_mess[1].empty?) ? MessagePack.unpack(CGI.unescape(log_mess[1])) : '' }", name) do
@@ -75,12 +123,11 @@ module ActiveRecord
75
123
  }
76
124
 
77
125
  result = if multiple_requests
78
- bind = binds.find { |x| x.name == 'LIMIT' }
79
- binds.delete(bind)
126
+ binds.delete_at(limit_bind_index) if limit_bind_index
80
127
 
81
128
  limit, offset, results = allowed_limit, 0, []
82
129
  while requested_limit ? offset < requested_limit : true
83
- split_arel = arel.clone
130
+ split_arel = arel.dup
84
131
  split_arel.limit = limit
85
132
  split_arel.offset = offset
86
133
  request_results = send_request.call(split_arel)
@@ -95,7 +142,7 @@ module ActiveRecord
95
142
 
96
143
  if sars[0].instance_variable_defined?(:@sunstone_calculation) && sars[0].instance_variable_get(:@sunstone_calculation)
97
144
  # this is a count, min, max.... yea i know..
98
- ActiveRecord::Result.new(['all'], [result], {:all => type_map.lookup('integer')})
145
+ ActiveRecord::Result.new(['all'], [result], {:all => type_map.lookup('integer', {})})
99
146
  elsif result.is_a?(Array)
100
147
  ActiveRecord::Result.new(result[0] ? result[0].keys : [], result.map{|r| r.values})
101
148
  else
@@ -104,8 +151,12 @@ module ActiveRecord
104
151
  end
105
152
 
106
153
  def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
107
- value = exec_insert(arel, name, binds, pk, sequence_name)
154
+ sar, binds = to_sar_and_binds(arel, binds)
155
+ value = exec_insert(sar, name, binds, pk, sequence_name)
108
156
  id_value || last_inserted_id(value)
157
+
158
+ # value = exec_insert(arel, name, binds, pk, sequence_name)
159
+ # id_value || last_inserted_id(value)
109
160
  end
110
161
 
111
162
  def update(arel, name = nil, binds = [])