sunstone 6.1.3 → 7.1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67c26e8a4275aa67d9e09b43cfce417732142a043b6ca49d2c1e85bbfb74950d
4
- data.tar.gz: a46c586fe763e9d90029a007074919fca9e997efa8ddddf57588136d6cb2b883
3
+ metadata.gz: 3956ea045dce2994b10bcac8535462bdf08597b85d7e15fc325110149a576aa6
4
+ data.tar.gz: 02be730df372f32557112e9fb618befb5aafd7a8ef15ce1e12a866f8c18c2ed7
5
5
  SHA512:
6
- metadata.gz: 1fd7cb872485fa5507d1bcb21e28e81d92b807279fbdbf12440a74de32cd39c4584c42e6f0ea1fd371261a3c614358967d94c1abc30bb304b2364bb8ae7e9dab
7
- data.tar.gz: 3d3105125dfaad25f7884648406444ca3a4dab3e2782b482659179ca8a484ce52bded0222af6b48210ad7f0f00c901ca92a3e780380b22d4b62cb3e3c57019f8
6
+ metadata.gz: c978ff5919d301007ccd326a632ed915cce129584e0ff9c25c199bddb9a65e517361f95a7d3a8af4ea70546acd1bb16fbc1118ff050a0c209f4168f9ec71feb9
7
+ data.tar.gz: 3a24f347b5ca8ccf2816e8d50a28ca3effedea79a897ab3692801b5cd8095d9fc324f37f792ffba621a9669eb7ea92f58be762b62d2a1e9096a9306fc1d46be9
@@ -1,3 +1,5 @@
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
@@ -8,7 +10,7 @@ module ActiveRecord
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?(:@updating) && owner.instance_variable_get(:@updating)
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?(:@updating) && owner.instance_variable_get(:@updating))
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)
@@ -70,27 +72,3 @@ module ActiveRecord
70
72
 
71
73
  end
72
74
  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
@@ -44,4 +48,4 @@ module ActiveRecord
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 do |name|
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 ||= {}
@@ -97,10 +98,16 @@ module ActiveRecord
97
98
  []
98
99
  else
99
100
  association.target.select { |r| !r.destroyed? }.map do |record|
100
- record.send(:attributes_with_values, record.send(:attribute_names_for_partial_writes) + (record.new_record? ? [] : [record.class.primary_key]))
101
+ record.send(
102
+ :attributes_with_values,
103
+ record.new_record? ?
104
+ record.send(:attribute_names_for_partial_inserts)
105
+ :
106
+ record.send(:attribute_names_for_partial_updates) + [record.class.primary_key]
107
+ )
101
108
  end
102
109
  end
103
-
110
+
104
111
  association.instance_variable_set(:@sunstone_changed, false)
105
112
  end
106
113
 
@@ -108,6 +115,6 @@ module ActiveRecord
108
115
  association.reset_scope if association.respond_to?(:reset_scope)
109
116
  end
110
117
  end
111
-
118
+
112
119
  end
113
120
  end
@@ -1,3 +1,6 @@
1
+ # The last ref that this code was synced with Rails
2
+ # ref: 9269f634d471ad6ca46752421eabd3e1c26220b5
3
+
1
4
  module ActiveRecord
2
5
  module Callbacks
3
6
  private
@@ -14,4 +17,4 @@ module ActiveRecord
14
17
  end
15
18
 
16
19
  end
17
- end
20
+ end
@@ -1,13 +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 value.is_a?(Hash) && !table.has_column?(key)
9
- ka = table.associated_table(key, &block).predicate_builder.expand_from_hash(value.stringify_keys)
10
- if self.send(:table).instance_variable_get(:@klass).connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
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)
18
+ ka = table.associated_table(key, &block)
19
+ .predicate_builder.expand_from_hash(value.stringify_keys)
20
+
21
+ if self.table.instance_variable_get(:@klass).connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
11
22
  ka.each { |k|
12
23
  if k.left.is_a?(Arel::Attributes::Attribute) || k.left.is_a?(Arel::Attributes::Relation)
13
24
  k.left = Arel::Attributes::Relation.new(k.left, key)
@@ -23,11 +34,8 @@ module ActiveRecord
23
34
  # PriceEstimate.where(estimate_of: treasure)
24
35
  associated_table = table.associated_table(key)
25
36
  if associated_table.polymorphic_association?
26
- case value.is_a?(Array) ? value.first : value
27
- when Base, Relation
28
- value = [value] unless value.is_a?(Array)
29
- klass = PolymorphicArrayValue
30
- end
37
+ value = [value] unless value.is_a?(Array)
38
+ klass = PolymorphicArrayValue
31
39
  elsif associated_table.through_association?
32
40
  next associated_table.predicate_builder.expand_from_hash(
33
41
  associated_table.primary_key => value
@@ -36,7 +44,9 @@ module ActiveRecord
36
44
 
37
45
  klass ||= AssociationQueryValue
38
46
  queries = klass.new(associated_table, value).queries.map! do |query|
39
- expand_from_hash(query)
47
+ # If the query produced is identical to attributes don't go any deeper.
48
+ # Prevents stack level too deep errors when association and foreign_key are identical.
49
+ query == attributes ? self[key, value] : expand_from_hash(query)
40
50
  end
41
51
 
42
52
  grouping_queries(queries)
@@ -202,7 +212,7 @@ module ActiveRecord
202
212
  relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
203
213
  end
204
214
 
205
- if eager_loading && !(
215
+ if eager_loading && has_limit_or_offset? && !(
206
216
  using_limitable_reflections?(join_dependency.reflections) &&
207
217
  using_limitable_reflections?(
208
218
  construct_join_dependency(
@@ -211,12 +221,12 @@ module ActiveRecord
211
221
  ), nil
212
222
  ).reflections
213
223
  )
214
- )
215
- if has_limit_or_offset? && !connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
216
- limited_ids = limited_ids_for(relation)
217
- limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
224
+ )
225
+ if !connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
226
+ relation = skip_query_cache_if_necessary do
227
+ klass.connection.distinct_relation_for_primary_key(relation)
228
+ end
218
229
  end
219
- relation.limit_value = relation.offset_value = nil
220
230
  end
221
231
 
222
232
  if block_given?
@@ -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.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)
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
- @updating = new_record? ? :creating : :updating
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.rows.first
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
- self.assign_attributes(row_hash.select{|k,v| self.class.column_names.include?(k.to_s) })
55
- row_hash.select{|k,v| !self.class.column_names.include?(k.to_s) }.each do |relation_name, value|
56
- assc = association(relation_name.to_sym)
57
- assc.reset if assc.reflection.collection?
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,36 +95,50 @@ module ActiveRecord
72
95
  end
73
96
  raise ActiveRecord::RecordInvalid
74
97
  ensure
75
- @updating = false
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
- attribute_names &= self.class.column_names
83
- attributes_values = attributes_with_values(attribute_names)
105
+ attribute_names = attributes_for_create(attribute_names)
106
+ attribute_values = attributes_with_values(attribute_names)
107
+
108
+ returning_columns = self.class._returning_columns_for_insert
84
109
 
85
- new_id = self.class._insert_record(attributes_values)
110
+ returning_values = self.class._insert_record(
111
+ attribute_values,
112
+ returning_columns
113
+ )
114
+
115
+ if !self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
116
+ returning_columns.zip(returning_values).each do |column, value|
117
+ _write_attribute(column, value) if !_read_attribute(column)
118
+ end if returning_values
119
+ end
86
120
 
87
121
  @new_record = false
122
+ @previously_new_record = true
123
+
124
+ yield(self) if block_given?
88
125
 
89
126
  if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
90
- new_id
127
+ returning_values
91
128
  else
92
- self.id ||= new_id if self.class.primary_key
93
129
  id
94
130
  end
95
131
  end
96
-
132
+
97
133
  def _update_record(attribute_names = self.attribute_names)
134
+ attribute_names = attributes_for_update(attribute_names)
98
135
  attribute_values = attributes_with_values(attribute_names)
99
136
 
100
137
  if attribute_values.empty?
101
138
  affected_rows = 0
102
139
  @_trigger_update_callback = true
103
140
  else
104
- affected_rows = self.class._update_record( attribute_values, self.class.primary_key => id_in_database )
141
+ affected_rows = self.class._update_record(attribute_values, _query_constraints_hash)
105
142
  @_trigger_update_callback = affected_rows == 1
106
143
  end
107
144
 
@@ -1,8 +1,11 @@
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)
5
- if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
8
+ if loaded? && all_attributes?(column_names)
6
9
  return records.pluck(*column_names)
7
10
  end
8
11
 
@@ -14,10 +17,17 @@ module ActiveRecord
14
17
  return records.pluck(*column_names.map{|n| n.to_s.sub(/^#{klass.table_name}\./, "")})
15
18
  else
16
19
  klass.disallow_raw_sql!(column_names)
20
+ columns = arel_columns(column_names)
17
21
  relation = spawn
18
- relation.select_values = column_names
19
- result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
20
- result.cast_values(klass.attribute_types)
22
+ relation.select_values = columns
23
+ result = skip_query_cache_if_necessary do
24
+ if where_clause.contradiction?
25
+ ActiveRecord::Result.empty
26
+ else
27
+ klass.connection.select_all(relation.arel, "#{klass.name} Pluck")
28
+ end
29
+ end
30
+ type_cast_pluck_values(result, columns)
21
31
  end
22
32
  end
23
33
 
@@ -3,7 +3,7 @@ module ActiveRecord
3
3
  private
4
4
  def assert_mutability!
5
5
  raise ImmutableRelation if @loaded
6
- raise ImmutableRelation if defined?(@arel) && !klass.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && @arel
6
+ raise ImmutableRelation if defined?(@arel) && @arel && !klass.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
7
7
  end
8
8
  end
9
9
  end
@@ -14,7 +14,6 @@ module ActiveRecord
14
14
 
15
15
  def sql_for(binds, connection)
16
16
  if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
17
- binds.map!(&:value_for_database)
18
17
  @values
19
18
  else
20
19
  val = @values.dup
@@ -36,8 +36,8 @@ module ActiveRecord
36
36
  def with_transaction_returning_status
37
37
  status = nil
38
38
  connection = self.class.connection
39
-
40
- if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && instance_variable_defined?(:@updating) && @updating
39
+
40
+ if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && instance_variable_defined?(:@sunstone_updating) && @sunstone_updating
41
41
  status = yield
42
42
  else
43
43
  ensure_finalize = !connection.transaction_open?
@@ -4,9 +4,9 @@ module Arel
4
4
 
5
5
  attr_accessor :eager_load
6
6
 
7
- def initialize(cores = [SelectCore.new])
7
+ def initialize(relation = nil)
8
8
  super()
9
- @cores = cores
9
+ @cores = [SelectCore.new(relation)]
10
10
  @orders = []
11
11
  @limit = nil
12
12
  @lock = nil
@@ -36,7 +36,7 @@ module Arel
36
36
  self.with == other.with &&
37
37
  self.eager_load == other.eager_load
38
38
  end
39
-
39
+ alias :== :eql?
40
40
  end
41
41
  end
42
42
  end
@@ -2,24 +2,34 @@ 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={})
8
10
  @name = name.freeze
9
11
  @sql_type_metadata = sql_type_metadata
10
12
  @null = options['null']
11
- @default = (sql_type_metadata.type == :json ? JSON.generate(options['default']) : options['default'])
13
+ @default = options['default'] ? JSON.generate(options['default']) : options['default']
12
14
  @default_function = nil
13
15
  @collation = nil
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,24 +25,35 @@ 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 = []) # :nodoc:
32
+ def to_sar_and_binds(arel_or_sar_string, binds = [], preparable = nil) # :nodoc:
33
+ # Arel::TreeManager -> Arel::Node
32
34
  if arel_or_sar_string.respond_to?(:ast)
35
+ arel_or_sar_string = arel_or_sar_string.ast
36
+ end
37
+
38
+ if Arel.arel_node?(arel_or_sar_string) && !(String === arel_or_sar_string)
33
39
  unless binds.empty?
34
40
  raise "Passing bind parameters with an arel AST is forbidden. " \
35
41
  "The values must be stored on the AST directly"
36
42
  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]
43
+
44
+ sar = visitor.accept(arel_or_sar_string, collector)
45
+ [sar.freeze, sar.binds, false]
40
46
  else
41
- # puts ['b',arel_or_sar_string.dup.freeze, binds].map(&:inspect)
42
- [arel_or_sar_string.dup.freeze, binds]
47
+ [arel_or_sar_string.dup.freeze, binds, false]
43
48
  end
44
49
  end
45
50
 
51
+ def sar_for_insert(sql, pk, binds, returning)
52
+ # TODO: when StandardAPI supports returning we can do this; it might
53
+ # already need to investigate
54
+ to_sar_and_binds(sql, binds)
55
+ end
56
+
46
57
  # This is used in the StatementCache object. It returns an object that
47
58
  # can be used to query the database repeatedly.
48
59
  def cacheable_query(klass, arel) # :nodoc:
@@ -79,13 +90,29 @@ module ActiveRecord
79
90
  end
80
91
 
81
92
  # Returns an ActiveRecord::Result instance.
82
- def select_all(arel, name = nil, binds = [], preparable: nil)
93
+ def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
83
94
  arel = arel_from_relation(arel)
84
- sar, binds = to_sar_and_binds(arel, binds)
85
- select(sar, name, binds)
95
+ sar, binds, preparable = to_sar_and_binds(arel, binds, preparable)
96
+
97
+ select(sar, name, binds, prepare: prepared_statements && preparable, async: async && FutureResult::SelectAll)
98
+ rescue ::RangeError
99
+ ActiveRecord::Result.empty(async: async)
100
+ end
101
+
102
+ # Executes insert +sql+ statement in the context of this connection using
103
+ # +binds+ as the bind substitutes. +name+ is logged along with
104
+ # the executed +sql+ statement.
105
+ # Some adapters support the `returning` keyword argument which allows to control the result of the query:
106
+ # `nil` is the default value and maintains default behavior. If an array of column names is passed -
107
+ # the result will contain values of the specified columns from the inserted row.
108
+ #
109
+ # TODO: Add support for returning
110
+ def exec_insert(arel, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil)
111
+ sar, binds = sar_for_insert(arel, pk, binds, returning)
112
+ internal_exec_query(sar, name, binds)
86
113
  end
87
114
 
88
- def exec_query(arel, name = 'SAR', binds = [], prepare: false)
115
+ def internal_exec_query(arel, name = 'SAR', binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true)
89
116
  sars = []
90
117
  multiple_requests = arel.is_a?(Arel::Collectors::Sunstone)
91
118
  type_casted_binds = binds#type_casted_binds(binds)
@@ -96,7 +123,7 @@ module ActiveRecord
96
123
  requested_limit = if limit_bind_index
97
124
  type_casted_binds[limit_bind_index]
98
125
  else
99
- arel.limit&.value&.value_for_database
126
+ arel.limit
100
127
  end
101
128
 
102
129
  if allowed_limit.nil?
@@ -113,11 +140,13 @@ module ActiveRecord
113
140
  sars.push(sar)
114
141
  log_mess = sar.path.split('?', 2)
115
142
  log("#{sar.method} #{log_mess[0]} #{(log_mess[1] && !log_mess[1].empty?) ? MessagePack.unpack(CGI.unescape(log_mess[1])) : '' }", name) do
116
- response = @connection.send_request(sar)
117
- if response.is_a?(Net::HTTPNoContent)
118
- nil
119
- else
120
- JSON.parse(response.body)
143
+ with_raw_connection do |conn|
144
+ response = conn.send_request(sar)
145
+ if response.is_a?(Net::HTTPNoContent)
146
+ nil
147
+ else
148
+ JSON.parse(response.body)
149
+ end
121
150
  end
122
151
  end
123
152
  }
@@ -142,21 +171,21 @@ module ActiveRecord
142
171
 
143
172
  if sars[0].instance_variable_defined?(:@sunstone_calculation) && sars[0].instance_variable_get(:@sunstone_calculation)
144
173
  # this is a count, min, max.... yea i know..
145
- ActiveRecord::Result.new(['all'], [result], {:all => type_map.lookup('integer', {})})
174
+ ActiveRecord::Result.new(['all'], [result], {:all => @type_map.lookup('integer', {})})
146
175
  elsif result.is_a?(Array)
147
176
  ActiveRecord::Result.new(result[0] ? result[0].keys : [], result.map{|r| r.values})
148
177
  else
149
- ActiveRecord::Result.new(result.keys, [result])
178
+ ActiveRecord::Result.new(result.keys, [result.values])
150
179
  end
151
180
  end
152
181
 
153
182
  def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
154
183
  sar, binds = to_sar_and_binds(arel, binds)
155
184
  value = exec_insert(sar, name, binds, pk, sequence_name)
185
+
186
+ return returning_column_values(value) unless returning.nil?
187
+
156
188
  id_value || last_inserted_id(value)
157
-
158
- # value = exec_insert(arel, name, binds, pk, sequence_name)
159
- # id_value || last_inserted_id(value)
160
189
  end
161
190
 
162
191
  def update(arel, name = nil, binds = [])
@@ -172,6 +201,10 @@ module ActiveRecord
172
201
  row && row['id']
173
202
  end
174
203
 
204
+ def returning_column_values(result)
205
+ result.rows.first
206
+ end
207
+
175
208
  end
176
209
  end
177
210
  end