viking-sequel 3.10.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.
- data/CHANGELOG +3134 -0
- data/COPYING +19 -0
- data/README.rdoc +723 -0
- data/Rakefile +193 -0
- data/bin/sequel +196 -0
- data/doc/advanced_associations.rdoc +644 -0
- data/doc/cheat_sheet.rdoc +218 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/dataset_filtering.rdoc +158 -0
- data/doc/opening_databases.rdoc +296 -0
- data/doc/prepared_statements.rdoc +104 -0
- data/doc/reflection.rdoc +84 -0
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.12.0.txt +534 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/doc/release_notes/3.1.0.txt +406 -0
- data/doc/release_notes/3.10.0.txt +286 -0
- data/doc/release_notes/3.2.0.txt +268 -0
- data/doc/release_notes/3.3.0.txt +192 -0
- data/doc/release_notes/3.4.0.txt +325 -0
- data/doc/release_notes/3.5.0.txt +510 -0
- data/doc/release_notes/3.6.0.txt +366 -0
- data/doc/release_notes/3.7.0.txt +179 -0
- data/doc/release_notes/3.8.0.txt +151 -0
- data/doc/release_notes/3.9.0.txt +233 -0
- data/doc/schema.rdoc +36 -0
- data/doc/sharding.rdoc +113 -0
- data/doc/virtual_rows.rdoc +205 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel/adapters/ado.rb +90 -0
- data/lib/sequel/adapters/ado/mssql.rb +30 -0
- data/lib/sequel/adapters/amalgalite.rb +176 -0
- data/lib/sequel/adapters/db2.rb +139 -0
- data/lib/sequel/adapters/dbi.rb +113 -0
- data/lib/sequel/adapters/do.rb +188 -0
- data/lib/sequel/adapters/do/mysql.rb +49 -0
- data/lib/sequel/adapters/do/postgres.rb +91 -0
- data/lib/sequel/adapters/do/sqlite.rb +40 -0
- data/lib/sequel/adapters/firebird.rb +283 -0
- data/lib/sequel/adapters/informix.rb +77 -0
- data/lib/sequel/adapters/jdbc.rb +587 -0
- data/lib/sequel/adapters/jdbc/as400.rb +58 -0
- data/lib/sequel/adapters/jdbc/h2.rb +133 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
- data/lib/sequel/adapters/mysql.rb +421 -0
- data/lib/sequel/adapters/odbc.rb +143 -0
- data/lib/sequel/adapters/odbc/mssql.rb +42 -0
- data/lib/sequel/adapters/openbase.rb +64 -0
- data/lib/sequel/adapters/oracle.rb +131 -0
- data/lib/sequel/adapters/postgres.rb +504 -0
- data/lib/sequel/adapters/shared/mssql.rb +490 -0
- data/lib/sequel/adapters/shared/mysql.rb +498 -0
- data/lib/sequel/adapters/shared/oracle.rb +195 -0
- data/lib/sequel/adapters/shared/postgres.rb +830 -0
- data/lib/sequel/adapters/shared/progress.rb +44 -0
- data/lib/sequel/adapters/shared/sqlite.rb +389 -0
- data/lib/sequel/adapters/sqlite.rb +224 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
- data/lib/sequel/connection_pool.rb +99 -0
- data/lib/sequel/connection_pool/sharded_single.rb +84 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
- data/lib/sequel/connection_pool/single.rb +29 -0
- data/lib/sequel/connection_pool/threaded.rb +150 -0
- data/lib/sequel/core.rb +293 -0
- data/lib/sequel/core_sql.rb +241 -0
- data/lib/sequel/database.rb +1079 -0
- data/lib/sequel/database/schema_generator.rb +327 -0
- data/lib/sequel/database/schema_methods.rb +203 -0
- data/lib/sequel/database/schema_sql.rb +320 -0
- data/lib/sequel/dataset.rb +32 -0
- data/lib/sequel/dataset/actions.rb +441 -0
- data/lib/sequel/dataset/features.rb +86 -0
- data/lib/sequel/dataset/graph.rb +254 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +227 -0
- data/lib/sequel/dataset/query.rb +709 -0
- data/lib/sequel/dataset/sql.rb +996 -0
- data/lib/sequel/exceptions.rb +51 -0
- data/lib/sequel/extensions/blank.rb +43 -0
- data/lib/sequel/extensions/inflector.rb +242 -0
- data/lib/sequel/extensions/looser_typecasting.rb +21 -0
- data/lib/sequel/extensions/migration.rb +239 -0
- data/lib/sequel/extensions/named_timezones.rb +61 -0
- data/lib/sequel/extensions/pagination.rb +100 -0
- data/lib/sequel/extensions/pretty_table.rb +82 -0
- data/lib/sequel/extensions/query.rb +52 -0
- data/lib/sequel/extensions/schema_dumper.rb +271 -0
- data/lib/sequel/extensions/sql_expr.rb +122 -0
- data/lib/sequel/extensions/string_date_time.rb +46 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
- data/lib/sequel/metaprogramming.rb +9 -0
- data/lib/sequel/model.rb +120 -0
- data/lib/sequel/model/associations.rb +1514 -0
- data/lib/sequel/model/base.rb +1069 -0
- data/lib/sequel/model/default_inflections.rb +45 -0
- data/lib/sequel/model/errors.rb +39 -0
- data/lib/sequel/model/exceptions.rb +21 -0
- data/lib/sequel/model/inflections.rb +162 -0
- data/lib/sequel/model/plugins.rb +70 -0
- data/lib/sequel/plugins/active_model.rb +59 -0
- data/lib/sequel/plugins/association_dependencies.rb +103 -0
- data/lib/sequel/plugins/association_proxies.rb +41 -0
- data/lib/sequel/plugins/boolean_readers.rb +53 -0
- data/lib/sequel/plugins/caching.rb +141 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
- data/lib/sequel/plugins/composition.rb +138 -0
- data/lib/sequel/plugins/force_encoding.rb +72 -0
- data/lib/sequel/plugins/hook_class_methods.rb +126 -0
- data/lib/sequel/plugins/identity_map.rb +116 -0
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/instance_hooks.rb +57 -0
- data/lib/sequel/plugins/lazy_attributes.rb +77 -0
- data/lib/sequel/plugins/many_through_many.rb +208 -0
- data/lib/sequel/plugins/nested_attributes.rb +206 -0
- data/lib/sequel/plugins/optimistic_locking.rb +81 -0
- data/lib/sequel/plugins/rcte_tree.rb +281 -0
- data/lib/sequel/plugins/schema.rb +66 -0
- data/lib/sequel/plugins/serialization.rb +166 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
- data/lib/sequel/plugins/subclasses.rb +45 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
- data/lib/sequel/plugins/timestamps.rb +87 -0
- data/lib/sequel/plugins/touch.rb +118 -0
- data/lib/sequel/plugins/typecast_on_load.rb +72 -0
- data/lib/sequel/plugins/validation_class_methods.rb +405 -0
- data/lib/sequel/plugins/validation_helpers.rb +223 -0
- data/lib/sequel/sql.rb +1020 -0
- data/lib/sequel/timezones.rb +161 -0
- data/lib/sequel/version.rb +12 -0
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/firebird_spec.rb +407 -0
- data/spec/adapters/informix_spec.rb +97 -0
- data/spec/adapters/mssql_spec.rb +403 -0
- data/spec/adapters/mysql_spec.rb +1019 -0
- data/spec/adapters/oracle_spec.rb +286 -0
- data/spec/adapters/postgres_spec.rb +969 -0
- data/spec/adapters/spec_helper.rb +51 -0
- data/spec/adapters/sqlite_spec.rb +432 -0
- data/spec/core/connection_pool_spec.rb +808 -0
- data/spec/core/core_sql_spec.rb +417 -0
- data/spec/core/database_spec.rb +1662 -0
- data/spec/core/dataset_spec.rb +3827 -0
- data/spec/core/expression_filters_spec.rb +595 -0
- data/spec/core/object_graph_spec.rb +296 -0
- data/spec/core/schema_generator_spec.rb +159 -0
- data/spec/core/schema_spec.rb +830 -0
- data/spec/core/spec_helper.rb +56 -0
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/active_model_spec.rb +76 -0
- data/spec/extensions/association_dependencies_spec.rb +127 -0
- data/spec/extensions/association_proxies_spec.rb +50 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/boolean_readers_spec.rb +92 -0
- data/spec/extensions/caching_spec.rb +250 -0
- data/spec/extensions/class_table_inheritance_spec.rb +252 -0
- data/spec/extensions/composition_spec.rb +194 -0
- data/spec/extensions/force_encoding_spec.rb +117 -0
- data/spec/extensions/hook_class_methods_spec.rb +470 -0
- data/spec/extensions/identity_map_spec.rb +202 -0
- data/spec/extensions/inflector_spec.rb +181 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/instance_hooks_spec.rb +133 -0
- data/spec/extensions/lazy_attributes_spec.rb +153 -0
- data/spec/extensions/looser_typecasting_spec.rb +39 -0
- data/spec/extensions/many_through_many_spec.rb +884 -0
- data/spec/extensions/migration_spec.rb +332 -0
- data/spec/extensions/named_timezones_spec.rb +72 -0
- data/spec/extensions/nested_attributes_spec.rb +396 -0
- data/spec/extensions/optimistic_locking_spec.rb +100 -0
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/extensions/rcte_tree_spec.rb +205 -0
- data/spec/extensions/schema_dumper_spec.rb +357 -0
- data/spec/extensions/schema_spec.rb +127 -0
- data/spec/extensions/serialization_spec.rb +209 -0
- data/spec/extensions/single_table_inheritance_spec.rb +96 -0
- data/spec/extensions/spec_helper.rb +91 -0
- data/spec/extensions/sql_expr_spec.rb +89 -0
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/extensions/subclasses_spec.rb +52 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
- data/spec/extensions/thread_local_timezones_spec.rb +45 -0
- data/spec/extensions/timestamps_spec.rb +150 -0
- data/spec/extensions/touch_spec.rb +155 -0
- data/spec/extensions/typecast_on_load_spec.rb +69 -0
- data/spec/extensions/validation_class_methods_spec.rb +984 -0
- data/spec/extensions/validation_helpers_spec.rb +438 -0
- data/spec/integration/associations_test.rb +281 -0
- data/spec/integration/database_test.rb +26 -0
- data/spec/integration/dataset_test.rb +963 -0
- data/spec/integration/eager_loader_test.rb +734 -0
- data/spec/integration/model_test.rb +130 -0
- data/spec/integration/plugin_test.rb +814 -0
- data/spec/integration/prepared_statement_test.rb +213 -0
- data/spec/integration/schema_test.rb +361 -0
- data/spec/integration/spec_helper.rb +73 -0
- data/spec/integration/timezone_test.rb +55 -0
- data/spec/integration/transaction_test.rb +122 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/model/association_reflection_spec.rb +175 -0
- data/spec/model/associations_spec.rb +2633 -0
- data/spec/model/base_spec.rb +418 -0
- data/spec/model/dataset_methods_spec.rb +78 -0
- data/spec/model/eager_loading_spec.rb +1391 -0
- data/spec/model/hooks_spec.rb +240 -0
- data/spec/model/inflector_spec.rb +26 -0
- data/spec/model/model_spec.rb +593 -0
- data/spec/model/plugins_spec.rb +236 -0
- data/spec/model/record_spec.rb +1500 -0
- data/spec/model/spec_helper.rb +97 -0
- data/spec/model/validations_spec.rb +153 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +346 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Plugins::LazyAttributes" do
|
4
|
+
before do
|
5
|
+
class ::LazyAttributesModel < Sequel::Model(:la)
|
6
|
+
plugin :lazy_attributes
|
7
|
+
set_columns([:id, :name])
|
8
|
+
meta_def(:columns){[:id, :name]}
|
9
|
+
lazy_attributes :name
|
10
|
+
meta_def(:columns){[:id]}
|
11
|
+
ds = dataset
|
12
|
+
def ds.fetch_rows(sql)
|
13
|
+
execute(sql)
|
14
|
+
select = @opts[:select]
|
15
|
+
where = @opts[:where]
|
16
|
+
block = @mod_block || proc{|s| s}
|
17
|
+
if !where
|
18
|
+
if select.include?(:name)
|
19
|
+
yield(block[:id=>1, :name=>'1'])
|
20
|
+
yield(block[:id=>2, :name=>'2'])
|
21
|
+
else
|
22
|
+
yield(:id=>1)
|
23
|
+
yield(:id=>2)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
i = where.args.last
|
27
|
+
i = i.instance_variable_get(:@array) if i.is_a?(Sequel::SQL::SQLArray)
|
28
|
+
Array(i).each do |x|
|
29
|
+
if sql =~ /SELECT name FROM/
|
30
|
+
yield(block[:name=>x.to_s])
|
31
|
+
else
|
32
|
+
yield(block[:id=>x, :name=>x.to_s])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
@c = ::LazyAttributesModel
|
39
|
+
@ds = LazyAttributesModel.dataset
|
40
|
+
MODEL_DB.reset
|
41
|
+
end
|
42
|
+
after do
|
43
|
+
Object.send(:remove_const, :LazyAttributesModel)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should allowing adding additional lazy attributes via plugin :lazy_attributes" do
|
47
|
+
@c.set_dataset(@ds.select(:id, :blah))
|
48
|
+
@c.dataset.sql.should == 'SELECT id, blah FROM la'
|
49
|
+
@c.plugin :lazy_attributes, :blah
|
50
|
+
@c.dataset.opts[:select].should == [:id]
|
51
|
+
@c.dataset.sql.should == 'SELECT id FROM la'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should allowing adding additional lazy attributes via lazy_attributes" do
|
55
|
+
@c.set_dataset(@ds.select(:id, :blah))
|
56
|
+
@c.dataset.sql.should == 'SELECT id, blah FROM la'
|
57
|
+
@c.lazy_attributes :blah
|
58
|
+
@c.dataset.opts[:select].should == [:id]
|
59
|
+
@c.dataset.sql.should == 'SELECT id FROM la'
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should remove the attributes given from the SELECT columns of the model's dataset" do
|
63
|
+
@ds.opts[:select].should == [:id]
|
64
|
+
@ds.sql.should == 'SELECT id FROM la'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should lazily load the attribute for a single model object if there is an active identity map" do
|
68
|
+
@c.with_identity_map do
|
69
|
+
m = @c.first
|
70
|
+
m.values.should == {:id=>1}
|
71
|
+
m.name.should == '1'
|
72
|
+
m.values.should == {:id=>1, :name=>'1'}
|
73
|
+
MODEL_DB.sqls.should == ['SELECT id FROM la LIMIT 1', 'SELECT name FROM la WHERE (id = 1) LIMIT 1']
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should lazily load the attribute for a single model object if there is no active identity map" do
|
78
|
+
m = @c.first
|
79
|
+
m.values.should == {:id=>1}
|
80
|
+
m.name.should == '1'
|
81
|
+
m.values.should == {:id=>1, :name=>'1'}
|
82
|
+
MODEL_DB.sqls.should == ['SELECT id FROM la LIMIT 1', 'SELECT name FROM la WHERE (id = 1) LIMIT 1']
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not lazily load the attribute for a single model object if the value already exists" do
|
86
|
+
@c.with_identity_map do
|
87
|
+
m = @c.first
|
88
|
+
m.values.should == {:id=>1}
|
89
|
+
m[:name] = '1'
|
90
|
+
m.name.should == '1'
|
91
|
+
m.values.should == {:id=>1, :name=>'1'}
|
92
|
+
MODEL_DB.sqls.should == ['SELECT id FROM la LIMIT 1']
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should not lazily load the attribute for a single model object if it is a new record" do
|
97
|
+
@c.with_identity_map do
|
98
|
+
m = @c.new
|
99
|
+
m.values.should == {}
|
100
|
+
m.name.should == nil
|
101
|
+
MODEL_DB.sqls.should == []
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should eagerly load the attribute for all model objects reteived with it" do
|
106
|
+
@c.with_identity_map do
|
107
|
+
ms = @c.all
|
108
|
+
ms.map{|m| m.values}.should == [{:id=>1}, {:id=>2}]
|
109
|
+
ms.map{|m| m.name}.should == %w'1 2'
|
110
|
+
ms.map{|m| m.values}.should == [{:id=>1, :name=>'1'}, {:id=>2, :name=>'2'}]
|
111
|
+
MODEL_DB.sqls.should == ['SELECT id FROM la', 'SELECT id, name FROM la WHERE (id IN (1, 2))']
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should add the accessors to a module included in the class, so they can be easily overridden" do
|
116
|
+
@c.class_eval do
|
117
|
+
def name
|
118
|
+
"#{super}-blah"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
@c.with_identity_map do
|
122
|
+
ms = @c.all
|
123
|
+
ms.map{|m| m.values}.should == [{:id=>1}, {:id=>2}]
|
124
|
+
ms.map{|m| m.name}.should == %w'1-blah 2-blah'
|
125
|
+
ms.map{|m| m.values}.should == [{:id=>1, :name=>'1'}, {:id=>2, :name=>'2'}]
|
126
|
+
MODEL_DB.sqls.should == ['SELECT id FROM la', 'SELECT id, name FROM la WHERE (id IN (1, 2))']
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should work with the serialization plugin" do
|
131
|
+
@c.plugin :serialization, :yaml, :name
|
132
|
+
@ds.instance_variable_set(:@mod_block, proc{|s| s.merge(:name=>"--- #{s[:name].to_i*3}\n")})
|
133
|
+
@c.with_identity_map do
|
134
|
+
ms = @ds.all
|
135
|
+
ms.map{|m| m.values}.should == [{:id=>1}, {:id=>2}]
|
136
|
+
ms.map{|m| m.name}.should == [3,6]
|
137
|
+
ms.map{|m| m.values}.should == [{:id=>1, :name=>"--- 3\n"}, {:id=>2, :name=>"--- 6\n"}]
|
138
|
+
ms.map{|m| m.deserialized_values}.should == [{:name=>3}, {:name=>6}]
|
139
|
+
ms.map{|m| m.name}.should == [3,6]
|
140
|
+
MODEL_DB.sqls.should == ['SELECT id FROM la', 'SELECT id, name FROM la WHERE (id IN (1, 2))']
|
141
|
+
end
|
142
|
+
MODEL_DB.reset
|
143
|
+
@c.with_identity_map do
|
144
|
+
m = @ds.first
|
145
|
+
m.values.should == {:id=>1}
|
146
|
+
m.name.should == 3
|
147
|
+
m.values.should == {:id=>1, :name=>"--- 3\n"}
|
148
|
+
m.deserialized_values.should == {:name=>3}
|
149
|
+
m.name.should == 3
|
150
|
+
MODEL_DB.sqls.should == ["SELECT id FROM la LIMIT 1", "SELECT name FROM la WHERE (id = 1) LIMIT 1"]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
context "LooserTypecasting Extension" do
|
4
|
+
before do
|
5
|
+
@db = Sequel::Database.new({})
|
6
|
+
def @db.schema(*args)
|
7
|
+
[[:id, {}], [:y, {:type=>:float}], [:b, {:type=>:integer}]]
|
8
|
+
end
|
9
|
+
@c = Class.new(Sequel::Model(@db[:items]))
|
10
|
+
@c.instance_eval do
|
11
|
+
@columns = [:id, :b, :y]
|
12
|
+
def columns; @columns; end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "Should use to_i instead of Integer() for typecasting integers" do
|
17
|
+
proc{@c.new(:b=>'a')}.should raise_error(Sequel::InvalidValue)
|
18
|
+
@db.extend(Sequel::LooserTypecasting)
|
19
|
+
@c.new(:b=>'a').b.should == 0
|
20
|
+
|
21
|
+
o = Object.new
|
22
|
+
def o.to_i
|
23
|
+
1
|
24
|
+
end
|
25
|
+
@c.new(:b=>o).b.should == 1
|
26
|
+
end
|
27
|
+
|
28
|
+
specify "Should use to_f instead of Float() for typecasting floats" do
|
29
|
+
proc{@c.new(:y=>'a')}.should raise_error(Sequel::InvalidValue)
|
30
|
+
@db.extend(Sequel::LooserTypecasting)
|
31
|
+
@c.new(:y=>'a').y.should == 0.0
|
32
|
+
|
33
|
+
o = Object.new
|
34
|
+
def o.to_f
|
35
|
+
1.0
|
36
|
+
end
|
37
|
+
@c.new(:y=>o).y.should == 1.0
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,884 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Sequel::Model, "many_through_many" do
|
4
|
+
before do
|
5
|
+
class ::Artist < Sequel::Model
|
6
|
+
attr_accessor :yyy
|
7
|
+
columns :id
|
8
|
+
plugin :many_through_many
|
9
|
+
end
|
10
|
+
class ::Tag < Sequel::Model
|
11
|
+
end
|
12
|
+
MODEL_DB.reset
|
13
|
+
@c1 = Artist
|
14
|
+
@c2 = Tag
|
15
|
+
@dataset = @c2.dataset
|
16
|
+
def @dataset.fetch_rows(sql)
|
17
|
+
@db << sql
|
18
|
+
yield({:id=>1})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
after do
|
22
|
+
Object.send(:remove_const, :Artist)
|
23
|
+
Object.send(:remove_const, :Tag)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should default to associating to other models in the same scope" do
|
27
|
+
class ::AssociationModuleTest
|
28
|
+
class Artist < Sequel::Model
|
29
|
+
plugin :many_through_many
|
30
|
+
many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
|
31
|
+
end
|
32
|
+
class Tag < Sequel::Model
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
::AssociationModuleTest::Artist.association_reflection(:tags).associated_class.should == ::AssociationModuleTest::Tag
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should raise an error if in invalid form of through is used" do
|
40
|
+
proc{@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id]]}.should raise_error(Sequel::Error)
|
41
|
+
proc{@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], {:table=>:album_tags, :left=>:album_id}]}.should raise_error(Sequel::Error)
|
42
|
+
proc{@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], :album_tags]}.should raise_error(Sequel::Error)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should use join tables given" do
|
46
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
|
47
|
+
n = @c1.load(:id => 1234)
|
48
|
+
a = n.tags_dataset
|
49
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
50
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234))'
|
51
|
+
n.tags.should == [@c2.load(:id=>1)]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should handle multiple aliasing of tables" do
|
55
|
+
class ::Album < Sequel::Model
|
56
|
+
end
|
57
|
+
@c1.many_through_many :albums, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_artists, :album_id, :artist_id], [:artists, :id, :id], [:albums_artists, :artist_id, :album_id]]
|
58
|
+
n = @c1.load(:id => 1234)
|
59
|
+
a = n.albums_dataset
|
60
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
61
|
+
a.sql.should == 'SELECT albums.* FROM albums INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) INNER JOIN artists ON (artists.id = albums_artists.artist_id) INNER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.artist_id = artists.id) INNER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_0.album_id) INNER JOIN albums_artists AS albums_artists_1 ON ((albums_artists_1.album_id = albums_0.id) AND (albums_artists_1.artist_id = 1234))'
|
62
|
+
n.albums.should == [Album.load(:id=>1, :x=>1)]
|
63
|
+
Object.send(:remove_const, :Album)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should use explicit class if given" do
|
67
|
+
@c1.many_through_many :albums_tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :class=>Tag
|
68
|
+
n = @c1.load(:id => 1234)
|
69
|
+
a = n.albums_tags_dataset
|
70
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
71
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234))'
|
72
|
+
n.albums_tags.should == [@c2.load(:id=>1)]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should accept :left_primary_key and :right_primary_key option for primary keys to use in current and associated table" do
|
76
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :right_primary_key=>:tag_id, :left_primary_key=>:yyy
|
77
|
+
n = @c1.load(:id => 1234)
|
78
|
+
n.yyy = 85
|
79
|
+
a = n.tags_dataset
|
80
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
81
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.tag_id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 85))'
|
82
|
+
n.tags.should == [@c2.load(:id=>1)]
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should handle composite keys" do
|
86
|
+
@c1.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
|
87
|
+
n = @c1.load(:id => 1234)
|
88
|
+
n.yyy = 85
|
89
|
+
a = n.tags_dataset
|
90
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
91
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON ((albums_tags.g1 = tags.h1) AND (albums_tags.g2 = tags.h2)) INNER JOIN albums ON ((albums.e1 = albums_tags.f1) AND (albums.e2 = albums_tags.f2)) INNER JOIN albums_artists ON ((albums_artists.c1 = albums.d1) AND (albums_artists.c2 = albums.d2) AND (albums_artists.b1 = 1234) AND (albums_artists.b2 = 85))'
|
92
|
+
n.tags.should == [@c2.load(:id=>1)]
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should support a :conditions option" do
|
96
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :conditions=>{:a=>32}
|
97
|
+
n = @c1.load(:id => 1234)
|
98
|
+
a = n.tags_dataset
|
99
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
100
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234)) WHERE (a = 32)'
|
101
|
+
n.tags.should == [@c2.load(:id=>1)]
|
102
|
+
|
103
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :conditions=>['a = ?', 42]
|
104
|
+
n = @c1.load(:id => 1234)
|
105
|
+
a = n.tags_dataset
|
106
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
107
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234)) WHERE (a = 42)'
|
108
|
+
n.tags.should == [@c2.load(:id=>1)]
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should support an :order option" do
|
112
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :order=>:blah
|
113
|
+
n = @c1.load(:id => 1234)
|
114
|
+
a = n.tags_dataset
|
115
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
116
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234)) ORDER BY blah'
|
117
|
+
n.tags.should == [@c2.load(:id=>1)]
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should support an array for the :order option" do
|
121
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :order=>[:blah1, :blah2]
|
122
|
+
n = @c1.load(:id => 1234)
|
123
|
+
a = n.tags_dataset
|
124
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
125
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234)) ORDER BY blah1, blah2'
|
126
|
+
n.tags.should == [@c2.load(:id=>1)]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should support a select option" do
|
130
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>:blah
|
131
|
+
n = @c1.load(:id => 1234)
|
132
|
+
a = n.tags_dataset
|
133
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
134
|
+
a.sql.should == 'SELECT blah FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234))'
|
135
|
+
n.tags.should == [@c2.load(:id=>1)]
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should support an array for the select option" do
|
139
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>[:tags.*, :albums__name]
|
140
|
+
n = @c1.load(:id => 1234)
|
141
|
+
a = n.tags_dataset
|
142
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
143
|
+
a.sql.should == 'SELECT tags.*, albums.name FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234))'
|
144
|
+
n.tags.should == [@c2.load(:id=>1)]
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should accept a block" do
|
148
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]] do |ds| ds.filter(:yyy=>@yyy) end
|
149
|
+
n = @c1.load(:id => 1234)
|
150
|
+
n.yyy = 85
|
151
|
+
a = n.tags_dataset
|
152
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
153
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234)) WHERE (yyy = 85)'
|
154
|
+
n.tags.should == [@c2.load(:id=>1)]
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should allow the :order option while accepting a block" do
|
158
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :order=>:blah do |ds| ds.filter(:yyy=>@yyy) end
|
159
|
+
n = @c1.load(:id => 1234)
|
160
|
+
n.yyy = 85
|
161
|
+
a = n.tags_dataset
|
162
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
163
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234)) WHERE (yyy = 85) ORDER BY blah'
|
164
|
+
n.tags.should == [@c2.load(:id=>1)]
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should support a :dataset option that is used instead of the default" do
|
168
|
+
@c1.many_through_many :tags, [[:a, :b, :c]], :dataset=>proc{Tag.join(:albums_tags, [:tag_id]).join(:albums, [:album_id]).join(:albums_artists, [:album_id]).filter(:albums_artists__artist_id=>id)}
|
169
|
+
n = @c1.load(:id => 1234)
|
170
|
+
a = n.tags_dataset
|
171
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
172
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags USING (tag_id) INNER JOIN albums USING (album_id) INNER JOIN albums_artists USING (album_id) WHERE (albums_artists.artist_id = 1234)'
|
173
|
+
n.tags.should == [@c2.load(:id=>1)]
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should support a :limit option" do
|
177
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :limit=>10
|
178
|
+
n = @c1.load(:id => 1234)
|
179
|
+
a = n.tags_dataset
|
180
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
181
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234)) LIMIT 10'
|
182
|
+
n.tags.should == [@c2.load(:id=>1)]
|
183
|
+
|
184
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :limit=>[10, 10]
|
185
|
+
n = @c1.load(:id => 1234)
|
186
|
+
a = n.tags_dataset
|
187
|
+
a.should be_a_kind_of(Sequel::Dataset)
|
188
|
+
a.sql.should == 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234)) LIMIT 10 OFFSET 10'
|
189
|
+
n.tags.should == [@c2.load(:id=>1)]
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should have the :eager option affect the _dataset method" do
|
193
|
+
@c2.many_to_many :fans
|
194
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager=>:fans
|
195
|
+
@c1.load(:id => 1234).tags_dataset.opts[:eager].should == {:fans=>nil}
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should provide an array with all members of the association" do
|
199
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
|
200
|
+
@c1.load(:id => 1234).tags.should == [@c2.load(:id=>1)]
|
201
|
+
MODEL_DB.sqls.should == ['SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234))']
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should set cached instance variable when accessed" do
|
205
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
|
206
|
+
n = @c1.load(:id => 1234)
|
207
|
+
n.associations[:tags].should == nil
|
208
|
+
MODEL_DB.sqls.should == []
|
209
|
+
n.tags.should == [@c2.load(:id=>1)]
|
210
|
+
MODEL_DB.sqls.should == ['SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234))']
|
211
|
+
n.associations[:tags].should == n.tags
|
212
|
+
MODEL_DB.sqls.length.should == 1
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should use cached instance variable if available" do
|
216
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
|
217
|
+
n = @c1.load(:id => 1234)
|
218
|
+
n.associations[:tags] = []
|
219
|
+
n.tags.should == []
|
220
|
+
MODEL_DB.sqls.should == []
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should not use cached instance variable if asked to reload" do
|
224
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
|
225
|
+
n = @c1.load(:id => 1234)
|
226
|
+
n.associations[:tags] = []
|
227
|
+
MODEL_DB.sqls.should == []
|
228
|
+
n.tags(true).should == [@c2.load(:id=>1)]
|
229
|
+
MODEL_DB.sqls.should == ['SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1234))']
|
230
|
+
n.associations[:tags].should == n.tags
|
231
|
+
MODEL_DB.sqls.length.should == 1
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should not add associations methods directly to class" do
|
235
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
|
236
|
+
im = @c1.instance_methods.collect{|x| x.to_s}
|
237
|
+
im.should(include('tags'))
|
238
|
+
im.should(include('tags_dataset'))
|
239
|
+
im2 = @c1.instance_methods(false).collect{|x| x.to_s}
|
240
|
+
im2.should_not(include('tags'))
|
241
|
+
im2.should_not(include('tags_dataset'))
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should support after_load association callback" do
|
245
|
+
h = []
|
246
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :after_load=>:al
|
247
|
+
@c1.class_eval do
|
248
|
+
@@blah = h
|
249
|
+
def al(v)
|
250
|
+
v.each{|x| @@blah << x.pk * 20}
|
251
|
+
end
|
252
|
+
end
|
253
|
+
@c2.class_eval do
|
254
|
+
def @dataset.fetch_rows(sql)
|
255
|
+
yield({:id=>20})
|
256
|
+
yield({:id=>30})
|
257
|
+
end
|
258
|
+
end
|
259
|
+
p = @c1.load(:id=>10, :parent_id=>20)
|
260
|
+
p.tags
|
261
|
+
h.should == [400, 600]
|
262
|
+
p.tags.collect{|a| a.pk}.should == [20, 30]
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should support a :uniq option that removes duplicates from the association" do
|
266
|
+
h = []
|
267
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :uniq=>true
|
268
|
+
@c2.class_eval do
|
269
|
+
def @dataset.fetch_rows(sql)
|
270
|
+
yield({:id=>20})
|
271
|
+
yield({:id=>30})
|
272
|
+
yield({:id=>20})
|
273
|
+
yield({:id=>30})
|
274
|
+
end
|
275
|
+
end
|
276
|
+
@c1.load(:id=>10).tags.should == [@c2.load(:id=>20), @c2.load(:id=>30)]
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
describe 'Sequel::Plugins::ManyThroughMany::ManyThroughManyAssociationReflection' do
|
281
|
+
before do
|
282
|
+
class ::Artist < Sequel::Model
|
283
|
+
plugin :many_through_many
|
284
|
+
many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
|
285
|
+
end
|
286
|
+
class ::Tag < Sequel::Model
|
287
|
+
end
|
288
|
+
MODEL_DB.reset
|
289
|
+
@ar = Artist.association_reflection(:tags)
|
290
|
+
end
|
291
|
+
after do
|
292
|
+
Object.send(:remove_const, :Artist)
|
293
|
+
Object.send(:remove_const, :Tag)
|
294
|
+
end
|
295
|
+
|
296
|
+
it "#edges should be an array of joins to make when eager graphing" do
|
297
|
+
@ar.edges.should == [{:conditions=>[], :left=>:id, :right=>:artist_id, :table=>:albums_artists, :join_type=>:left_outer, :block=>nil}, {:conditions=>[], :left=>:album_id, :right=>:id, :table=>:albums, :join_type=>:left_outer, :block=>nil}, {:conditions=>[], :left=>:id, :right=>:album_id, :table=>:albums_tags, :join_type=>:left_outer, :block=>nil}]
|
298
|
+
end
|
299
|
+
|
300
|
+
it "#edges should handle composite keys" do
|
301
|
+
Artist.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
|
302
|
+
Artist.association_reflection(:tags).edges.should == [{:conditions=>[], :left=>[:id, :yyy], :right=>[:b1, :b2], :table=>:albums_artists, :join_type=>:left_outer, :block=>nil}, {:conditions=>[], :left=>[:c1, :c2], :right=>[:d1, :d2], :table=>:albums, :join_type=>:left_outer, :block=>nil}, {:conditions=>[], :left=>[:e1, :e2], :right=>[:f1, :f2], :table=>:albums_tags, :join_type=>:left_outer, :block=>nil}]
|
303
|
+
end
|
304
|
+
|
305
|
+
it "#reverse_edges should be an array of joins to make when lazy loading or eager loading" do
|
306
|
+
@ar.reverse_edges.should == [{:alias=>:albums_tags, :left=>:tag_id, :right=>:id, :table=>:albums_tags}, {:alias=>:albums, :left=>:id, :right=>:album_id, :table=>:albums}]
|
307
|
+
end
|
308
|
+
|
309
|
+
it "#reverse_edges should handle composite keys" do
|
310
|
+
Artist.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
|
311
|
+
Artist.association_reflection(:tags).reverse_edges.should == [{:alias=>:albums_tags, :left=>[:g1, :g2], :right=>[:h1, :h2], :table=>:albums_tags}, {:alias=>:albums, :left=>[:e1, :e2], :right=>[:f1, :f2], :table=>:albums}]
|
312
|
+
end
|
313
|
+
|
314
|
+
it "#reciprocal should be nil" do
|
315
|
+
@ar.reciprocal.should == nil
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
describe "Sequel::Plugins::ManyThroughMany eager loading methods" do
|
320
|
+
before do
|
321
|
+
class ::Artist < Sequel::Model
|
322
|
+
plugin :many_through_many
|
323
|
+
many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]]
|
324
|
+
many_through_many :other_tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :class=>:Tag
|
325
|
+
many_through_many :albums, [[:albums_artists, :artist_id, :album_id]]
|
326
|
+
many_through_many :artists, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_artists, :album_id, :artist_id]]
|
327
|
+
end
|
328
|
+
class ::Tag < Sequel::Model
|
329
|
+
plugin :many_through_many
|
330
|
+
many_through_many :tracks, [[:albums_tags, :tag_id, :album_id], [:albums, :id, :id]], :right_primary_key=>:album_id
|
331
|
+
end
|
332
|
+
class ::Album < Sequel::Model
|
333
|
+
end
|
334
|
+
class ::Track < Sequel::Model
|
335
|
+
end
|
336
|
+
|
337
|
+
Artist.dataset.extend(Module.new {
|
338
|
+
def columns
|
339
|
+
[:id]
|
340
|
+
end
|
341
|
+
|
342
|
+
def fetch_rows(sql)
|
343
|
+
@db << sql
|
344
|
+
h = {:id => 1}
|
345
|
+
if sql =~ /FROM artists LEFT OUTER JOIN albums_artists/
|
346
|
+
h[:tags_id] = 2
|
347
|
+
h[:albums_0_id] = 3 if sql =~ /LEFT OUTER JOIN albums AS albums_0/
|
348
|
+
h[:tracks_id] = 4 if sql =~ /LEFT OUTER JOIN tracks/
|
349
|
+
h[:other_tags_id] = 9 if sql =~ /other_tags\.id AS other_tags_id/
|
350
|
+
h[:artists_0_id] = 10 if sql =~ /artists_0\.id AS artists_0_id/
|
351
|
+
end
|
352
|
+
yield h
|
353
|
+
end
|
354
|
+
})
|
355
|
+
|
356
|
+
Tag.dataset.extend(Module.new {
|
357
|
+
def fetch_rows(sql)
|
358
|
+
@db << sql
|
359
|
+
h = {:id => 2}
|
360
|
+
if sql =~ /albums_artists.artist_id IN \(([18])\)/
|
361
|
+
h.merge!(:x_foreign_key_x=>$1.to_i)
|
362
|
+
elsif sql =~ /\(\(albums_artists.b1, albums_artists.b2\) IN \(\(1, 8\)\)\)/
|
363
|
+
h.merge!(:x_foreign_key_0_x=>1, :x_foreign_key_1_x=>8)
|
364
|
+
end
|
365
|
+
h[:tag_id] = h.delete(:id) if sql =~ /albums_artists.artist_id IN \(8\)/
|
366
|
+
yield h
|
367
|
+
end
|
368
|
+
})
|
369
|
+
|
370
|
+
Album.dataset.extend(Module.new {
|
371
|
+
def fetch_rows(sql)
|
372
|
+
@db << sql
|
373
|
+
h = {:id => 3}
|
374
|
+
h.merge!(:x_foreign_key_x=>1) if sql =~ /albums_artists.artist_id IN \(1\)/
|
375
|
+
yield h
|
376
|
+
end
|
377
|
+
})
|
378
|
+
|
379
|
+
Track.dataset.extend(Module.new {
|
380
|
+
def fetch_rows(sql)
|
381
|
+
@db << sql
|
382
|
+
h = {:id => 4}
|
383
|
+
h.merge!(:x_foreign_key_x=>2) if sql =~ /albums_tags.tag_id IN \(2\)/
|
384
|
+
yield h
|
385
|
+
end
|
386
|
+
})
|
387
|
+
|
388
|
+
@c1 = Artist
|
389
|
+
MODEL_DB.reset
|
390
|
+
end
|
391
|
+
after do
|
392
|
+
[:Artist, :Tag, :Album, :Track].each{|x| Object.send(:remove_const, x)}
|
393
|
+
end
|
394
|
+
|
395
|
+
it "should eagerly load a single many_through_many association" do
|
396
|
+
a = @c1.eager(:tags).all
|
397
|
+
a.should == [@c1.load(:id=>1)]
|
398
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists', 'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))']
|
399
|
+
a.first.tags.should == [Tag.load(:id=>2)]
|
400
|
+
MODEL_DB.sqls.length.should == 2
|
401
|
+
end
|
402
|
+
|
403
|
+
it "should eagerly load multiple associations in a single call" do
|
404
|
+
a = @c1.eager(:tags, :albums).all
|
405
|
+
a.should == [@c1.load(:id=>1)]
|
406
|
+
MODEL_DB.sqls.length.should == 3
|
407
|
+
MODEL_DB.sqls[0].should == 'SELECT * FROM artists'
|
408
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))'))
|
409
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))'))
|
410
|
+
a = a.first
|
411
|
+
a.tags.should == [Tag.load(:id=>2)]
|
412
|
+
a.albums.should == [Album.load(:id=>3)]
|
413
|
+
MODEL_DB.sqls.length.should == 3
|
414
|
+
end
|
415
|
+
|
416
|
+
it "should eagerly load multiple associations in separate" do
|
417
|
+
a = @c1.eager(:tags).eager(:albums).all
|
418
|
+
a.should == [@c1.load(:id=>1)]
|
419
|
+
MODEL_DB.sqls.length.should == 3
|
420
|
+
MODEL_DB.sqls[0].should == 'SELECT * FROM artists'
|
421
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))'))
|
422
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))'))
|
423
|
+
a = a.first
|
424
|
+
a.tags.should == [Tag.load(:id=>2)]
|
425
|
+
a.albums.should == [Album.load(:id=>3)]
|
426
|
+
MODEL_DB.sqls.length.should == 3
|
427
|
+
end
|
428
|
+
|
429
|
+
it "should allow cascading of eager loading for associations of associated models" do
|
430
|
+
a = @c1.eager(:tags=>:tracks).all
|
431
|
+
a.should == [@c1.load(:id=>1)]
|
432
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
433
|
+
'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))',
|
434
|
+
'SELECT tracks.*, albums_tags.tag_id AS x_foreign_key_x FROM tracks INNER JOIN albums ON (albums.id = tracks.album_id) INNER JOIN albums_tags ON ((albums_tags.album_id = albums.id) AND (albums_tags.tag_id IN (2)))']
|
435
|
+
a = a.first
|
436
|
+
a.tags.should == [Tag.load(:id=>2)]
|
437
|
+
a.tags.first.tracks.should == [Track.load(:id=>4)]
|
438
|
+
MODEL_DB.sqls.length.should == 3
|
439
|
+
end
|
440
|
+
|
441
|
+
it "should cascade eagerly loading when the :eager association option is used" do
|
442
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager=>:tracks
|
443
|
+
a = @c1.eager(:tags).all
|
444
|
+
a.should == [@c1.load(:id=>1)]
|
445
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
446
|
+
'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))',
|
447
|
+
'SELECT tracks.*, albums_tags.tag_id AS x_foreign_key_x FROM tracks INNER JOIN albums ON (albums.id = tracks.album_id) INNER JOIN albums_tags ON ((albums_tags.album_id = albums.id) AND (albums_tags.tag_id IN (2)))']
|
448
|
+
a = a.first
|
449
|
+
a.tags.should == [Tag.load(:id=>2)]
|
450
|
+
a.tags.first.tracks.should == [Track.load(:id=>4)]
|
451
|
+
MODEL_DB.sqls.length.should == 3
|
452
|
+
end
|
453
|
+
|
454
|
+
it "should respect :eager when lazily loading an association" do
|
455
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager=>:tracks
|
456
|
+
a = @c1.load(:id=>1)
|
457
|
+
a.tags.should == [Tag.load(:id=>2)]
|
458
|
+
MODEL_DB.sqls.should == ['SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1))',
|
459
|
+
'SELECT tracks.*, albums_tags.tag_id AS x_foreign_key_x FROM tracks INNER JOIN albums ON (albums.id = tracks.album_id) INNER JOIN albums_tags ON ((albums_tags.album_id = albums.id) AND (albums_tags.tag_id IN (2)))']
|
460
|
+
a.tags.first.tracks.should == [Track.load(:id=>4)]
|
461
|
+
MODEL_DB.sqls.length.should == 2
|
462
|
+
end
|
463
|
+
|
464
|
+
it "should cascade eagerly loading when the :eager_graph association option is used" do
|
465
|
+
Tag.dataset.extend(Module.new {
|
466
|
+
def columns
|
467
|
+
[:id]
|
468
|
+
end
|
469
|
+
def fetch_rows(sql)
|
470
|
+
@db << sql
|
471
|
+
yield({:id=>2, :tracks_id=>4, :x_foreign_key_x=>1})
|
472
|
+
end
|
473
|
+
})
|
474
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager_graph=>:tracks
|
475
|
+
a = @c1.eager(:tags).all
|
476
|
+
a.should == [@c1.load(:id=>1)]
|
477
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
478
|
+
'SELECT tags.id, tracks.id AS tracks_id, albums_artists.artist_id AS x_foreign_key_x FROM (SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))) AS tags LEFT OUTER JOIN albums_tags AS albums_tags_0 ON (albums_tags_0.tag_id = tags.id) LEFT OUTER JOIN albums ON (albums.id = albums_tags_0.album_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)']
|
479
|
+
a = a.first
|
480
|
+
a.tags.should == [Tag.load(:id=>2)]
|
481
|
+
a.tags.first.tracks.should == [Track.load(:id=>4)]
|
482
|
+
MODEL_DB.sqls.length.should == 2
|
483
|
+
end
|
484
|
+
|
485
|
+
it "should respect :eager_graph when lazily loading an association" do
|
486
|
+
Tag.dataset.extend(Module.new {
|
487
|
+
def columns
|
488
|
+
[:id]
|
489
|
+
end
|
490
|
+
def fetch_rows(sql)
|
491
|
+
@db << sql
|
492
|
+
yield({:id=>2, :tracks_id=>4})
|
493
|
+
end
|
494
|
+
})
|
495
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager_graph=>:tracks
|
496
|
+
a = @c1.load(:id=>1)
|
497
|
+
a.tags
|
498
|
+
MODEL_DB.sqls.should == [ 'SELECT tags.id, tracks.id AS tracks_id FROM (SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id = 1))) AS tags LEFT OUTER JOIN albums_tags AS albums_tags_0 ON (albums_tags_0.tag_id = tags.id) LEFT OUTER JOIN albums ON (albums.id = albums_tags_0.album_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)']
|
499
|
+
a.tags.should == [Tag.load(:id=>2)]
|
500
|
+
a.tags.first.tracks.should == [Track.load(:id=>4)]
|
501
|
+
MODEL_DB.sqls.length.should == 1
|
502
|
+
end
|
503
|
+
|
504
|
+
it "should respect :conditions when eagerly loading" do
|
505
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :conditions=>{:a=>32}
|
506
|
+
a = @c1.eager(:tags).all
|
507
|
+
a.should == [@c1.load(:id=>1)]
|
508
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
509
|
+
'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1))) WHERE (a = 32)']
|
510
|
+
a.first.tags.should == [Tag.load(:id=>2)]
|
511
|
+
MODEL_DB.sqls.length.should == 2
|
512
|
+
end
|
513
|
+
|
514
|
+
it "should respect :order when eagerly loading" do
|
515
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :order=>:blah
|
516
|
+
a = @c1.eager(:tags).all
|
517
|
+
a.should == [@c1.load(:id=>1)]
|
518
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
519
|
+
'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1))) ORDER BY blah']
|
520
|
+
a.first.tags.should == [Tag.load(:id=>2)]
|
521
|
+
MODEL_DB.sqls.length.should == 2
|
522
|
+
end
|
523
|
+
|
524
|
+
it "should use the association's block when eager loading by default" do
|
525
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]] do |ds| ds.filter(:a) end
|
526
|
+
a = @c1.eager(:tags).all
|
527
|
+
a.should == [@c1.load(:id=>1)]
|
528
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
529
|
+
'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1))) WHERE a']
|
530
|
+
a.first.tags.should == [Tag.load(:id=>2)]
|
531
|
+
MODEL_DB.sqls.length.should == 2
|
532
|
+
end
|
533
|
+
|
534
|
+
it "should use the :eager_block option when eager loading if given" do
|
535
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager_block=>proc{|ds| ds.filter(:b)} do |ds| ds.filter(:a) end
|
536
|
+
a = @c1.eager(:tags).all
|
537
|
+
a.should == [@c1.load(:id=>1)]
|
538
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
539
|
+
'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1))) WHERE b']
|
540
|
+
a.first.tags.should == [Tag.load(:id=>2)]
|
541
|
+
MODEL_DB.sqls.length.should == 2
|
542
|
+
end
|
543
|
+
|
544
|
+
it "should raise an error when attempting to eagerly load an association with the :allow_eager option set to false" do
|
545
|
+
proc{@c1.eager(:tags).all}.should_not raise_error
|
546
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :allow_eager=>false
|
547
|
+
proc{@c1.eager(:tags).all}.should raise_error(Sequel::Error)
|
548
|
+
end
|
549
|
+
|
550
|
+
it "should respect the association's :select option" do
|
551
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>:tags__name
|
552
|
+
a = @c1.eager(:tags).all
|
553
|
+
a.should == [@c1.load(:id=>1)]
|
554
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
555
|
+
'SELECT tags.name, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))']
|
556
|
+
a.first.tags.should == [Tag.load(:id=>2)]
|
557
|
+
MODEL_DB.sqls.length.should == 2
|
558
|
+
end
|
559
|
+
|
560
|
+
it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
|
561
|
+
@c1.send(:define_method, :yyy){values[:yyy]}
|
562
|
+
@c1.dataset.extend(Module.new {
|
563
|
+
def columns
|
564
|
+
[:id, :yyy]
|
565
|
+
end
|
566
|
+
def fetch_rows(sql)
|
567
|
+
@db << sql
|
568
|
+
yield({:id=>1, :yyy=>8})
|
569
|
+
end
|
570
|
+
})
|
571
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :left_primary_key=>:yyy, :right_primary_key=>:tag_id
|
572
|
+
a = @c1.eager(:tags).all
|
573
|
+
a.should == [@c1.load(:id=>1, :yyy=>8)]
|
574
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
575
|
+
'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.tag_id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (8)))']
|
576
|
+
a.first.tags.should == [Tag.load(:tag_id=>2)]
|
577
|
+
MODEL_DB.sqls.length.should == 2
|
578
|
+
end
|
579
|
+
|
580
|
+
it "should handle composite keys" do
|
581
|
+
@c1.send(:define_method, :yyy){values[:yyy]}
|
582
|
+
@c1.dataset.extend(Module.new {
|
583
|
+
def columns
|
584
|
+
[:id, :yyy]
|
585
|
+
end
|
586
|
+
def fetch_rows(sql)
|
587
|
+
@db << sql
|
588
|
+
yield({:id=>1, :yyy=>8})
|
589
|
+
end
|
590
|
+
})
|
591
|
+
@c1.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:h1, :h2], :left_primary_key=>[:id, :yyy]
|
592
|
+
a = @c1.eager(:tags).all
|
593
|
+
a.should == [@c1.load(:id=>1, :yyy=>8)]
|
594
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
595
|
+
'SELECT tags.*, albums_artists.b1 AS x_foreign_key_0_x, albums_artists.b2 AS x_foreign_key_1_x FROM tags INNER JOIN albums_tags ON ((albums_tags.g1 = tags.h1) AND (albums_tags.g2 = tags.h2)) INNER JOIN albums ON ((albums.e1 = albums_tags.f1) AND (albums.e2 = albums_tags.f2)) INNER JOIN albums_artists ON ((albums_artists.c1 = albums.d1) AND (albums_artists.c2 = albums.d2) AND ((albums_artists.b1, albums_artists.b2) IN ((1, 8))))']
|
596
|
+
a.first.tags.should == [Tag.load(:id=>2)]
|
597
|
+
MODEL_DB.sqls.length.should == 2
|
598
|
+
end
|
599
|
+
|
600
|
+
it "should respect :after_load callbacks on associations when eager loading" do
|
601
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :after_load=>lambda{|o, as| o[:id] *= 2; as.each{|a| a[:id] *= 3}}
|
602
|
+
a = @c1.eager(:tags).all
|
603
|
+
a.should == [@c1.load(:id=>2)]
|
604
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists',
|
605
|
+
'SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))']
|
606
|
+
a.first.tags.should == [Tag.load(:id=>6)]
|
607
|
+
MODEL_DB.sqls.length.should == 2
|
608
|
+
end
|
609
|
+
|
610
|
+
it "should raise an error if called without a symbol or hash" do
|
611
|
+
proc{@c1.eager_graph(Object.new)}.should raise_error(Sequel::Error)
|
612
|
+
end
|
613
|
+
|
614
|
+
it "should eagerly graph a single many_through_many association" do
|
615
|
+
a = @c1.eager_graph(:tags).all
|
616
|
+
a.should == [@c1.load(:id=>1)]
|
617
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)']
|
618
|
+
a.first.tags.should == [Tag.load(:id=>2)]
|
619
|
+
MODEL_DB.sqls.length.should == 1
|
620
|
+
end
|
621
|
+
|
622
|
+
it "should eagerly graph multiple associations in a single call" do
|
623
|
+
a = @c1.eager_graph(:tags, :albums).all
|
624
|
+
a.should == [@c1.load(:id=>1)]
|
625
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id, albums_0.id AS albums_0_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.artist_id = artists.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_0.album_id)']
|
626
|
+
a = a.first
|
627
|
+
a.tags.should == [Tag.load(:id=>2)]
|
628
|
+
a.albums.should == [Album.load(:id=>3)]
|
629
|
+
MODEL_DB.sqls.length.should == 1
|
630
|
+
end
|
631
|
+
|
632
|
+
it "should eagerly graph multiple associations in separate calls" do
|
633
|
+
a = @c1.eager_graph(:tags).eager_graph(:albums).all
|
634
|
+
a.should == [@c1.load(:id=>1)]
|
635
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id, albums_0.id AS albums_0_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.artist_id = artists.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_0.album_id)']
|
636
|
+
a = a.first
|
637
|
+
a.tags.should == [Tag.load(:id=>2)]
|
638
|
+
a.albums.should == [Album.load(:id=>3)]
|
639
|
+
MODEL_DB.sqls.length.should == 1
|
640
|
+
end
|
641
|
+
|
642
|
+
it "should allow cascading of eager graphing for associations of associated models" do
|
643
|
+
a = @c1.eager_graph(:tags=>:tracks).all
|
644
|
+
a.should == [@c1.load(:id=>1)]
|
645
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id, tracks.id AS tracks_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_tags AS albums_tags_0 ON (albums_tags_0.tag_id = tags.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_tags_0.album_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums_0.id)']
|
646
|
+
a = a.first
|
647
|
+
a.tags.should == [Tag.load(:id=>2)]
|
648
|
+
a.tags.first.tracks.should == [Track.load(:id=>4)]
|
649
|
+
MODEL_DB.sqls.length.should == 1
|
650
|
+
end
|
651
|
+
|
652
|
+
it "eager graphing should eliminate duplicates caused by cartesian products" do
|
653
|
+
ds = @c1.eager_graph(:tags)
|
654
|
+
def ds.fetch_rows(sql, &block)
|
655
|
+
@db << sql
|
656
|
+
# Assume artist has 2 albums each with 2 tags
|
657
|
+
yield({:id=>1, :tags_id=>2})
|
658
|
+
yield({:id=>1, :tags_id=>3})
|
659
|
+
yield({:id=>1, :tags_id=>2})
|
660
|
+
yield({:id=>1, :tags_id=>3})
|
661
|
+
end
|
662
|
+
a = ds.all
|
663
|
+
a.should == [@c1.load(:id=>1)]
|
664
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)']
|
665
|
+
a.first.tags.should == [Tag.load(:id=>2), Tag.load(:id=>3)]
|
666
|
+
MODEL_DB.sqls.length.should == 1
|
667
|
+
end
|
668
|
+
|
669
|
+
it "should eager graph multiple associations from the same table" do
|
670
|
+
a = @c1.eager_graph(:tags, :other_tags).all
|
671
|
+
a.should == [@c1.load(:id=>1)]
|
672
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id, other_tags.id AS other_tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.artist_id = artists.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_0.album_id) LEFT OUTER JOIN albums_tags AS albums_tags_0 ON (albums_tags_0.album_id = albums_0.id) LEFT OUTER JOIN tags AS other_tags ON (other_tags.id = albums_tags_0.tag_id)']
|
673
|
+
a = a.first
|
674
|
+
a.tags.should == [Tag.load(:id=>2)]
|
675
|
+
a.other_tags.should == [Tag.load(:id=>9)]
|
676
|
+
MODEL_DB.sqls.length.should == 1
|
677
|
+
end
|
678
|
+
|
679
|
+
it "should eager graph a self_referential association" do
|
680
|
+
a = @c1.eager_graph(:tags, :artists).all
|
681
|
+
a.should == [@c1.load(:id=>1)]
|
682
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id, artists_0.id AS artists_0_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.artist_id = artists.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_0.album_id) LEFT OUTER JOIN albums_artists AS albums_artists_1 ON (albums_artists_1.album_id = albums_0.id) LEFT OUTER JOIN artists AS artists_0 ON (artists_0.id = albums_artists_1.artist_id)']
|
683
|
+
a = a.first
|
684
|
+
a.tags.should == [Tag.load(:id=>2)]
|
685
|
+
a.artists.should == [@c1.load(:id=>10)]
|
686
|
+
MODEL_DB.sqls.length.should == 1
|
687
|
+
end
|
688
|
+
|
689
|
+
it "eager graphing should give you a graph of tables when called without .all" do
|
690
|
+
@c1.eager_graph(:tags, :artists).first.should == {:artists=>@c1.load(:id=>1), :artists_0=>@c1.load(:id=>10), :tags=>Tag.load(:id=>2)}
|
691
|
+
end
|
692
|
+
|
693
|
+
it "should be able to use eager and eager_graph together" do
|
694
|
+
a = @c1.eager_graph(:tags).eager(:albums).all
|
695
|
+
a.should == [@c1.load(:id=>1)]
|
696
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)',
|
697
|
+
'SELECT albums.*, albums_artists.artist_id AS x_foreign_key_x FROM albums INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (1)))']
|
698
|
+
a = a.first
|
699
|
+
a.tags.should == [Tag.load(:id=>2)]
|
700
|
+
a.albums.should == [Album.load(:id=>3)]
|
701
|
+
MODEL_DB.sqls.length.should == 2
|
702
|
+
end
|
703
|
+
|
704
|
+
it "should handle no associated records when eagerly graphing a single many_through_many association" do
|
705
|
+
ds = @c1.eager_graph(:tags)
|
706
|
+
def ds.fetch_rows(sql)
|
707
|
+
@db << sql
|
708
|
+
yield({:id=>1, :tags_id=>nil})
|
709
|
+
end
|
710
|
+
a = ds.all
|
711
|
+
a.should == [@c1.load(:id=>1)]
|
712
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)']
|
713
|
+
a.first.tags.should == []
|
714
|
+
MODEL_DB.sqls.length.should == 1
|
715
|
+
end
|
716
|
+
|
717
|
+
it "should handle no associated records when eagerly graphing multiple many_through_many associations" do
|
718
|
+
ds = @c1.eager_graph(:tags, :albums)
|
719
|
+
def ds.fetch_rows(sql)
|
720
|
+
@db << sql
|
721
|
+
yield({:id=>1, :tags_id=>nil, :albums_0_id=>3})
|
722
|
+
yield({:id=>1, :tags_id=>2, :albums_0_id=>nil})
|
723
|
+
yield({:id=>1, :tags_id=>5, :albums_0_id=>6})
|
724
|
+
yield({:id=>7, :tags_id=>nil, :albums_0_id=>nil})
|
725
|
+
end
|
726
|
+
a = ds.all
|
727
|
+
a.should == [@c1.load(:id=>1), @c1.load(:id=>7)]
|
728
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id, albums_0.id AS albums_0_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.artist_id = artists.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_0.album_id)']
|
729
|
+
a.first.tags.should == [Tag.load(:id=>2), Tag.load(:id=>5)]
|
730
|
+
a.first.albums.should == [Album.load(:id=>3), Album.load(:id=>6)]
|
731
|
+
a.last.tags.should == []
|
732
|
+
a.last.albums.should == []
|
733
|
+
MODEL_DB.sqls.length.should == 1
|
734
|
+
end
|
735
|
+
|
736
|
+
it "should handle missing associated records when cascading eager graphing for associations of associated models" do
|
737
|
+
ds = @c1.eager_graph(:tags=>:tracks)
|
738
|
+
def ds.fetch_rows(sql)
|
739
|
+
@db << sql
|
740
|
+
yield({:id=>1, :tags_id=>2, :tracks_id=>4})
|
741
|
+
yield({:id=>1, :tags_id=>3, :tracks_id=>nil})
|
742
|
+
yield({:id=>2, :tags_id=>nil, :tracks_id=>nil})
|
743
|
+
end
|
744
|
+
a = ds.all
|
745
|
+
a.should == [@c1.load(:id=>1), @c1.load(:id=>2)]
|
746
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.id AS tags_id, tracks.id AS tracks_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_tags AS albums_tags_0 ON (albums_tags_0.tag_id = tags.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_tags_0.album_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums_0.id)']
|
747
|
+
a.last.tags.should == []
|
748
|
+
a = a.first
|
749
|
+
a.tags.should == [Tag.load(:id=>2), Tag.load(:id=>3)]
|
750
|
+
a.tags.first.tracks.should == [Track.load(:id=>4)]
|
751
|
+
a.tags.last.tracks.should == []
|
752
|
+
MODEL_DB.sqls.length.should == 1
|
753
|
+
end
|
754
|
+
|
755
|
+
it "eager graphing should respect :left_primary_key and :right_primary_key options" do
|
756
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :left_primary_key=>:yyy, :right_primary_key=>:tag_id
|
757
|
+
@c1.dataset.meta_def(:columns){[:id, :yyy]}
|
758
|
+
Tag.dataset.meta_def(:columns){[:id, :tag_id]}
|
759
|
+
ds = @c1.eager_graph(:tags)
|
760
|
+
def ds.fetch_rows(sql)
|
761
|
+
@db << sql
|
762
|
+
yield({:id=>1, :yyy=>8, :tags_id=>2, :tag_id=>4})
|
763
|
+
end
|
764
|
+
a = ds.all
|
765
|
+
a.should == [@c1.load(:id=>1, :yyy=>8)]
|
766
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, artists.yyy, tags.id AS tags_id, tags.tag_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.yyy) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.tag_id = albums_tags.tag_id)']
|
767
|
+
a.first.tags.should == [Tag.load(:id=>2, :tag_id=>4)]
|
768
|
+
MODEL_DB.sqls.length.should == 1
|
769
|
+
end
|
770
|
+
|
771
|
+
it "eager graphing should respect composite keys" do
|
772
|
+
@c1.many_through_many :tags, [[:albums_artists, [:b1, :b2], [:c1, :c2]], [:albums, [:d1, :d2], [:e1, :e2]], [:albums_tags, [:f1, :f2], [:g1, :g2]]], :right_primary_key=>[:id, :tag_id], :left_primary_key=>[:id, :yyy]
|
773
|
+
@c1.dataset.meta_def(:columns){[:id, :yyy]}
|
774
|
+
Tag.dataset.meta_def(:columns){[:id, :tag_id]}
|
775
|
+
ds = @c1.eager_graph(:tags)
|
776
|
+
def ds.fetch_rows(sql)
|
777
|
+
@db << sql
|
778
|
+
yield({:id=>1, :yyy=>8, :tags_id=>2, :tag_id=>4})
|
779
|
+
end
|
780
|
+
a = ds.all
|
781
|
+
a.should == [@c1.load(:id=>1, :yyy=>8)]
|
782
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, artists.yyy, tags.id AS tags_id, tags.tag_id FROM artists LEFT OUTER JOIN albums_artists ON ((albums_artists.b1 = artists.id) AND (albums_artists.b2 = artists.yyy)) LEFT OUTER JOIN albums ON ((albums.d1 = albums_artists.c1) AND (albums.d2 = albums_artists.c2)) LEFT OUTER JOIN albums_tags ON ((albums_tags.f1 = albums.e1) AND (albums_tags.f2 = albums.e2)) LEFT OUTER JOIN tags ON ((tags.id = albums_tags.g1) AND (tags.tag_id = albums_tags.g2))']
|
783
|
+
a.first.tags.should == [Tag.load(:id=>2, :tag_id=>4)]
|
784
|
+
MODEL_DB.sqls.length.should == 1
|
785
|
+
end
|
786
|
+
|
787
|
+
it "should respect the association's :graph_select option" do
|
788
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :graph_select=>:b
|
789
|
+
ds = @c1.eager_graph(:tags)
|
790
|
+
def ds.fetch_rows(sql)
|
791
|
+
@db << sql
|
792
|
+
yield({:id=>1, :b=>2})
|
793
|
+
end
|
794
|
+
a = ds.all
|
795
|
+
a.should == [@c1.load(:id=>1)]
|
796
|
+
MODEL_DB.sqls.should == ['SELECT artists.id, tags.b FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)']
|
797
|
+
a.first.tags.should == [Tag.load(:b=>2)]
|
798
|
+
MODEL_DB.sqls.length.should == 1
|
799
|
+
end
|
800
|
+
|
801
|
+
it "should respect the association's :graph_join_type option" do
|
802
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :graph_join_type=>:inner
|
803
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists INNER JOIN albums_artists ON (albums_artists.artist_id = artists.id) INNER JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) INNER JOIN tags ON (tags.id = albums_tags.tag_id)'
|
804
|
+
end
|
805
|
+
|
806
|
+
it "should respect the association's :join_type option on through" do
|
807
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id, :join_type=>:natural}, [:albums_tags, :album_id, :tag_id]], :graph_join_type=>:inner
|
808
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists INNER JOIN albums_artists ON (albums_artists.artist_id = artists.id) NATURAL JOIN albums ON (albums.id = albums_artists.album_id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) INNER JOIN tags ON (tags.id = albums_tags.tag_id)'
|
809
|
+
end
|
810
|
+
|
811
|
+
it "should respect the association's :conditions option" do
|
812
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :conditions=>{:a=>32}
|
813
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON ((tags.id = albums_tags.tag_id) AND (tags.a = 32))'
|
814
|
+
end
|
815
|
+
|
816
|
+
it "should respect the association's :graph_conditions option" do
|
817
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :graph_conditions=>{:a=>42}
|
818
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON ((tags.id = albums_tags.tag_id) AND (tags.a = 42))'
|
819
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :graph_conditions=>{:a=>42}, :conditions=>{:a=>32}
|
820
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON ((tags.id = albums_tags.tag_id) AND (tags.a = 42))'
|
821
|
+
end
|
822
|
+
|
823
|
+
it "should respect the association's :conditions option on through" do
|
824
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id, :conditions=>{:a=>42}}, [:albums_tags, :album_id, :tag_id]]
|
825
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON ((albums.id = albums_artists.album_id) AND (albums.a = 42)) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)'
|
826
|
+
end
|
827
|
+
|
828
|
+
it "should respect the association's :graph_block option" do
|
829
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :graph_block=>proc{|ja,lja,js| {:active.qualify(ja)=>true}}
|
830
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON ((tags.id = albums_tags.tag_id) AND (tags.active IS TRUE))'
|
831
|
+
end
|
832
|
+
|
833
|
+
it "should respect the association's :block option on through" do
|
834
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id, :block=>proc{|ja,lja,js| {:active.qualify(ja)=>true}}}, [:albums_tags, :album_id, :tag_id]]
|
835
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON ((albums.id = albums_artists.album_id) AND (albums.active IS TRUE)) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)'
|
836
|
+
end
|
837
|
+
|
838
|
+
it "should respect the association's :graph_only_conditions option" do
|
839
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :graph_only_conditions=>{:a=>32}
|
840
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.a = 32)'
|
841
|
+
end
|
842
|
+
|
843
|
+
it "should respect the association's :only_conditions option on through" do
|
844
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id, :only_conditions=>{:a=>42}}, [:albums_tags, :album_id, :tag_id]]
|
845
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.a = 42) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)'
|
846
|
+
end
|
847
|
+
|
848
|
+
it "should create unique table aliases for all associations" do
|
849
|
+
@c1.eager_graph(:artists=>{:artists=>:artists}).sql.should == "SELECT artists.id, artists_0.id AS artists_0_id, artists_1.id AS artists_1_id, artists_2.id AS artists_2_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.album_id = albums.id) LEFT OUTER JOIN artists AS artists_0 ON (artists_0.id = albums_artists_0.artist_id) LEFT OUTER JOIN albums_artists AS albums_artists_1 ON (albums_artists_1.artist_id = artists_0.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_1.album_id) LEFT OUTER JOIN albums_artists AS albums_artists_2 ON (albums_artists_2.album_id = albums_0.id) LEFT OUTER JOIN artists AS artists_1 ON (artists_1.id = albums_artists_2.artist_id) LEFT OUTER JOIN albums_artists AS albums_artists_3 ON (albums_artists_3.artist_id = artists_1.id) LEFT OUTER JOIN albums AS albums_1 ON (albums_1.id = albums_artists_3.album_id) LEFT OUTER JOIN albums_artists AS albums_artists_4 ON (albums_artists_4.album_id = albums_1.id) LEFT OUTER JOIN artists AS artists_2 ON (artists_2.id = albums_artists_4.artist_id)"
|
850
|
+
end
|
851
|
+
|
852
|
+
it "should respect the association's :order" do
|
853
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[:blah1, :blah2]
|
854
|
+
@c1.order(:artists__blah2, :artists__blah3).eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tags.blah1, tags.blah2'
|
855
|
+
end
|
856
|
+
|
857
|
+
it "should only qualify unqualified symbols, identifiers, or ordered versions in association's :order" do
|
858
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[:blah__id.identifier, :blah__id.identifier.desc, :blah__id.desc, :blah__id, :album_id, :album_id.desc, 1, 'RANDOM()'.lit, :a.qualify(:b)]
|
859
|
+
@c1.order(:artists__blah2, :artists__blah3).eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tags.blah__id, tags.blah__id DESC, blah.id DESC, blah.id, tags.album_id, tags.album_id DESC, 1, RANDOM(), b.a'
|
860
|
+
end
|
861
|
+
|
862
|
+
it "should not respect the association's :order if :order_eager_graph is false" do
|
863
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[:blah1, :blah2], :order_eager_graph=>false
|
864
|
+
@c1.order(:artists__blah2, :artists__blah3).eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3'
|
865
|
+
end
|
866
|
+
|
867
|
+
it "should add the associations :order for multiple associations" do
|
868
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[:blah1, :blah2]
|
869
|
+
@c1.many_through_many :albums, [[:albums_artists, :artist_id, :album_id]], :order=>[:blah3, :blah4]
|
870
|
+
@c1.eager_graph(:tags, :albums).sql.should == 'SELECT artists.id, tags.id AS tags_id, albums_0.id AS albums_0_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_artists AS albums_artists_0 ON (albums_artists_0.artist_id = artists.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_0.album_id) ORDER BY tags.blah1, tags.blah2, albums_0.blah3, albums_0.blah4'
|
871
|
+
end
|
872
|
+
|
873
|
+
it "should add the association's :order for cascading associations" do
|
874
|
+
@c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[:blah1, :blah2]
|
875
|
+
Tag.many_through_many :tracks, [[:albums_tags, :tag_id, :album_id], [:albums, :id, :id]], :right_primary_key=>:album_id, :order=>[:blah3, :blah4]
|
876
|
+
@c1.eager_graph(:tags=>:tracks).sql.should == 'SELECT artists.id, tags.id AS tags_id, tracks.id AS tracks_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_tags AS albums_tags_0 ON (albums_tags_0.tag_id = tags.id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_tags_0.album_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums_0.id) ORDER BY tags.blah1, tags.blah2, tracks.blah3, tracks.blah4'
|
877
|
+
end
|
878
|
+
|
879
|
+
it "should use the correct qualifier when graphing multiple tables with extra conditions" do
|
880
|
+
@c1.many_through_many :tags, [{:table=>:albums_artists, :left=>:artist_id, :right=>:album_id, :conditions=>{:a=>:b}}, {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]]
|
881
|
+
@c1.many_through_many :albums, [{:table=>:albums_artists, :left=>:artist_id, :right=>:album_id, :conditions=>{:c=>:d}}]
|
882
|
+
@c1.eager_graph(:tags, :albums).sql.should == 'SELECT artists.id, tags.id AS tags_id, albums_0.id AS albums_0_id FROM artists LEFT OUTER JOIN albums_artists ON ((albums_artists.artist_id = artists.id) AND (albums_artists.a = artists.b)) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_artists AS albums_artists_0 ON ((albums_artists_0.artist_id = artists.id) AND (albums_artists_0.c = artists.d)) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_0.album_id)'
|
883
|
+
end
|
884
|
+
end
|