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