sunstone 2.0.4 → 5.0.0.beta3
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 +46 -0
- data/ext/active_record/attribute_methods.rb +137 -0
- data/ext/active_record/calculations.rb +5 -1
- data/ext/active_record/finder_methods.rb +2 -3
- data/ext/active_record/persistence.rb +21 -0
- data/ext/active_record/query_methods.rb +9 -2
- data/ext/active_record/relation.rb +3 -3
- data/ext/active_record/statement_cache.rb +1 -1
- data/ext/active_support/core_ext/object/to_query.rb +14 -1
- data/ext/arel/attributes/relation.rb +30 -0
- data/lib/active_record/connection_adapters/sunstone/column.rb +11 -9
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +1 -6
- data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +21 -4
- data/lib/active_record/connection_adapters/sunstone/type/array.rb +52 -10
- data/lib/active_record/connection_adapters/sunstone/type/date_time.rb +1 -1
- data/lib/active_record/connection_adapters/sunstone/type/ewkb.rb +1 -1
- data/lib/active_record/connection_adapters/sunstone/type_metadata.rb +15 -0
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +21 -5
- data/lib/arel/collectors/sunstone.rb +29 -9
- data/lib/arel/visitors/sunstone.rb +285 -56
- data/lib/sunstone.rb +6 -0
- data/lib/sunstone/connection.rb +7 -8
- data/lib/sunstone/exception.rb +0 -5
- data/lib/sunstone/version.rb +1 -1
- data/sunstone.gemspec +5 -4
- metadata +32 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5c130a7d5b7307e472bd22688ee0b8621db478e
|
4
|
+
data.tar.gz: a3fde9dce1b08795ea7ff9a1217921fb57c099ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 383524737f0c0fefbec2c99d62d35ce23c6e3060f772e11ebac65418493cf2ee892e34cd637a6f86bbf5439275103c986887f4dd05494cb223a8cc51a9b67349
|
7
|
+
data.tar.gz: df9fe4e2e39011303804a12fe26b49b99c84c3651c017a202fbcec907b8439708f4ae04ca72400c47cc5031687de9c179495e23a5644a71ec6666ff69bcd1590
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class CollectionAssociation
|
4
|
+
|
5
|
+
def replace(other_array)
|
6
|
+
other_array.each { |val| raise_on_type_mismatch!(val) }
|
7
|
+
original_target = load_target.dup
|
8
|
+
|
9
|
+
if owner.instance_variable_get(:@updateing)
|
10
|
+
replace_common_records_in_memory(other_array, original_target)
|
11
|
+
concat(other_array - original_target)
|
12
|
+
other_array
|
13
|
+
elsif owner.new_record?
|
14
|
+
replace_records(other_array, original_target)
|
15
|
+
else
|
16
|
+
replace_common_records_in_memory(other_array, original_target)
|
17
|
+
if other_array != original_target
|
18
|
+
transaction { replace_records(other_array, original_target) }
|
19
|
+
else
|
20
|
+
other_array
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module ActiveRecord
|
30
|
+
module Persistence
|
31
|
+
# Updates the attributes of the model from the passed-in hash and saves the
|
32
|
+
# record, all wrapped in a transaction. If the object is invalid, the saving
|
33
|
+
# will fail and false will be returned.
|
34
|
+
def update(attributes)
|
35
|
+
@updateing = true
|
36
|
+
# The following transaction covers any possible database side-effects of the
|
37
|
+
# attributes assignment. For example, setting the IDs of a child collection.
|
38
|
+
with_transaction_returning_status do
|
39
|
+
assign_attributes(attributes)
|
40
|
+
save
|
41
|
+
end
|
42
|
+
ensure
|
43
|
+
@updateing = false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
# Returns a Hash of the Arel::Attributes and attribute values that have been
|
7
|
+
# typecasted for use in an Arel insert/update method.
|
8
|
+
def arel_attributes_with_values(attribute_names)
|
9
|
+
attrs = {}
|
10
|
+
arel_table = self.class.arel_table
|
11
|
+
|
12
|
+
attribute_names.each do |name|
|
13
|
+
attrs[arel_table[name]] = typecasted_attribute_value(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
17
|
+
self.class.reflect_on_all_associations.each do |reflection|
|
18
|
+
if reflection.belongs_to?
|
19
|
+
add_attributes_for_belongs_to_association(reflection, attrs)
|
20
|
+
elsif reflection.has_one?
|
21
|
+
add_attributes_for_has_one_association(reflection, attrs)
|
22
|
+
elsif reflection.collection?
|
23
|
+
add_attributes_for_collection_association(reflection, attrs)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attrs
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_attributes_for_belongs_to_association(reflection, attrs)
|
32
|
+
key = :"add_attributes_for_belongs_to_association#{reflection.name}"
|
33
|
+
@_already_called ||= {}
|
34
|
+
return if @_already_called[key]
|
35
|
+
@_already_called[key]=true
|
36
|
+
@_already_called[:"autosave_associated_records_for_#{reflection.name}"] = true
|
37
|
+
|
38
|
+
association = association_instance_get(reflection.name)
|
39
|
+
record = association && association.load_target
|
40
|
+
if record && !record.destroyed?
|
41
|
+
autosave = reflection.options[:autosave]
|
42
|
+
|
43
|
+
if autosave && record.marked_for_destruction?
|
44
|
+
self[reflection.foreign_key] = nil
|
45
|
+
record.destroy
|
46
|
+
elsif autosave != false
|
47
|
+
if record.new_record? || (autosave && record.changed_for_autosave?)
|
48
|
+
if record.new_record?
|
49
|
+
record.send(:arel_attributes_with_values_for_create, record.attribute_names).each do |k, v|
|
50
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name)] = v
|
51
|
+
end
|
52
|
+
else
|
53
|
+
record.send(:arel_attributes_with_values_for_update, record.attribute_names).each do |k, v|
|
54
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name)] = v
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_attributes_for_has_one_association(reflection, attrs)
|
63
|
+
key = :"add_attributes_for_has_one_association#{reflection.name}"
|
64
|
+
@_already_called ||= {}
|
65
|
+
return if @_already_called[key]
|
66
|
+
@_already_called[key]=true
|
67
|
+
@_already_called[:"autosave_associated_records_for_#{reflection.name}"] = true
|
68
|
+
|
69
|
+
association = association_instance_get(reflection.name)
|
70
|
+
record = association && association.load_target
|
71
|
+
|
72
|
+
if record && !record.destroyed?
|
73
|
+
autosave = reflection.options[:autosave]
|
74
|
+
|
75
|
+
if autosave && record.marked_for_destruction?
|
76
|
+
record.destroy
|
77
|
+
elsif autosave != false
|
78
|
+
key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
|
79
|
+
|
80
|
+
if (autosave && record.changed_for_autosave?) || new_record? || record_changed?(reflection, record, key)
|
81
|
+
unless reflection.through_reflection
|
82
|
+
record[reflection.foreign_key] = key
|
83
|
+
end
|
84
|
+
|
85
|
+
if record.new_record?
|
86
|
+
record.send(:arel_attributes_with_values_for_create, record.attribute_names).each do |k, v|
|
87
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name)] = v
|
88
|
+
end
|
89
|
+
else
|
90
|
+
record.send(:arel_attributes_with_values_for_update, record.attribute_names).each do |k, v|
|
91
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name)] = v
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_attributes_for_collection_association(reflection, attrs)
|
100
|
+
key = :"add_attributes_for_collection_association#{reflection.name}"
|
101
|
+
@_already_called ||= {}
|
102
|
+
return if @_already_called[key]
|
103
|
+
@_already_called[key]=true
|
104
|
+
@_already_called[:"autosave_associated_records_for_#{reflection.name}"] = true
|
105
|
+
if reflection.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
|
106
|
+
@_already_called[:"autosave_associated_records_for_#{self.class.name.downcase.pluralize}_#{reflection.name}"] = true
|
107
|
+
end
|
108
|
+
|
109
|
+
if association = association_instance_get(reflection.name)
|
110
|
+
autosave = reflection.options[:autosave]
|
111
|
+
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
|
112
|
+
|
113
|
+
records.each_with_index do |record, idx|
|
114
|
+
next if record.destroyed?
|
115
|
+
|
116
|
+
if record.new_record?
|
117
|
+
record.send(:arel_attributes_with_values_for_create, record.attribute_names).each do |k, v|
|
118
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name, idx)] = v
|
119
|
+
end
|
120
|
+
else
|
121
|
+
record.send(:arel_attributes_with_values_for_update, record.attribute_names).each do |k, v|
|
122
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name, idx)] = v
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# reconstruct the scope now that we know the owner's id
|
130
|
+
association.reset_scope if association.respond_to?(:reset_scope)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -9,7 +9,11 @@ module ActiveRecord
|
|
9
9
|
# column_name.to_s
|
10
10
|
# end
|
11
11
|
# end
|
12
|
-
|
12
|
+
|
13
|
+
if loaded? && (column_names - @klass.column_names).empty?
|
14
|
+
return @records.pluck(*column_names)
|
15
|
+
end
|
16
|
+
|
13
17
|
if has_include?(column_names.first)
|
14
18
|
construct_relation_for_association_calculations.pluck(*column_names)
|
15
19
|
else
|
@@ -20,13 +20,12 @@ module ActiveRecord
|
|
20
20
|
[]
|
21
21
|
else
|
22
22
|
arel = relation.arel
|
23
|
-
rows = connection.select_all(arel, 'SQL', arel.bind_values + relation.
|
23
|
+
rows = connection.select_all(arel, 'SQL', arel.bind_values + relation.bound_attributes)
|
24
24
|
if join_dependency
|
25
25
|
join_dependency.instantiate(rows, aliases)
|
26
26
|
else
|
27
27
|
instantiate_with_associations(rows, relation)
|
28
28
|
end
|
29
|
-
|
30
29
|
end
|
31
30
|
end
|
32
31
|
end
|
@@ -58,7 +57,7 @@ module ActiveRecord
|
|
58
57
|
other = parent.association(reflection.name)
|
59
58
|
other.loaded!
|
60
59
|
else
|
61
|
-
if parent.
|
60
|
+
if parent.association_cached?(reflection.name)
|
62
61
|
model = parent.association(reflection.name).target
|
63
62
|
construct(model, attributes.select{|k,v| !reflection.klass.column_names.include?(k.to_s) }, seen, model_cache)
|
64
63
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
# = Active Record \Persistence
|
3
|
+
module Persistence
|
4
|
+
private
|
5
|
+
|
6
|
+
def create_or_update(*args)
|
7
|
+
raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
|
8
|
+
result = new_record? ? _create_record : _update_record(*args)
|
9
|
+
result != false
|
10
|
+
rescue Sunstone::Exception::BadRequest => e
|
11
|
+
JSON.parse(e.message)['errors'].each do |field, message|
|
12
|
+
if message.is_a?(Array)
|
13
|
+
message.each { |m| errors.add(field, m) }
|
14
|
+
else
|
15
|
+
errors.add(field, message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
raise ActiveRecord::RecordInvalid
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module QueryMethods
|
3
|
-
|
3
|
+
|
4
4
|
def reverse_sql_order(order_query)
|
5
5
|
order_query = [arel_table[primary_key].asc] if order_query.empty?
|
6
6
|
|
@@ -18,6 +18,13 @@ module ActiveRecord
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
|
+
def joins(*args)
|
23
|
+
# If a joins happen with sunstone messes up visitor / collector
|
24
|
+
return self if klass.connection.class.name == "ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter"
|
25
|
+
check_if_method_has_arguments!(:joins, args)
|
26
|
+
spawn.joins!(*args)
|
27
|
+
end
|
28
|
+
|
22
29
|
end
|
23
30
|
end
|
@@ -12,13 +12,13 @@ module ActiveRecord
|
|
12
12
|
end
|
13
13
|
|
14
14
|
arel = relation.arel
|
15
|
-
binds = (arel.bind_values + relation.
|
16
|
-
binds.map! { |bv| connection.quote(
|
15
|
+
binds = connection.prepare_binds_for_database(arel.bind_values + relation.bound_attributes)
|
16
|
+
binds.map! { |bv| connection.quote(bv) }
|
17
17
|
collect = visitor.accept(arel.ast, Arel::Collectors::Bind.new)
|
18
18
|
collect.substitute_binds(binds).join
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
|
23
23
|
end
|
24
24
|
end
|
@@ -1,7 +1,20 @@
|
|
1
1
|
class NilClass
|
2
2
|
|
3
3
|
def to_query(namespace)
|
4
|
-
namespace
|
4
|
+
namespace.to_s
|
5
5
|
end
|
6
6
|
|
7
|
+
end
|
8
|
+
|
9
|
+
class Hash
|
10
|
+
|
11
|
+
def to_query(namespace = nil)
|
12
|
+
collect do |key, value|
|
13
|
+
# unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
|
14
|
+
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
|
15
|
+
# end
|
16
|
+
end.compact.sort! * '&'
|
17
|
+
end
|
18
|
+
|
19
|
+
alias_method :to_param, :to_query
|
7
20
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Arel
|
2
|
+
module Attributes
|
3
|
+
class Relation < Attribute
|
4
|
+
|
5
|
+
attr_accessor :collection
|
6
|
+
|
7
|
+
def initialize(relation, name, collection = false)
|
8
|
+
self[:relation] = relation
|
9
|
+
self[:name] = name
|
10
|
+
@collection = collection
|
11
|
+
end
|
12
|
+
|
13
|
+
def able_to_type_cast?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def table_name
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def eql? other
|
22
|
+
self.class == other.class &&
|
23
|
+
self.relation == other.relation &&
|
24
|
+
self.name == other.name &&
|
25
|
+
self.collection == other.collection
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -2,16 +2,18 @@ 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
|
-
|
7
|
-
|
5
|
+
delegate :array, to: :sql_type_metadata
|
6
|
+
alias :array? :array
|
7
|
+
|
8
|
+
def initialize(name, sql_type_metadata, options={})
|
9
|
+
@name = name.freeze
|
10
|
+
@sql_type_metadata = sql_type_metadata
|
11
|
+
@null = options['null']
|
12
|
+
@default = options['default']
|
13
|
+
@default_function = nil
|
14
|
+
@collation = nil
|
15
|
+
@table_name = nil
|
8
16
|
@primary_key = (options['primary_key'] == true)
|
9
|
-
@array = !!options['array']
|
10
|
-
if @array
|
11
|
-
super(name, options['default'], Sunstone::Type::Array.new(cast_type), nil, options['null'])
|
12
|
-
else
|
13
|
-
super(name, options['default'], cast_type, nil, options['null'])
|
14
|
-
end
|
15
17
|
end
|
16
18
|
|
17
19
|
def primary_key?
|
@@ -13,12 +13,7 @@ module ActiveRecord
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
def select_all(arel, name = nil, binds = [], &block)
|
18
|
-
exec_query(arel, name, binds)
|
19
|
-
end
|
20
|
-
|
21
|
-
def exec_query(arel, name = 'SAR', binds = [])
|
16
|
+
def exec_query(arel, name = 'SAR', binds = [], prepare: false)
|
22
17
|
sar = to_sar(arel, binds)
|
23
18
|
result = exec(sar, name)
|
24
19
|
|
@@ -15,7 +15,7 @@ module ActiveRecord
|
|
15
15
|
def columns(table_name)
|
16
16
|
# Limit, precision, and scale are all handled by the superclass.
|
17
17
|
column_definitions(table_name).map do |column_name, options|
|
18
|
-
new_column(column_name,
|
18
|
+
new_column(column_name, options)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -34,8 +34,25 @@ module ActiveRecord
|
|
34
34
|
Wankel.parse(@connection.get('/tables').body)
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
38
|
-
|
37
|
+
def views
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
|
41
|
+
def new_column(name, options)
|
42
|
+
sql_type_metadata = fetch_type_metadata(options)
|
43
|
+
SunstoneColumn.new(name, sql_type_metadata, options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_type_metadata(options)
|
47
|
+
cast_type = lookup_cast_type(options['type'])
|
48
|
+
simple_type = SqlTypeMetadata.new(
|
49
|
+
sql_type: options['type'],
|
50
|
+
type: cast_type.type,
|
51
|
+
limit: cast_type.limit,
|
52
|
+
precision: cast_type.precision,
|
53
|
+
scale: cast_type.scale,
|
54
|
+
)
|
55
|
+
SunstoneSQLTypeMetadata.new(simple_type, options)
|
39
56
|
end
|
40
57
|
|
41
58
|
def column_name_for_operation(operation, node) # :nodoc:
|
@@ -46,7 +63,7 @@ module ActiveRecord
|
|
46
63
|
|
47
64
|
# Returns just a table's primary key
|
48
65
|
def primary_key(table)
|
49
|
-
columns(table).find{ |c| c.primary_key? }.name
|
66
|
+
columns(table).find{ |c| c.primary_key? }.try(:name)
|
50
67
|
end
|
51
68
|
|
52
69
|
end
|