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