sunstone 5.0.0.beta3 → 5.0.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 +4 -4
- data/.gitignore +1 -0
- data/.tm_properties +1 -0
- data/.travis.yml +36 -0
- data/README.md +1 -2
- data/Rakefile.rb +1 -1
- data/ext/active_record/associations/collection_association.rb +48 -6
- data/ext/active_record/attribute_methods.rb +25 -21
- data/ext/active_record/callbacks.rb +17 -0
- data/ext/active_record/finder_methods.rb +44 -2
- data/ext/active_record/persistence.rb +127 -1
- data/ext/active_record/relation.rb +13 -5
- data/ext/active_record/relation/calculations.rb +25 -0
- data/ext/active_record/statement_cache.rb +3 -2
- data/ext/active_record/transactions.rb +60 -0
- data/ext/arel/attributes/empty_relation.rb +31 -0
- data/ext/arel/attributes/relation.rb +3 -2
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +13 -2
- data/lib/active_record/connection_adapters/sunstone/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sunstone/type/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +54 -30
- data/lib/arel/collectors/sunstone.rb +6 -4
- data/lib/arel/visitors/sunstone.rb +61 -39
- data/lib/sunstone.rb +18 -11
- data/lib/sunstone/connection.rb +62 -22
- data/lib/sunstone/exception.rb +3 -0
- data/lib/sunstone/gis.rb +1 -0
- data/lib/sunstone/version.rb +2 -2
- data/sunstone.gemspec +4 -5
- data/test/active_record/associations/has_and_belongs_to_many_test.rb +12 -0
- data/test/active_record/associations/has_many_test.rb +72 -0
- data/test/active_record/eager_loading_test.rb +15 -0
- data/test/active_record/persistance_test.rb +190 -0
- data/test/active_record/preload_test.rb +16 -0
- data/test/active_record/query_test.rb +91 -0
- data/test/models.rb +91 -0
- data/test/sunstone/connection/configuration_test.rb +44 -0
- data/test/sunstone/connection/cookie_store_test.rb +37 -0
- data/test/sunstone/connection/request_helper_test.rb +105 -0
- data/test/sunstone/connection/send_request_test.rb +164 -0
- data/test/sunstone/connection_test.rb +2 -298
- data/test/test_helper.rb +45 -2
- metadata +52 -47
- data/ext/active_record/associations/builder/has_and_belongs_to_many.rb +0 -48
- data/ext/active_record/calculations.rb +0 -32
- data/ext/active_record/query_methods.rb +0 -30
- data/ext/active_record/relation/predicate_builder.rb +0 -23
- data/test/models/ship.rb +0 -14
- data/test/query_test.rb +0 -134
- data/test/sunstone/parser_test.rb +0 -124
- data/test/sunstone_test.rb +0 -303
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1fc21e0215013059317cc971ba06e8a221343e2
|
4
|
+
data.tar.gz: 9c9f8128129d8d9ff50e398f7982f9288573a41f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccb44a14900ab3434926246a341740026723695e868283a0d09f3b4d6e41700da0aaf2f77f61c4bc69ca6fe3cdeee5204924fc67695b5ddcc09c211ae4a466a4
|
7
|
+
data.tar.gz: 2fb90af0945f9c7ae8dbd1dad2dc7c0072efa24dcd2bd3cf1b76507fb6754e4a06f6093117d2e94c5900624f7083effdcaab8d02a00ff648c28e268fa2fc46b7
|
data/.gitignore
CHANGED
data/.tm_properties
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
exclude = '{$exclude,log,bin,tmp,.tm_properties,coverage}'
|
data/.travis.yml
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm: 2.3.1
|
3
|
+
|
4
|
+
cache:
|
5
|
+
bundler: true
|
6
|
+
directories:
|
7
|
+
- /home/travis/.rvm/gems
|
8
|
+
|
9
|
+
addons:
|
10
|
+
postgresql: "9.4"
|
11
|
+
|
12
|
+
before_install:
|
13
|
+
- unset BUNDLE_GEMFILE
|
14
|
+
|
15
|
+
install:
|
16
|
+
- git clone https://github.com/rails/rails.git ~/build/rails
|
17
|
+
|
18
|
+
before_script:
|
19
|
+
- export RAILS_VERSION=`cat sunstone.gemspec | grep activerecord | grep -ow "[0-9\.]\{1,\}"`
|
20
|
+
- pushd ~/build/rails
|
21
|
+
- git checkout v$RAILS_VERSION
|
22
|
+
- sed -i "/require 'support\/connection'/a \$LOAD_PATH.unshift\(File.expand_path\('~\/build\/malomalo\/sunstone\/lib'\)\)\nrequire 'sunstone'" ~/build/rails/activerecord/test/cases/helper.rb
|
23
|
+
- cat ~/build/rails/Gemfile
|
24
|
+
- "sed -i \"/group :db do/a gem 'sunstone', path: File.expand_path\\('~\\/build\\/malomalo\\/sunstone'\\)\" ~/build/rails/Gemfile"
|
25
|
+
- cat ~/build/rails/Gemfile
|
26
|
+
- bundle install --jobs=3 --retry=3
|
27
|
+
- createdb activerecord_unittest
|
28
|
+
- createdb activerecord_unittest2
|
29
|
+
- mysql -e "create database IF NOT EXISTS activerecord_unittest DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci;"
|
30
|
+
- mysql -e "create database IF NOT EXISTS activerecord_unittest2 DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci;"
|
31
|
+
- gem environment gempath
|
32
|
+
- popd
|
33
|
+
- bundle install --jobs=3 --retry=3
|
34
|
+
- gem environment gempath
|
35
|
+
|
36
|
+
script: bundle exec rake test && cd ~/build/rails/activerecord && bundle exec rake test --verbose
|
data/README.md
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
Sunstone
|
2
|
-
========
|
1
|
+
# Sunstone [](https://travis-ci.org/malomalo/sunstone)
|
3
2
|
|
4
3
|
An [ActiveRecord](https://rubygems.org/gems/activerecord) adapter for quering
|
5
4
|
APIs over Standard API (https://github.com/waratuman/standardapi).
|
data/Rakefile.rb
CHANGED
@@ -6,12 +6,22 @@ module ActiveRecord
|
|
6
6
|
other_array.each { |val| raise_on_type_mismatch!(val) }
|
7
7
|
original_target = load_target.dup
|
8
8
|
|
9
|
-
if owner.
|
9
|
+
if owner.new_record?
|
10
|
+
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)
|
10
12
|
replace_common_records_in_memory(other_array, original_target)
|
11
|
-
|
13
|
+
|
14
|
+
# Remove from target
|
15
|
+
(original_target - other_array).each { |record| callback(:before_remove, record) }
|
16
|
+
(original_target - other_array).each { |record| target.delete(record) }
|
17
|
+
(original_target - other_array).each { |record| callback(:after_remove, record) }
|
18
|
+
|
19
|
+
# Add to target
|
20
|
+
(other_array - original_target).each do |record|
|
21
|
+
add_to_target(record)
|
22
|
+
end
|
23
|
+
|
12
24
|
other_array
|
13
|
-
elsif owner.new_record?
|
14
|
-
replace_records(other_array, original_target)
|
15
25
|
else
|
16
26
|
replace_common_records_in_memory(other_array, original_target)
|
17
27
|
if other_array != original_target
|
@@ -22,17 +32,47 @@ module ActiveRecord
|
|
22
32
|
end
|
23
33
|
end
|
24
34
|
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class HasManyAssociation
|
39
|
+
|
40
|
+
def insert_record(record, validate = true, raise = false)
|
41
|
+
set_owner_attributes(record)
|
42
|
+
set_inverse_instance(record)
|
43
|
+
|
44
|
+
if record.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && (!owner.instance_variable_defined?(:@updating) && owner.instance_variable_get(:@updating))
|
45
|
+
true
|
46
|
+
elsif raise
|
47
|
+
record.save!(:validate => validate)
|
48
|
+
else
|
49
|
+
record.save(:validate => validate)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def save_through_record(record)
|
55
|
+
return if record.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
56
|
+
build_through_record(record).save!
|
57
|
+
ensure
|
58
|
+
@through_records.delete(record.object_id)
|
59
|
+
end
|
60
|
+
|
25
61
|
end
|
62
|
+
|
26
63
|
end
|
27
64
|
end
|
28
65
|
|
29
66
|
module ActiveRecord
|
30
67
|
module Persistence
|
68
|
+
|
31
69
|
# Updates the attributes of the model from the passed-in hash and saves the
|
32
70
|
# record, all wrapped in a transaction. If the object is invalid, the saving
|
33
71
|
# will fail and false will be returned.
|
34
72
|
def update(attributes)
|
35
|
-
@
|
73
|
+
@updating = :updating
|
74
|
+
$updating_model = self
|
75
|
+
|
36
76
|
# The following transaction covers any possible database side-effects of the
|
37
77
|
# attributes assignment. For example, setting the IDs of a child collection.
|
38
78
|
with_transaction_returning_status do
|
@@ -40,7 +80,9 @@ module ActiveRecord
|
|
40
80
|
save
|
41
81
|
end
|
42
82
|
ensure
|
43
|
-
@
|
83
|
+
@updating = false
|
84
|
+
$updating_model = nil
|
44
85
|
end
|
86
|
+
|
45
87
|
end
|
46
88
|
end
|
@@ -12,15 +12,19 @@ module ActiveRecord
|
|
12
12
|
attribute_names.each do |name|
|
13
13
|
attrs[arel_table[name]] = typecasted_attribute_value(name)
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
17
17
|
self.class.reflect_on_all_associations.each do |reflection|
|
18
18
|
if reflection.belongs_to?
|
19
|
-
|
19
|
+
if association(reflection.name).loaded? && association(reflection.name).target == $updating_model
|
20
|
+
attrs.delete(arel_table[reflection.foreign_key])
|
21
|
+
else
|
22
|
+
add_attributes_for_belongs_to_association(reflection, attrs)
|
23
|
+
end
|
20
24
|
elsif reflection.has_one?
|
21
25
|
add_attributes_for_has_one_association(reflection, attrs)
|
22
26
|
elsif reflection.collection?
|
23
|
-
add_attributes_for_collection_association(reflection, attrs)
|
27
|
+
add_attributes_for_collection_association(reflection, attrs, arel_table)
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -29,7 +33,7 @@ module ActiveRecord
|
|
29
33
|
end
|
30
34
|
|
31
35
|
def add_attributes_for_belongs_to_association(reflection, attrs)
|
32
|
-
key = :"
|
36
|
+
key = :"add_attributes_for_belongs_to_association_#{reflection.name}"
|
33
37
|
@_already_called ||= {}
|
34
38
|
return if @_already_called[key]
|
35
39
|
@_already_called[key]=true
|
@@ -47,11 +51,11 @@ module ActiveRecord
|
|
47
51
|
if record.new_record? || (autosave && record.changed_for_autosave?)
|
48
52
|
if record.new_record?
|
49
53
|
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
|
54
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name, false, true)] = v
|
51
55
|
end
|
52
56
|
else
|
53
57
|
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
|
58
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name, false, true)] = v
|
55
59
|
end
|
56
60
|
end
|
57
61
|
end
|
@@ -84,11 +88,11 @@ module ActiveRecord
|
|
84
88
|
|
85
89
|
if record.new_record?
|
86
90
|
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
|
91
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name, false, true)] = v
|
88
92
|
end
|
89
93
|
else
|
90
94
|
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
|
95
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name, false, true)] = v
|
92
96
|
end
|
93
97
|
end
|
94
98
|
end
|
@@ -96,7 +100,7 @@ module ActiveRecord
|
|
96
100
|
end
|
97
101
|
end
|
98
102
|
|
99
|
-
def add_attributes_for_collection_association(reflection, attrs)
|
103
|
+
def add_attributes_for_collection_association(reflection, attrs, arel_table=nil)
|
100
104
|
key = :"add_attributes_for_collection_association#{reflection.name}"
|
101
105
|
@_already_called ||= {}
|
102
106
|
return if @_already_called[key]
|
@@ -108,22 +112,22 @@ module ActiveRecord
|
|
108
112
|
|
109
113
|
if association = association_instance_get(reflection.name)
|
110
114
|
autosave = reflection.options[:autosave]
|
111
|
-
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
|
112
115
|
|
113
|
-
|
114
|
-
|
116
|
+
attrs[Arel::Attributes::EmptyRelation.new(arel_table, reflection.name, true, true)] = [] if association.target.empty?
|
117
|
+
|
118
|
+
association.target.each_with_index do |record, idx|
|
119
|
+
next if record.destroyed?
|
115
120
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
end
|
121
|
+
if record.new_record?
|
122
|
+
record.send(:arel_attributes_with_values_for_create, record.attribute_names).each do |k, v|
|
123
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name, idx, true)] = v
|
124
|
+
end
|
125
|
+
else
|
126
|
+
record.send(:arel_attributes_with_values_for_update, record.attribute_names).each do |k, v|
|
127
|
+
attrs[Arel::Attributes::Relation.new(k, reflection.name, idx, true)] = v
|
124
128
|
end
|
125
|
-
|
126
129
|
end
|
130
|
+
|
127
131
|
end
|
128
132
|
|
129
133
|
# reconstruct the scope now that we know the owner's id
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Callbacks
|
3
|
+
private
|
4
|
+
|
5
|
+
def create_or_update(*) #:nodoc:
|
6
|
+
if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
7
|
+
@_already_called ||= {}
|
8
|
+
self.class.reflect_on_all_associations.each do |r|
|
9
|
+
@_already_called[:"autosave_associated_records_for_#{r.name}"] = true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
_run_save_callbacks { super }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -1,3 +1,41 @@
|
|
1
|
+
module Arel
|
2
|
+
module Visitors
|
3
|
+
class ToSql < Arel::Visitors::Reduce
|
4
|
+
|
5
|
+
def visit_Arel_Attributes_Relation o, collector
|
6
|
+
visit(o.relation, collector)
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ActiveRecord
|
14
|
+
class PredicateBuilder # :nodoc:
|
15
|
+
|
16
|
+
def expand_from_hash(attributes)
|
17
|
+
return ["1=0"] if attributes.empty?
|
18
|
+
|
19
|
+
attributes.flat_map do |key, value|
|
20
|
+
if value.is_a?(Hash)
|
21
|
+
ka = associated_predicate_builder(key).expand_from_hash(value)
|
22
|
+
if self.table.instance_variable_get(:@klass).connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
23
|
+
ka.each { |k|
|
24
|
+
if k.left.is_a?(Arel::Attributes::Attribute) || k.left.is_a?(Arel::Attributes::Relation)
|
25
|
+
k.left = Arel::Attributes::Relation.new(k.left, key)
|
26
|
+
end
|
27
|
+
}
|
28
|
+
end
|
29
|
+
ka
|
30
|
+
else
|
31
|
+
expand(key, value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
1
39
|
module ActiveRecord
|
2
40
|
module FinderMethods
|
3
41
|
|
@@ -20,7 +58,11 @@ module ActiveRecord
|
|
20
58
|
[]
|
21
59
|
else
|
22
60
|
arel = relation.arel
|
23
|
-
rows = connection.
|
61
|
+
rows = if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
62
|
+
connection.select_all(arel, 'SQL', arel.bind_values + relation.bound_attributes)
|
63
|
+
else
|
64
|
+
connection.select_all(arel, 'SQL', relation.bound_attributes)
|
65
|
+
end
|
24
66
|
if join_dependency
|
25
67
|
join_dependency.instantiate(rows, aliases)
|
26
68
|
else
|
@@ -37,7 +79,7 @@ module ActiveRecord
|
|
37
79
|
}
|
38
80
|
}
|
39
81
|
|
40
|
-
model_cache = Hash.new { |h,
|
82
|
+
model_cache = Hash.new { |h,kklass| h[kklass] = {} }
|
41
83
|
parents = model_cache[self.base_class]
|
42
84
|
|
43
85
|
result_set.each { |row_hash|
|
@@ -4,10 +4,36 @@ module ActiveRecord
|
|
4
4
|
private
|
5
5
|
|
6
6
|
def create_or_update(*args)
|
7
|
+
@updating = new_record? ? :creating : :updating
|
8
|
+
$updating_model = self
|
9
|
+
|
7
10
|
raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
|
8
11
|
result = new_record? ? _create_record : _update_record(*args)
|
12
|
+
|
13
|
+
if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && result != 0
|
14
|
+
row_hash = result.rows.first
|
15
|
+
|
16
|
+
seen = Hash.new { |h, parent_klass|
|
17
|
+
h[parent_klass] = Hash.new { |i, parent_id|
|
18
|
+
i[parent_id] = Hash.new { |j, child_klass| j[child_klass] = {} }
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
model_cache = Hash.new { |h,klass| h[klass] = {} }
|
23
|
+
parents = model_cache[self.class.base_class]
|
24
|
+
|
25
|
+
self.assign_attributes(row_hash.select{|k,v| self.class.column_names.include?(k.to_s) })
|
26
|
+
row_hash.select{|k,v| !self.class.column_names.include?(k.to_s) }.each do |relation_name, value|
|
27
|
+
assc = association(relation_name.to_sym)
|
28
|
+
assc.reset if assc.reflection.collection?
|
29
|
+
end
|
30
|
+
|
31
|
+
construct(self, row_hash.select{|k,v| !self.class.column_names.include?(k.to_s) }, seen, model_cache)
|
32
|
+
end
|
33
|
+
|
9
34
|
result != false
|
10
|
-
|
35
|
+
# TODO: perhaps this can go further down the stack?
|
36
|
+
rescue Sunstone::Exception::BadRequest, Sunstone::Exception::Forbidden => e
|
11
37
|
JSON.parse(e.message)['errors'].each do |field, message|
|
12
38
|
if message.is_a?(Array)
|
13
39
|
message.each { |m| errors.add(field, m) }
|
@@ -16,6 +42,106 @@ module ActiveRecord
|
|
16
42
|
end
|
17
43
|
end
|
18
44
|
raise ActiveRecord::RecordInvalid
|
45
|
+
ensure
|
46
|
+
@updating = false
|
47
|
+
$updating_model = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# Creates a record with values matching those of the instance attributes
|
51
|
+
# and returns its id.
|
52
|
+
def _create_record(attribute_names = self.attribute_names)
|
53
|
+
attributes_values = arel_attributes_with_values_for_create(attribute_names)
|
54
|
+
|
55
|
+
new_id = self.class.unscoped.insert attributes_values
|
56
|
+
|
57
|
+
@new_record = false
|
58
|
+
|
59
|
+
if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
60
|
+
new_id
|
61
|
+
else
|
62
|
+
self.id ||= new_id if self.class.primary_key
|
63
|
+
id
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
#!!!! TODO: I am duplicated from finder_methods.....
|
68
|
+
def construct(parent, relations, seen, model_cache)
|
69
|
+
relations.each do |key, attributes|
|
70
|
+
reflection = parent.class.reflect_on_association(key)
|
71
|
+
next unless reflection
|
72
|
+
|
73
|
+
if reflection.collection?
|
74
|
+
other = parent.association(reflection.name)
|
75
|
+
other.loaded!
|
76
|
+
else
|
77
|
+
if parent.association_cached?(reflection.name)
|
78
|
+
model = parent.association(reflection.name).target
|
79
|
+
construct(model, attributes.select{|k,v| !reflection.klass.column_names.include?(k.to_s) }, seen, model_cache)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
if !reflection.collection?
|
84
|
+
construct_association(parent, reflection, attributes, seen, model_cache)
|
85
|
+
else
|
86
|
+
attributes.each do |row|
|
87
|
+
construct_association(parent, reflection, row, seen, model_cache)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
#!!!! TODO: I am duplicated from finder_methods.....
|
95
|
+
def construct_association(parent, reflection, attributes, seen, model_cache)
|
96
|
+
return if attributes.nil?
|
97
|
+
|
98
|
+
klass = if reflection.polymorphic?
|
99
|
+
parent.send(reflection.foreign_type).constantize.base_class
|
100
|
+
else
|
101
|
+
reflection.klass
|
102
|
+
end
|
103
|
+
id = attributes[klass.primary_key]
|
104
|
+
model = seen[parent.class.base_class][parent.id][klass][id]
|
105
|
+
|
106
|
+
if model
|
107
|
+
construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache)
|
108
|
+
|
109
|
+
other = parent.association(reflection.name)
|
110
|
+
|
111
|
+
if reflection.collection?
|
112
|
+
other.target.push(model)
|
113
|
+
else
|
114
|
+
other.target = model
|
115
|
+
end
|
116
|
+
|
117
|
+
other.set_inverse_instance(model)
|
118
|
+
else
|
119
|
+
model = construct_model(parent, reflection, id, attributes.select{|k,v| klass.column_names.include?(k.to_s) }, seen, model_cache)
|
120
|
+
seen[parent.class.base_class][parent.id][model.class.base_class][id] = model
|
121
|
+
construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
#!!!! TODO: I am duplicated from finder_methods.....
|
126
|
+
def construct_model(record, reflection, id, attributes, seen, model_cache)
|
127
|
+
klass = if reflection.polymorphic?
|
128
|
+
record.send(reflection.foreign_type).constantize
|
129
|
+
else
|
130
|
+
reflection.klass
|
131
|
+
end
|
132
|
+
|
133
|
+
model = model_cache[klass][id] ||= klass.instantiate(attributes)
|
134
|
+
other = record.association(reflection.name)
|
135
|
+
|
136
|
+
if reflection.collection?
|
137
|
+
other.target.push(model)
|
138
|
+
else
|
139
|
+
other.target = model
|
140
|
+
end
|
141
|
+
|
142
|
+
other.set_inverse_instance(model)
|
143
|
+
model
|
19
144
|
end
|
145
|
+
|
20
146
|
end
|
21
147
|
end
|