sunstone 6.1.3 → 7.1.0.1

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 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