sunstone 5.0.0.beta3 → 5.0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Travis CI](https://travis-ci.org/malomalo/sunstone.svg)](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
|