sunstone 8.0.0 → 8.1.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/README.md +221 -0
  4. data/ext/active_record/associations/collection_association.rb +45 -63
  5. data/ext/active_record/associations/has_many_through_association.rb +21 -0
  6. data/ext/active_record/associations.rb +12 -10
  7. data/ext/active_record/attribute_methods.rb +4 -2
  8. data/ext/active_record/base.rb +16 -0
  9. data/ext/active_record/callbacks.rb +4 -2
  10. data/ext/active_record/locking/optimistic.rb +60 -0
  11. data/ext/active_record/persistence.rb +35 -12
  12. data/ext/active_record/relation/calculations.rb +26 -24
  13. data/ext/active_record/relation/finder_methods.rb +165 -0
  14. data/ext/active_record/relation/predicate_builder.rb +91 -0
  15. data/ext/active_record/relation/query_methods.rb +6 -1
  16. data/ext/active_record/relation.rb +5 -0
  17. data/ext/active_record/statement_cache.rb +11 -3
  18. data/ext/active_record/transactions.rb +29 -15
  19. data/ext/active_support/core_ext/object/to_query.rb +2 -0
  20. data/ext/arel/attributes/empty_relation.rb +2 -0
  21. data/ext/arel/nodes/eager_load.rb +2 -0
  22. data/ext/arel/nodes/select_statement.rb +2 -0
  23. data/ext/arel/select_manager.rb +2 -0
  24. data/lib/active_record/connection_adapters/sunstone/column.rb +4 -1
  25. data/lib/active_record/connection_adapters/sunstone/database_statements.rb +12 -1
  26. data/lib/active_record/connection_adapters/sunstone/quoting.rb +2 -0
  27. data/lib/active_record/connection_adapters/sunstone/schema_dumper.rb +2 -0
  28. data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +6 -4
  29. data/lib/active_record/connection_adapters/sunstone/type/array.rb +2 -0
  30. data/lib/active_record/connection_adapters/sunstone/type/binary.rb +2 -0
  31. data/lib/active_record/connection_adapters/sunstone/type/date_time.rb +2 -0
  32. data/lib/active_record/connection_adapters/sunstone/type/ewkb.rb +2 -0
  33. data/lib/active_record/connection_adapters/sunstone/type/json.rb +2 -0
  34. data/lib/active_record/connection_adapters/sunstone/type/uuid.rb +2 -0
  35. data/lib/active_record/connection_adapters/sunstone/type_metadata.rb +2 -0
  36. data/lib/active_record/connection_adapters/sunstone_adapter.rb +2 -0
  37. data/lib/arel/collectors/sunstone.rb +15 -5
  38. data/lib/arel/visitors/sunstone.rb +2 -3
  39. data/lib/sunstone/connection.rb +2 -0
  40. data/lib/sunstone/exception.rb +2 -0
  41. data/lib/sunstone/gis.rb +2 -0
  42. data/lib/sunstone/version.rb +3 -1
  43. data/lib/sunstone.rb +9 -1
  44. metadata +23 -16
  45. data/ext/active_record/finder_methods.rb +0 -246
@@ -1,3 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The last ref that this code was synced with Rails
4
+ # ref: 90a1eaa1b3
5
+
1
6
  module ActiveRecord
2
7
  # = Active Record \Persistence
3
8
  module Persistence
@@ -59,7 +64,7 @@ module ActiveRecord
59
64
 
60
65
  result = new_record? ? _create_record(&block) : _update_record(&block)
61
66
 
62
- if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && result != 0
67
+ if self.sunstone? && result != 0 && !result[0].nil?
63
68
  row_hash = result[0]
64
69
 
65
70
  seen = Hash.new { |h, parent_klass|
@@ -70,7 +75,7 @@ module ActiveRecord
70
75
 
71
76
  model_cache = Hash.new { |h,klass| h[klass] = {} }
72
77
  parents = model_cache[self.class.base_class]
73
-
78
+
74
79
  row_hash.each do |key, value|
75
80
  if self.class.column_names.include?(key.to_s)
76
81
  _write_attribute(key, value)
@@ -105,7 +110,7 @@ module ActiveRecord
105
110
  attribute_names = attributes_for_create(attribute_names)
106
111
  attribute_values = attributes_with_values(attribute_names)
107
112
  returning_values = nil
108
-
113
+
109
114
  self.class.with_connection do |connection|
110
115
  returning_columns = self.class._returning_columns_for_insert(connection)
111
116
 
@@ -115,25 +120,41 @@ module ActiveRecord
115
120
  returning_columns
116
121
  )
117
122
 
118
- if !self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
123
+ if !self.sunstone?
119
124
  returning_columns.zip(returning_values).each do |column, value|
120
- _write_attribute(column, value) if !_read_attribute(column)
125
+ _write_attribute(column, type_for_attribute(column).deserialize(value)) if !_read_attribute(column)
121
126
  end if returning_values
122
127
  end
123
128
  end
124
129
 
125
130
  @new_record = false
126
131
  @previously_new_record = true
127
-
132
+
128
133
  yield(self) if block_given?
129
-
130
- if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
134
+
135
+ if self.sunstone?
131
136
  returning_values
132
137
  else
133
138
  id
134
139
  end
135
140
  end
136
141
 
142
+ def _touch_row(attribute_names, time)
143
+ time ||= current_time_from_proper_timezone
144
+
145
+ attribute_names.each do |attr_name|
146
+ _write_attribute(attr_name, time)
147
+ end
148
+
149
+ _update_row(attributes_with_values(attribute_names), "touch")
150
+ end
151
+
152
+ # Sunstone passes the values, not just the names. This is because if a
153
+ # sub resource has changed it'll send the whole shabang
154
+ def _update_row(attribute_values, attempted_action = "update")
155
+ self.class._update_record(attribute_values, _query_constraints_hash)
156
+ end
157
+
137
158
  def _update_record(attribute_names = self.attribute_names)
138
159
  attribute_names = attributes_for_update(attribute_names)
139
160
  attribute_values = attributes_with_values(attribute_names)
@@ -142,8 +163,10 @@ module ActiveRecord
142
163
  affected_rows = 0
143
164
  @_trigger_update_callback = true
144
165
  else
145
- affected_rows = self.class._update_record(attribute_values, _query_constraints_hash)
146
- @_trigger_update_callback = affected_rows == 1
166
+ affected_rows = _update_row(attribute_values)
167
+
168
+ # Suntone returns the row(s) not a int of afftecd_rows
169
+ @_trigger_update_callback = (sunstone? ? affected_rows.rows.size : affected_rows) == 1
147
170
  end
148
171
 
149
172
  @previously_new_record = false
@@ -179,7 +202,7 @@ module ActiveRecord
179
202
 
180
203
  end
181
204
  end
182
-
205
+
183
206
  #!!!! TODO: I am duplicated from finder_methods.....
184
207
  def construct_association(parent, reflection, attributes, seen, model_cache)
185
208
  return if attributes.nil?
@@ -231,6 +254,6 @@ module ActiveRecord
231
254
  other.set_inverse_instance(model)
232
255
  model
233
256
  end
234
-
257
+
235
258
  end
236
259
  end
@@ -1,30 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # The last ref that this code was synced with Rails
2
- # ref: 9269f634d471ad6ca46752421eabd3e1c26220b5
4
+ # ref: 90a1eaa1b3
3
5
 
4
6
  module ActiveRecord
5
7
  module Calculations
6
8
 
7
- # Prior to Rails 8 we didn't need this method becuase it would
8
- # return the first value if there was just one - so we'll just
9
- # do the same as prevously because it doesn't have to be joined
10
- def select_for_count
11
- if select_values.empty?
12
- :all
13
- else
14
- with_connection do |conn|
15
- # Rails compiles this to a string, but we don't have string we
16
- # have a hash
17
- if model.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
18
- sv = arel_columns(select_values)
19
- sv.one? ? sv.first : sv
20
- else
21
- sv = arel_columns(select_values).map { |column| conn.visitor.compile(column) }
22
- sv.one? ? sv.first : sv.join(", ")
23
- end
24
- end
25
- end
26
- end
27
-
28
9
  def pluck(*column_names)
29
10
  if @none
30
11
  if @async
@@ -46,7 +27,7 @@ module ActiveRecord
46
27
  if has_include?(column_names.first)
47
28
  relation = apply_join_dependency
48
29
  relation.pluck(*column_names)
49
- elsif model.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
30
+ elsif model.sunstone?
50
31
  load
51
32
  return records.pluck(*column_names.map{|n| n.to_s.sub(/^#{model.table_name}\./, "")})
52
33
  else
@@ -55,7 +36,11 @@ module ActiveRecord
55
36
  columns = relation.arel_columns(column_names)
56
37
  relation.select_values = columns
57
38
  result = skip_query_cache_if_necessary do
58
- if where_clause.contradiction?
39
+ # TODO: drop this Rails 8.0 compatibility guard when Rails 8.0 support is
40
+ # dropped, and call possible_aggregation?(column_names) directly.
41
+ # possible_aggregation? was added in Rails 8.1; on 8.0 a contradiction
42
+ # short-circuits to an empty result unconditionally.
43
+ if where_clause.contradiction? && !(respond_to?(:possible_aggregation?, true) && possible_aggregation?(column_names))
59
44
  ActiveRecord::Result.empty(async: @async)
60
45
  else
61
46
  model.with_connection do |c|
@@ -69,5 +54,22 @@ module ActiveRecord
69
54
  end
70
55
  end
71
56
 
57
+ private
58
+
59
+ # Prior to Rails 8 we didn't need this method becuase it would
60
+ # return the first value if there was just one - so we'll just
61
+ # do the same as prevously because it doesn't have to be joined
62
+ def select_for_count
63
+ if select_values.empty?
64
+ :all
65
+ elsif model.sunstone?
66
+ select_values.one? ? select_values.first : select_values
67
+ else
68
+ with_connection do |conn|
69
+ arel_columns(select_values).map { |column| conn.visitor.compile(column) }.join(", ")
70
+ end
71
+ end
72
+ end
73
+
72
74
  end
73
75
  end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The last ref that this code was synced with Rails
4
+ # ref: 90a1eaa1b3
5
+
6
+ module ActiveRecord::FinderMethods
7
+ class SunstoneJoinDependency
8
+ def initialize(klass)
9
+ @klass = klass
10
+ end
11
+
12
+ def reflections
13
+ []
14
+ end
15
+
16
+ def apply_column_aliases(relation)
17
+ relation
18
+ end
19
+
20
+ def instantiate(result_set, strict_loading_value, &block)
21
+ seen = Hash.new { |i, object_id|
22
+ i[object_id] = Hash.new { |j, child_class|
23
+ j[child_class] = {}
24
+ }
25
+ }
26
+
27
+ model_cache = Hash.new { |h, klass| h[klass] = {} }
28
+ parents = model_cache[@klass]
29
+
30
+ message_bus = ActiveSupport::Notifications.instrumenter
31
+
32
+ payload = {
33
+ record_count: result_set.length,
34
+ class_name: @klass.name
35
+ }
36
+
37
+ message_bus.instrument("instantiation.active_record", payload) do
38
+ result_set.each { |row_hash|
39
+ parent_key = @klass.primary_key ? row_hash[@klass.primary_key] : row_hash
40
+ parent = parents[parent_key] ||= @klass.instantiate(row_hash.select{|k,v| @klass.column_names.include?(k.to_s) }, &block)
41
+ construct(parent, row_hash.select{|k,v| !@klass.column_names.include?(k.to_s) }, seen, model_cache, strict_loading_value)
42
+ }
43
+ end
44
+
45
+ parents.values
46
+ end
47
+
48
+ def construct(parent, relations, seen, model_cache, strict_loading_value)
49
+ relations.each do |key, attributes|
50
+ reflection = parent.class.reflect_on_association(key)
51
+ next unless reflection
52
+
53
+ if reflection.collection?
54
+ other = parent.association(reflection.name)
55
+ other.loaded!
56
+ else
57
+ if parent.association_cached?(reflection.name)
58
+ model = parent.association(reflection.name).target
59
+ construct(model, attributes.select{|k,v| !model.class.column_names.include?(k.to_s) }, seen, model_cache, strict_loading_value)
60
+ end
61
+ end
62
+
63
+ if !reflection.collection?
64
+ construct_association(parent, reflection, attributes, seen, model_cache, strict_loading_value)
65
+ else
66
+ attributes.each do |row|
67
+ construct_association(parent, reflection, row, seen, model_cache, strict_loading_value)
68
+ end
69
+ end
70
+
71
+ end
72
+ end
73
+
74
+ def construct_association(parent, reflection, attributes, seen, model_cache, strict_loading_value)
75
+ return if attributes.nil?
76
+
77
+ klass = if reflection.polymorphic?
78
+ parent.send(reflection.foreign_type).constantize.base_class
79
+ else
80
+ reflection.klass
81
+ end
82
+ id = attributes[klass.primary_key]
83
+ model = seen[parent.object_id][klass][id]
84
+
85
+ if model
86
+ construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache, strict_loading_value)
87
+
88
+ other = parent.association(reflection.name)
89
+
90
+ if reflection.collection?
91
+ other.target.push(model)
92
+ else
93
+ other.target = model
94
+ end
95
+
96
+ other.set_inverse_instance(model)
97
+ else
98
+ model = construct_model(parent, reflection, id, attributes.select{|k,v| klass.column_names.include?(k.to_s) }, seen, model_cache, strict_loading_value)
99
+ seen[parent.object_id][model.class.base_class][id] = model
100
+ construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache, strict_loading_value)
101
+ end
102
+ end
103
+
104
+
105
+ def construct_model(record, reflection, id, attributes, seen, model_cache, strict_loading_value)
106
+ klass = if reflection.polymorphic?
107
+ record.send(reflection.foreign_type).constantize
108
+ else
109
+ reflection.klass
110
+ end
111
+
112
+ model = model_cache[klass][id] ||= klass.instantiate(attributes)
113
+ other = record.association(reflection.name)
114
+
115
+ if reflection.collection?
116
+ other.target.push(model)
117
+ else
118
+ other.target = model
119
+ end
120
+
121
+ other.set_inverse_instance(model)
122
+ model
123
+ end
124
+
125
+ end
126
+
127
+ private
128
+
129
+ def apply_join_dependency(eager_loading: group_values.empty?)
130
+ if model.sunstone?
131
+ join_dependency = SunstoneJoinDependency.new(base_class)
132
+ relation = except(:includes, :eager_load, :preload)
133
+ relation.arel.eager_load = Arel::Nodes::EagerLoad.new(eager_load_values)
134
+ else
135
+ join_dependency = construct_join_dependency(
136
+ eager_load_values | includes_values, Arel::Nodes::OuterJoin
137
+ )
138
+ relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
139
+
140
+ if eager_loading && has_limit_or_offset? && !(
141
+ using_limitable_reflections?(join_dependency.reflections) &&
142
+ using_limitable_reflections?(
143
+ construct_join_dependency(
144
+ select_association_list(joins_values).concat(
145
+ select_association_list(left_outer_joins_values)
146
+ ), nil
147
+ ).reflections
148
+ )
149
+ )
150
+ relation = skip_query_cache_if_necessary do
151
+ model.with_connection do |c|
152
+ c.distinct_relation_for_primary_key(relation)
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ if block_given?
159
+ yield relation, join_dependency
160
+ else
161
+ relation
162
+ end
163
+ end
164
+
165
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The last ref that this code was synced with Rails
4
+ # ref: 90a1eaa1b3
5
+
6
+ class ActiveRecord::PredicateBuilder # :nodoc:
7
+
8
+ def expand_from_hash(attributes, &block)
9
+ return [Arel.sql("1=0", retryable: true)] if attributes.empty?
10
+
11
+ attributes.flat_map do |key, value|
12
+ if key.is_a?(Array) && key.size == 1
13
+ key = key.first
14
+ value = value.flatten
15
+ end
16
+
17
+ if key.is_a?(Array)
18
+ queries = Array(value).map do |ids_set|
19
+ raise ArgumentError, "Expected corresponding value for #{key} to be an Array" unless ids_set.is_a?(Array)
20
+ expand_from_hash(key.zip(ids_set).to_h)
21
+ end
22
+ grouping_queries(queries)
23
+ elsif value.is_a?(Hash) && !table.has_column?(key)
24
+ ka = table.associated_table(key, &block)
25
+ .predicate_builder.expand_from_hash(value.stringify_keys)
26
+
27
+ if self.table.instance_variable_get(:@klass).sunstone?
28
+ ka.each { |k|
29
+ if k.left.is_a?(Arel::Attributes::Attribute) || k.left.is_a?(Arel::Attributes::Relation)
30
+ k.left = Arel::Attributes::Relation.new(k.left, key)
31
+ end
32
+ }
33
+ end
34
+ ka
35
+ # TODO: drop this Rails 8.0 compatibility branch when Rails 8.0 support is
36
+ # dropped, and always use table.associated_with(key). (8.0 named it associated_with?)
37
+ elsif (associated_reflection = (table.respond_to?(:associated_with) ? table.associated_with(key) : table.associated_with?(key)))
38
+ # Find the foreign key when using queries such as:
39
+ # Post.where(author: author)
40
+ #
41
+ # For polymorphic relationships, find the foreign key and type:
42
+ # PriceEstimate.where(estimate_of: treasure)
43
+
44
+ if associated_reflection.polymorphic?
45
+ value = [value] unless value.is_a?(Array)
46
+ klass = PolymorphicArrayValue
47
+ elsif associated_reflection.through_reflection?
48
+ associated_table = table.associated_table(key)
49
+
50
+ next associated_table.predicate_builder.expand_from_hash(
51
+ associated_table.primary_key => value
52
+ )
53
+ end
54
+
55
+ klass ||= AssociationQueryValue
56
+ # TODO: drop this Rails 8.0 compatibility branch when Rails 8.0 support is
57
+ # dropped, and always pass associated_reflection.
58
+ # Rails 8.1 threads the reflection through the value objects; 8.0 threads the table metadata.
59
+ query_source = table.respond_to?(:associated_with) ? associated_reflection : table.associated_table(key)
60
+ queries = klass.new(query_source, value).queries.map! do |query|
61
+ # If the query produced is identical to attributes don't go any deeper.
62
+ # Prevents stack level too deep errors when association and foreign_key are identical.
63
+ query == attributes ? self[key, value] : expand_from_hash(query)
64
+ end
65
+
66
+ grouping_queries(queries)
67
+ elsif table.aggregated_with?(key)
68
+ mapping = table.reflect_on_aggregation(key).mapping
69
+ values = value.nil? ? [nil] : Array.wrap(value)
70
+ if mapping.length == 1 || values.empty?
71
+ column_name, aggr_attr = mapping.first
72
+ values = values.map do |object|
73
+ object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object
74
+ end
75
+ self[column_name, values]
76
+ else
77
+ queries = values.map do |object|
78
+ mapping.map do |field_attr, aggregate_attr|
79
+ self[field_attr, object.try!(aggregate_attr)]
80
+ end
81
+ end
82
+
83
+ grouping_queries(queries)
84
+ end
85
+ else
86
+ self[key, value]
87
+ end
88
+ end
89
+ end
90
+
91
+ end
@@ -1,10 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The last ref that this code was synced with Rails
4
+ # ref: 90a1eaa1b3
5
+
1
6
  module ActiveRecord
2
7
  module QueryMethods
3
8
  private
4
9
 
5
10
  def assert_modifiable!
6
11
  raise UnmodifiableRelation if @loaded
7
- raise UnmodifiableRelation if @arel && !model.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
12
+ raise UnmodifiableRelation if @arel && !model.sunstone?
8
13
  end
9
14
 
10
15
  end
@@ -1,3 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The last ref that this code was synced with Rails
4
+ # ref: 90a1eaa1b3
5
+
1
6
  module ActiveRecord
2
7
  class Relation
3
8
 
@@ -1,8 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The last ref that this code was synced with Rails
4
+ # ref: 90a1eaa1b3
5
+
1
6
  module ActiveRecord
2
7
  class StatementCache
3
8
  class PartialQuery
4
9
 
5
- def initialize(values, sunstone=false)
10
+ # TODO: drop this Rails 8.0 compatibility default when Rails 8.0 support is
11
+ # dropped, and make retryable: a required keyword again.
12
+ # retryable: is required on Rails 8.1 but absent from 8.0's caller.
13
+ def initialize(values, retryable: false, sunstone: false)
6
14
  @values = values
7
15
  @indexes = if sunstone
8
16
  else
@@ -10,8 +18,9 @@ module ActiveRecord
10
18
  Substitute === thing
11
19
  }.map(&:last)
12
20
  end
21
+ @retryable = retryable
13
22
  end
14
-
23
+
15
24
  def sql_for(binds, connection)
16
25
  if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
17
26
  @values
@@ -29,6 +38,5 @@ module ActiveRecord
29
38
  end
30
39
 
31
40
  end
32
-
33
41
  end
34
42
  end
@@ -1,3 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The last ref that this code was synced with Rails
4
+ # ref: 90a1eaa1b3
5
+
1
6
  require 'active_record'
2
7
  require 'active_record/transactions'
3
8
 
@@ -35,26 +40,35 @@ module ActiveRecord
35
40
 
36
41
  def with_transaction_returning_status
37
42
  self.class.with_connection do |connection|
38
- status = nil
39
- # connection = self.class.connection
40
-
41
- if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && instance_variable_defined?(:@sunstone_updating) && @sunstone_updating
42
- status = yield
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
43
+ transaction_body = proc do
44
+ status = nil
48
45
 
46
+ if sunstone? && instance_variable_defined?(:@sunstone_updating) && @sunstone_updating
49
47
  status = yield
50
- raise ActiveRecord::Rollback unless status
48
+ else
49
+ ensure_finalize = !connection.transaction_open?
50
+ connection.transaction do
51
+ add_to_transaction(ensure_finalize || has_transactional_callbacks?)
52
+ remember_transaction_record_state
53
+
54
+ status = yield
55
+ raise ActiveRecord::Rollback unless status
56
+ end
57
+ @_last_transaction_return_status = status
58
+ status
51
59
  end
52
60
  end
53
-
54
- status
61
+
62
+ # TODO: drop this Rails 8.0 compatibility branch when Rails 8.0
63
+ # support is dropped, and always use with_pool_transaction_isolation_level.
64
+ # Rails 8.1 wraps the transaction in a pool-level isolation context;
65
+ # this API doesn't exist on 8.0, so run the body directly there.
66
+ if ActiveRecord.respond_to?(:default_transaction_isolation_level)
67
+ connection.pool.with_pool_transaction_isolation_level(ActiveRecord.default_transaction_isolation_level, connection.transaction_open?, &transaction_body)
68
+ else
69
+ transaction_body.call
70
+ end
55
71
  end
56
72
  end
57
-
58
-
59
73
  end
60
74
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class NilClass
2
4
 
3
5
  def to_query(namespace)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # module Arel
2
4
  # module Attributes
3
5
  # class EmptyRelation < Attribute
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class EagerLoad < Arel::Nodes::Unary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class SelectStatement < Arel::Nodes::NodeExpression
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  class SelectManager < Arel::TreeManager
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  # Sunstone-specific extensions to column definitions in a table.
@@ -6,8 +8,9 @@ module ActiveRecord
6
8
 
7
9
  attr_reader :array
8
10
 
9
- def initialize(name, sql_type_metadata, options={})
11
+ def initialize(name, cast_type, sql_type_metadata, options={})
10
12
  @name = name.freeze
13
+ @cast_type = cast_type
11
14
  @sql_type_metadata = sql_type_metadata
12
15
  @null = options['null']
13
16
  @default = options['default'] ? JSON.generate(options['default']) : options['default']
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "arel/collectors/sql_string"
2
4
 
3
5
  module ActiveRecord
@@ -66,7 +68,7 @@ module ActiveRecord
66
68
  elsif self.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
67
69
  collector = SunstonePartialQueryCollector.new(self.collector)
68
70
  parts, binds = visitor.compile(arel.ast, collector)
69
- query = StatementCache::PartialQuery.new(parts, true)
71
+ query = StatementCache::PartialQuery.new(parts, retryable: collector.retryable, sunstone: true)
70
72
  else
71
73
  collector = klass.partial_query_collector
72
74
  parts, binds = visitor.compile(arel.ast, collector)
@@ -118,6 +120,11 @@ module ActiveRecord
118
120
  sar, binds = sar_for_insert(arel, pk, binds, returning)
119
121
  internal_exec_query(sar, name, binds)
120
122
  end
123
+
124
+ def exec_delete(arel, name = nil, binds = [])
125
+ x = internal_execute(arel, name, binds)
126
+ x.nil? ? 1 : x
127
+ end
121
128
 
122
129
  # Lowest level way to execute a query. Doesn't check for illegal writes, doesn't annotate queries, yields a native result object.
123
130
  def raw_execute(arel, name = nil, binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true, batch: false)
@@ -240,6 +247,10 @@ module ActiveRecord
240
247
  result.rows.first
241
248
  end
242
249
 
250
+ def write_query?(arel)
251
+ arel.request_type != Net::HTTP::Get
252
+ end
253
+
243
254
  end
244
255
  end
245
256
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module Sunstone
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module Sunstone