sequel 2.12.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +62 -0
- data/README.rdoc +3 -3
- data/Rakefile +7 -0
- data/doc/advanced_associations.rdoc +44 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/lib/sequel/adapters/amalgalite.rb +208 -0
- data/lib/sequel/adapters/db2.rb +3 -0
- data/lib/sequel/adapters/dbi.rb +9 -0
- data/lib/sequel/adapters/do.rb +0 -4
- data/lib/sequel/adapters/firebird.rb +16 -18
- data/lib/sequel/adapters/informix.rb +5 -3
- data/lib/sequel/adapters/jdbc.rb +24 -20
- data/lib/sequel/adapters/jdbc/h2.rb +15 -4
- data/lib/sequel/adapters/mysql.rb +4 -8
- data/lib/sequel/adapters/odbc.rb +0 -4
- data/lib/sequel/adapters/oracle.rb +0 -4
- data/lib/sequel/adapters/shared/mssql.rb +16 -5
- data/lib/sequel/adapters/shared/mysql.rb +87 -86
- data/lib/sequel/adapters/shared/oracle.rb +92 -3
- data/lib/sequel/adapters/shared/postgres.rb +85 -29
- data/lib/sequel/adapters/shared/progress.rb +8 -3
- data/lib/sequel/adapters/shared/sqlite.rb +53 -23
- data/lib/sequel/adapters/sqlite.rb +4 -7
- data/lib/sequel/adapters/utils/unsupported.rb +3 -3
- data/lib/sequel/connection_pool.rb +18 -25
- data/lib/sequel/core.rb +2 -21
- data/lib/sequel/database.rb +60 -44
- data/lib/sequel/database/schema_generator.rb +26 -31
- data/lib/sequel/database/schema_methods.rb +8 -3
- data/lib/sequel/database/schema_sql.rb +114 -28
- data/lib/sequel/dataset.rb +14 -41
- data/lib/sequel/dataset/convenience.rb +31 -54
- data/lib/sequel/dataset/graph.rb +7 -13
- data/lib/sequel/dataset/sql.rb +43 -54
- data/lib/sequel/extensions/inflector.rb +0 -5
- data/lib/sequel/extensions/schema_dumper.rb +238 -0
- data/lib/sequel/metaprogramming.rb +0 -20
- data/lib/sequel/model.rb +1 -2
- data/lib/sequel/model/base.rb +18 -16
- data/lib/sequel/model/inflections.rb +6 -9
- data/lib/sequel/plugins/caching.rb +0 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +2 -0
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/firebird_spec.rb +35 -8
- data/spec/adapters/mysql_spec.rb +173 -266
- data/spec/adapters/oracle_spec.rb +13 -0
- data/spec/adapters/postgres_spec.rb +127 -227
- data/spec/adapters/sqlite_spec.rb +13 -171
- data/spec/core/connection_pool_spec.rb +15 -4
- data/spec/core/core_sql_spec.rb +14 -170
- data/spec/core/database_spec.rb +50 -132
- data/spec/core/dataset_spec.rb +47 -930
- data/spec/core/expression_filters_spec.rb +12 -0
- data/spec/core/schema_generator_spec.rb +37 -45
- data/spec/core/schema_spec.rb +26 -16
- data/spec/core/spec_helper.rb +0 -25
- data/spec/extensions/inflector_spec.rb +0 -3
- data/spec/extensions/schema_dumper_spec.rb +292 -0
- data/spec/extensions/serialization_spec.rb +9 -0
- data/spec/extensions/single_table_inheritance_spec.rb +6 -1
- data/spec/extensions/spec_helper.rb +1 -3
- data/spec/extensions/validation_helpers_spec.rb +4 -4
- data/spec/integration/database_test.rb +18 -0
- data/spec/integration/dataset_test.rb +112 -1
- data/spec/integration/eager_loader_test.rb +70 -9
- data/spec/integration/prepared_statement_test.rb +2 -2
- data/spec/integration/schema_test.rb +76 -27
- data/spec/integration/spec_helper.rb +0 -14
- data/spec/integration/transaction_test.rb +27 -0
- data/spec/model/associations_spec.rb +0 -36
- data/spec/model/base_spec.rb +18 -123
- data/spec/model/hooks_spec.rb +2 -235
- data/spec/model/inflector_spec.rb +15 -115
- data/spec/model/model_spec.rb +0 -120
- data/spec/model/plugins_spec.rb +0 -70
- data/spec/model/record_spec.rb +35 -93
- data/spec/model/spec_helper.rb +0 -27
- data/spec/model/validations_spec.rb +0 -931
- metadata +9 -14
- data/lib/sequel/deprecated.rb +0 -593
- data/lib/sequel/deprecated_migration.rb +0 -91
- data/lib/sequel/model/deprecated.rb +0 -204
- data/lib/sequel/model/deprecated_hooks.rb +0 -103
- data/lib/sequel/model/deprecated_inflector.rb +0 -335
- data/lib/sequel/model/deprecated_validations.rb +0 -388
- data/spec/core/core_ext_spec.rb +0 -156
- data/spec/core/migration_spec.rb +0 -263
- data/spec/core/pretty_table_spec.rb +0 -58
- data/spec/model/caching_spec.rb +0 -217
- data/spec/model/schema_spec.rb +0 -92
@@ -1,5 +1,7 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
2
|
|
3
|
+
require 'yaml'
|
4
|
+
|
3
5
|
describe "Serialization plugin" do
|
4
6
|
before do
|
5
7
|
@c = Class.new(Sequel::Model(:items)) do
|
@@ -49,6 +51,8 @@ describe "Serialization plugin" do
|
|
49
51
|
o = @c.first
|
50
52
|
o.id.should == 1
|
51
53
|
o.abc.should == 1
|
54
|
+
o.abc.should == 1
|
55
|
+
o.def.should == "hello"
|
52
56
|
o.def.should == "hello"
|
53
57
|
|
54
58
|
o.update(:abc => 23)
|
@@ -69,6 +73,8 @@ describe "Serialization plugin" do
|
|
69
73
|
o = @c.first
|
70
74
|
o.id.should == 1
|
71
75
|
o.abc.should == 1
|
76
|
+
o.abc.should == 1
|
77
|
+
o.def.should == "hello"
|
72
78
|
o.def.should == "hello"
|
73
79
|
|
74
80
|
o.update(:abc => 23)
|
@@ -89,6 +95,8 @@ describe "Serialization plugin" do
|
|
89
95
|
o = Class.new(@c).first
|
90
96
|
o.id.should == 1
|
91
97
|
o.abc.should == 1
|
98
|
+
o.abc.should == 1
|
99
|
+
o.def.should == "hello"
|
92
100
|
o.def.should == "hello"
|
93
101
|
|
94
102
|
o.update(:abc => 23)
|
@@ -103,6 +111,7 @@ describe "Serialization plugin" do
|
|
103
111
|
o = @c.load(:id => 1, :abc => "--- 1\n", :def => "--- hello\n")
|
104
112
|
o.abc = 23
|
105
113
|
o.deserialized_values.length.should == 1
|
114
|
+
o.abc.should == 23
|
106
115
|
o.refresh
|
107
116
|
o.deserialized_values.length.should == 0
|
108
117
|
end
|
@@ -4,7 +4,7 @@ describe Sequel::Model, "#sti_key" do
|
|
4
4
|
before do
|
5
5
|
class ::StiTest < Sequel::Model
|
6
6
|
def kind=(x); self[:kind] = x; end
|
7
|
-
def
|
7
|
+
def _refresh(x); end
|
8
8
|
plugin :single_table_inheritance, :kind
|
9
9
|
end
|
10
10
|
class ::StiTestSub1 < StiTest
|
@@ -14,6 +14,11 @@ describe Sequel::Model, "#sti_key" do
|
|
14
14
|
@ds = StiTest.dataset
|
15
15
|
MODEL_DB.reset
|
16
16
|
end
|
17
|
+
|
18
|
+
specify "should have simple_table = nil" do
|
19
|
+
StiTest.simple_table.should == nil
|
20
|
+
StiTestSub1.simple_table.should == nil
|
21
|
+
end
|
17
22
|
|
18
23
|
it "should return rows with the correct class based on the polymorphic_key value" do
|
19
24
|
def @ds.fetch_rows(sql)
|
@@ -10,7 +10,7 @@ end
|
|
10
10
|
|
11
11
|
Sequel.virtual_row_instance_eval = true
|
12
12
|
|
13
|
-
extensions = %w'string_date_time inflector pagination query pretty_table blank migration'
|
13
|
+
extensions = %w'string_date_time inflector pagination query pretty_table blank migration schema_dumper'
|
14
14
|
plugins = {:hook_class_methods=>[], :schema=>[], :validation_class_methods=>[]}
|
15
15
|
|
16
16
|
extensions.each{|e| require "sequel/extensions/#{e}"}
|
@@ -70,12 +70,10 @@ end
|
|
70
70
|
|
71
71
|
class << Sequel::Model
|
72
72
|
alias orig_columns columns
|
73
|
-
alias orig_str_columns str_columns
|
74
73
|
def columns(*cols)
|
75
74
|
return if cols.empty?
|
76
75
|
define_method(:columns){cols}
|
77
76
|
@dataset.instance_variable_set(:@columns, cols) if @dataset
|
78
|
-
define_method(:str_columns){cols.map{|x|x.to_s.freeze}}
|
79
77
|
def_column_accessor(*cols)
|
80
78
|
@columns = cols
|
81
79
|
@db_schema = {}
|
@@ -241,10 +241,10 @@ describe "Sequel::Plugins::ValidationHelpers" do
|
|
241
241
|
|
242
242
|
@user = @c.load(:id=>1, :username => "0records", :password => "anothertest")
|
243
243
|
@user.should be_valid
|
244
|
-
MODEL_DB.sqls.last.should == "SELECT COUNT(*) FROM items WHERE ((username = '0records') AND (id != 1)) LIMIT 1"
|
244
|
+
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (id != 1)) LIMIT 1"
|
245
245
|
@user = @c.new(:username => "0records", :password => "anothertest")
|
246
246
|
@user.should be_valid
|
247
|
-
MODEL_DB.sqls.last.should == "SELECT COUNT(*) FROM items WHERE (username = '0records') LIMIT 1"
|
247
|
+
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE (username = '0records') LIMIT 1"
|
248
248
|
end
|
249
249
|
|
250
250
|
it "should support validates_unique with multiple attributes" do
|
@@ -283,9 +283,9 @@ describe "Sequel::Plugins::ValidationHelpers" do
|
|
283
283
|
|
284
284
|
@user = @c.load(:id=>1, :username => "0records", :password => "anothertest")
|
285
285
|
@user.should be_valid
|
286
|
-
MODEL_DB.sqls.last.should == "SELECT COUNT(*) FROM items WHERE (((username = '0records') AND (password = 'anothertest')) AND (id != 1)) LIMIT 1"
|
286
|
+
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE (((username = '0records') AND (password = 'anothertest')) AND (id != 1)) LIMIT 1"
|
287
287
|
@user = @c.new(:username => "0records", :password => "anothertest")
|
288
288
|
@user.should be_valid
|
289
|
-
MODEL_DB.sqls.last.should == "SELECT COUNT(*) FROM items WHERE ((username = '0records') AND (password = 'anothertest')) LIMIT 1"
|
289
|
+
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = 'anothertest')) LIMIT 1"
|
290
290
|
end
|
291
291
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe Sequel::Database do
|
4
|
+
specify "should provide disconnect functionality" do
|
5
|
+
INTEGRATION_DB.test_connection
|
6
|
+
INTEGRATION_DB.pool.size.should == 1
|
7
|
+
INTEGRATION_DB.disconnect
|
8
|
+
INTEGRATION_DB.pool.size.should == 0
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "should raise Sequel::DatabaseError on invalid SQL" do
|
12
|
+
proc{INTEGRATION_DB << "SELECT"}.should raise_error(Sequel::DatabaseError)
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "should not have the connection pool swallow non-StandardError based exceptions" do
|
16
|
+
proc{INTEGRATION_DB.pool.hold{raise Interrupt, "test"}}.should raise_error(Interrupt)
|
17
|
+
end
|
18
|
+
end
|
@@ -4,7 +4,7 @@ describe "Simple Dataset operations" do
|
|
4
4
|
before do
|
5
5
|
INTEGRATION_DB.create_table!(:items) do
|
6
6
|
primary_key :id
|
7
|
-
|
7
|
+
Integer :number
|
8
8
|
end
|
9
9
|
@ds = INTEGRATION_DB[:items]
|
10
10
|
@ds.insert(:number=>10)
|
@@ -14,6 +14,15 @@ describe "Simple Dataset operations" do
|
|
14
14
|
INTEGRATION_DB.drop_table(:items)
|
15
15
|
end
|
16
16
|
|
17
|
+
specify "should support sequential primary keys" do
|
18
|
+
@ds << {:number=>20}
|
19
|
+
@ds << {:number=>30}
|
20
|
+
@ds.order(:number).all.should == [
|
21
|
+
{:id => 1, :number=>10},
|
22
|
+
{:id => 2, :number=>20},
|
23
|
+
{:id => 3, :number=>30} ]
|
24
|
+
end
|
25
|
+
|
17
26
|
specify "should insert with a primary key specified" do
|
18
27
|
@ds.insert(:id=>100, :number=>20)
|
19
28
|
sqls_should_be(/INSERT INTO items \((number, id|id, number)\) VALUES \((100, 20|20, 100)\)/)
|
@@ -55,6 +64,108 @@ describe "Simple Dataset operations" do
|
|
55
64
|
end
|
56
65
|
end
|
57
66
|
|
67
|
+
describe Sequel::Dataset do
|
68
|
+
before do
|
69
|
+
INTEGRATION_DB.create_table!(:test) do
|
70
|
+
String :name
|
71
|
+
Integer :value
|
72
|
+
end
|
73
|
+
@d = INTEGRATION_DB[:test]
|
74
|
+
clear_sqls
|
75
|
+
end
|
76
|
+
after do
|
77
|
+
INTEGRATION_DB.drop_table(:test)
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "should return the correct record count" do
|
81
|
+
@d.count.should == 0
|
82
|
+
@d << {:name => 'abc', :value => 123}
|
83
|
+
@d << {:name => 'abc', :value => 456}
|
84
|
+
@d << {:name => 'def', :value => 789}
|
85
|
+
@d.count.should == 3
|
86
|
+
end
|
87
|
+
|
88
|
+
specify "should return the correct records" do
|
89
|
+
@d.to_a.should == []
|
90
|
+
@d << {:name => 'abc', :value => 123}
|
91
|
+
@d << {:name => 'abc', :value => 456}
|
92
|
+
@d << {:name => 'def', :value => 789}
|
93
|
+
|
94
|
+
@d.order(:value).to_a.should == [
|
95
|
+
{:name => 'abc', :value => 123},
|
96
|
+
{:name => 'abc', :value => 456},
|
97
|
+
{:name => 'def', :value => 789}
|
98
|
+
]
|
99
|
+
end
|
100
|
+
|
101
|
+
specify "should update records correctly" do
|
102
|
+
@d << {:name => 'abc', :value => 123}
|
103
|
+
@d << {:name => 'abc', :value => 456}
|
104
|
+
@d << {:name => 'def', :value => 789}
|
105
|
+
@d.filter(:name => 'abc').update(:value => 530)
|
106
|
+
@d[:name => 'def'][:value].should == 789
|
107
|
+
@d.filter(:value => 530).count.should == 2
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "should delete records correctly" do
|
111
|
+
@d << {:name => 'abc', :value => 123}
|
112
|
+
@d << {:name => 'abc', :value => 456}
|
113
|
+
@d << {:name => 'def', :value => 789}
|
114
|
+
@d.filter(:name => 'abc').delete
|
115
|
+
@d.count.should == 1
|
116
|
+
@d.first[:name].should == 'def'
|
117
|
+
end
|
118
|
+
|
119
|
+
specify "should be able to literalize booleans" do
|
120
|
+
proc {@d.literal(true)}.should_not raise_error
|
121
|
+
proc {@d.literal(false)}.should_not raise_error
|
122
|
+
end
|
123
|
+
|
124
|
+
specify "should correctly escape strings" do
|
125
|
+
INTEGRATION_DB.get("\\dingo".as(:a)) == "\\dingo"
|
126
|
+
end
|
127
|
+
|
128
|
+
specify "should correctly escape strings with quotes" do
|
129
|
+
INTEGRATION_DB.get("\\'dingo".as(:a)) == "\\'dingo"
|
130
|
+
end
|
131
|
+
|
132
|
+
specify "should properly escape binary data" do
|
133
|
+
INTEGRATION_DB.get("\1\2\3".to_sequel_blob.as(:a)) == "\1\2\3"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "An SQLite dataset" do
|
138
|
+
before do
|
139
|
+
INTEGRATION_DB.create_table! :items do
|
140
|
+
primary_key :id
|
141
|
+
Integer :value
|
142
|
+
end
|
143
|
+
@d = INTEGRATION_DB[:items]
|
144
|
+
@d << {:value => 123}
|
145
|
+
@d << {:value => 456}
|
146
|
+
@d << {:value => 789}
|
147
|
+
end
|
148
|
+
after do
|
149
|
+
INTEGRATION_DB.drop_table(:items)
|
150
|
+
end
|
151
|
+
|
152
|
+
specify "should correctly return avg" do
|
153
|
+
@d.avg(:value).to_i.should == 456
|
154
|
+
end
|
155
|
+
|
156
|
+
specify "should correctly return sum" do
|
157
|
+
@d.sum(:value).to_i.should == 1368
|
158
|
+
end
|
159
|
+
|
160
|
+
specify "should correctly return max" do
|
161
|
+
@d.max(:value).to_i.should == 789
|
162
|
+
end
|
163
|
+
|
164
|
+
specify "should correctly return min" do
|
165
|
+
@d.min(:value).to_i.should == 123
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
58
169
|
describe "Simple Dataset operations" do
|
59
170
|
before do
|
60
171
|
INTEGRATION_DB.create_table!(:items) do
|
@@ -154,7 +154,7 @@ describe "Association Extensions" do
|
|
154
154
|
INTEGRATION_DB.create_table!(:authorships) do
|
155
155
|
primary_key :id
|
156
156
|
foreign_key :author_id, :authors
|
157
|
-
|
157
|
+
String :name
|
158
158
|
end
|
159
159
|
class ::Authorship < Sequel::Model
|
160
160
|
many_to_one :author
|
@@ -170,26 +170,26 @@ describe "Association Extensions" do
|
|
170
170
|
|
171
171
|
it "should allow methods to be called on the dataset method" do
|
172
172
|
Authorship.count.should == 0
|
173
|
-
sqls_should_be('SELECT COUNT(*) FROM authorships LIMIT 1')
|
173
|
+
sqls_should_be('SELECT COUNT(*) AS \'count\' FROM authorships LIMIT 1')
|
174
174
|
authorship = @author.authorships_dataset.find_or_create_by_name('Bob')
|
175
175
|
sqls_should_be("SELECT * FROM authorships WHERE ((authorships.author_id = 1) AND (name = 'Bob')) LIMIT 1",
|
176
176
|
/INSERT INTO authorships \((author_id, name|name, author_id)\) VALUES \((1, 'Bob'|'Bob', 1)\)/,
|
177
177
|
"SELECT * FROM authorships WHERE (id = 1) LIMIT 1")
|
178
178
|
Authorship.count.should == 1
|
179
179
|
Authorship.first.should == authorship
|
180
|
-
sqls_should_be('SELECT COUNT(*) FROM authorships LIMIT 1', "SELECT * FROM authorships LIMIT 1")
|
180
|
+
sqls_should_be('SELECT COUNT(*) AS \'count\' FROM authorships LIMIT 1', "SELECT * FROM authorships LIMIT 1")
|
181
181
|
authorship.name.should == 'Bob'
|
182
182
|
authorship.author_id.should == @author.id
|
183
183
|
@author.authorships_dataset.find_or_create_by_name('Bob').should == authorship
|
184
184
|
sqls_should_be("SELECT * FROM authorships WHERE ((authorships.author_id = 1) AND (name = 'Bob')) LIMIT 1")
|
185
185
|
Authorship.count.should == 1
|
186
|
-
sqls_should_be('SELECT COUNT(*) FROM authorships LIMIT 1')
|
186
|
+
sqls_should_be('SELECT COUNT(*) AS \'count\' FROM authorships LIMIT 1')
|
187
187
|
authorship2 = @author.authorships_dataset.find_or_create(:name=>'Jim')
|
188
188
|
sqls_should_be("SELECT * FROM authorships WHERE ((authorships.author_id = 1) AND (name = 'Jim')) LIMIT 1",
|
189
189
|
/INSERT INTO authorships \((author_id, name|name, author_id)\) VALUES \((1, 'Jim'|'Jim', 1)\)/,
|
190
190
|
"SELECT * FROM authorships WHERE (id = 2) LIMIT 1")
|
191
191
|
Authorship.count.should == 2
|
192
|
-
sqls_should_be('SELECT COUNT(*) FROM authorships LIMIT 1')
|
192
|
+
sqls_should_be('SELECT COUNT(*) AS \'count\' FROM authorships LIMIT 1')
|
193
193
|
Authorship.order(:name).map(:name).should == ['Bob', 'Jim']
|
194
194
|
sqls_should_be('SELECT * FROM authorships ORDER BY name')
|
195
195
|
authorship2.name.should == 'Jim'
|
@@ -364,8 +364,8 @@ describe "Polymorphic Associations" do
|
|
364
364
|
INTEGRATION_DB.instance_variable_set(:@schemas, nil)
|
365
365
|
INTEGRATION_DB.create_table!(:assets) do
|
366
366
|
primary_key :id
|
367
|
-
|
368
|
-
|
367
|
+
Integer :attachable_id
|
368
|
+
String :attachable_type
|
369
369
|
end
|
370
370
|
class ::Asset < Sequel::Model
|
371
371
|
m = method(:constantize)
|
@@ -536,7 +536,7 @@ describe "many_to_one/one_to_many not referencing primary key" do
|
|
536
536
|
INTEGRATION_DB.instance_variable_set(:@schemas, nil)
|
537
537
|
INTEGRATION_DB.create_table!(:clients) do
|
538
538
|
primary_key :id
|
539
|
-
|
539
|
+
String :name
|
540
540
|
end
|
541
541
|
class ::Client < Sequel::Model
|
542
542
|
one_to_many :invoices, :reciprocal=>:client, \
|
@@ -570,7 +570,7 @@ describe "many_to_one/one_to_many not referencing primary key" do
|
|
570
570
|
|
571
571
|
INTEGRATION_DB.create_table!(:invoices) do
|
572
572
|
primary_key :id
|
573
|
-
|
573
|
+
String :client_name
|
574
574
|
end
|
575
575
|
class ::Invoice < Sequel::Model
|
576
576
|
many_to_one :client, :key=>:client_name, \
|
@@ -681,3 +681,64 @@ describe "many_to_one/one_to_many not referencing primary key" do
|
|
681
681
|
@invoice2.client_name.should == nil
|
682
682
|
end
|
683
683
|
end
|
684
|
+
|
685
|
+
describe "statistics associations" do
|
686
|
+
before do
|
687
|
+
INTEGRATION_DB.create_table!(:projects) do
|
688
|
+
primary_key :id
|
689
|
+
String :name
|
690
|
+
end
|
691
|
+
class ::Project < Sequel::Model
|
692
|
+
many_to_one :ticket_hours, :read_only=>true, :key=>:id,
|
693
|
+
:dataset=>proc{Ticket.filter(:project_id=>id).select{sum(hours).as(hours)}},
|
694
|
+
:eager_loader=>(proc do |kh, projects, a|
|
695
|
+
projects.each{|p| p.associations[:ticket_hours] = nil}
|
696
|
+
Ticket.filter(:project_id=>kh[:id].keys).
|
697
|
+
group(:project_id).
|
698
|
+
select{[project_id.as(project_id), sum(hours).as(hours)]}.
|
699
|
+
all do |t|
|
700
|
+
p = kh[:id][t.values.delete(:project_id)].first
|
701
|
+
p.associations[:ticket_hours] = t
|
702
|
+
end
|
703
|
+
end)
|
704
|
+
def ticket_hours
|
705
|
+
if s = super
|
706
|
+
s[:hours]
|
707
|
+
end
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
INTEGRATION_DB.create_table!(:tickets) do
|
712
|
+
primary_key :id
|
713
|
+
foreign_key :project_id, :projects
|
714
|
+
Integer :hours
|
715
|
+
end
|
716
|
+
class ::Ticket < Sequel::Model
|
717
|
+
many_to_one :project
|
718
|
+
end
|
719
|
+
|
720
|
+
@project1 = Project.create(:name=>'X')
|
721
|
+
@project2 = Project.create(:name=>'Y')
|
722
|
+
@ticket1 = Ticket.create(:project=>@project1, :hours=>1)
|
723
|
+
@ticket2 = Ticket.create(:project=>@project1, :hours=>10)
|
724
|
+
@ticket3 = Ticket.create(:project=>@project2, :hours=>2)
|
725
|
+
@ticket4 = Ticket.create(:project=>@project2, :hours=>20)
|
726
|
+
clear_sqls
|
727
|
+
end
|
728
|
+
after do
|
729
|
+
INTEGRATION_DB.drop_table :tickets, :projects
|
730
|
+
Object.send(:remove_const, :Project)
|
731
|
+
Object.send(:remove_const, :Ticket)
|
732
|
+
end
|
733
|
+
|
734
|
+
it "should give the correct sum of ticket hours for each project" do
|
735
|
+
@project1.ticket_hours.to_i.should == 11
|
736
|
+
@project2.ticket_hours.to_i.should == 22
|
737
|
+
end
|
738
|
+
|
739
|
+
it "should give the correct sum of ticket hours for each project when eager loading" do
|
740
|
+
p1, p2 = Project.order(:name).eager(:ticket_hours).all
|
741
|
+
p1.ticket_hours.to_i.should == 11
|
742
|
+
p2.ticket_hours.to_i.should == 22
|
743
|
+
end
|
744
|
+
end
|
@@ -76,7 +76,7 @@ describe "Prepared Statements and Bound Arguments" do
|
|
76
76
|
INTEGRATION_DB.call(:select_n, :n=>10).should == [{:id=>1, :number=>10}]
|
77
77
|
@ds.filter(:number=>@ds.ba(:$n)).prepare(:first, :select_n)
|
78
78
|
INTEGRATION_DB.call(:select_n, :n=>10).should == {:id=>1, :number=>10}
|
79
|
-
if INTEGRATION_DB.
|
79
|
+
if INTEGRATION_DB.class.adapter_scheme == :jdbc and INTEGRATION_DB.database_type == :sqlite
|
80
80
|
# Work around for open prepared statements on a table not allowing the
|
81
81
|
# dropping of a table when using SQLite over JDBC
|
82
82
|
INTEGRATION_DB.synchronize{|c| c.prepared_statements[:select_n][1].close}
|
@@ -121,7 +121,7 @@ describe "Prepared Statements and Bound Arguments" do
|
|
121
121
|
INTEGRATION_DB.call(:select_n, :n=>10).should == [@c.load(:id=>1, :number=>10)]
|
122
122
|
@c.filter(:number=>@ds.ba(:$n)).prepare(:first, :select_n)
|
123
123
|
INTEGRATION_DB.call(:select_n, :n=>10).should == @c.load(:id=>1, :number=>10)
|
124
|
-
if INTEGRATION_DB.
|
124
|
+
if INTEGRATION_DB.class.adapter_scheme == :jdbc and INTEGRATION_DB.database_type == :sqlite
|
125
125
|
# Work around for open prepared statements on a table not allowing the
|
126
126
|
# dropping of a table when using SQLite over JDBC
|
127
127
|
INTEGRATION_DB.synchronize{|c| c.prepared_statements[:select_n][1].close}
|
@@ -19,20 +19,13 @@ describe "Database schema parser" do
|
|
19
19
|
INTEGRATION_DB.identifier_output_method = :reverse
|
20
20
|
INTEGRATION_DB.identifier_input_method = :reverse
|
21
21
|
INTEGRATION_DB.default_schema = nil if INTEGRATION_DB.default_schema
|
22
|
-
INTEGRATION_DB.create_table!(:items){
|
22
|
+
INTEGRATION_DB.create_table!(:items){Integer :number}
|
23
23
|
INTEGRATION_DB.schema(:items, :reload=>true).should be_a_kind_of(Array)
|
24
24
|
INTEGRATION_DB.schema(:items, :reload=>true).first.first.should == :number
|
25
25
|
end
|
26
26
|
|
27
|
-
deprec_specify "should be a hash with table_names as symbols" do
|
28
|
-
INTEGRATION_DB.create_table!(:items){integer :number}
|
29
|
-
schema = INTEGRATION_DB.schema(nil, :reload=>true)
|
30
|
-
schema.should be_a_kind_of(Hash)
|
31
|
-
schema[:items].should_not == nil
|
32
|
-
end
|
33
|
-
|
34
27
|
specify "should not issue an sql query if the schema has been loaded unless :reload is true" do
|
35
|
-
INTEGRATION_DB.create_table!(:items){
|
28
|
+
INTEGRATION_DB.create_table!(:items){Integer :number}
|
36
29
|
INTEGRATION_DB.schema(:items, :reload=>true)
|
37
30
|
clear_sqls
|
38
31
|
INTEGRATION_DB.schema(:items)
|
@@ -42,17 +35,12 @@ describe "Database schema parser" do
|
|
42
35
|
sqls_should_be "PRAGMA table_info('items')"
|
43
36
|
end
|
44
37
|
|
45
|
-
deprec_specify "should give the same result for a single table regardless of whether schema was called for a single table" do
|
46
|
-
INTEGRATION_DB.create_table!(:items){integer :number}
|
47
|
-
INTEGRATION_DB.schema(:items, :reload=>true).should == INTEGRATION_DB.schema(nil, :reload=>true)[:items]
|
48
|
-
end
|
49
|
-
|
50
38
|
specify "should raise an error when the table doesn't exist" do
|
51
39
|
proc{INTEGRATION_DB.schema(:no_table)}.should raise_error(Sequel::Error)
|
52
40
|
end
|
53
41
|
|
54
42
|
specify "should return the schema correctly" do
|
55
|
-
INTEGRATION_DB.create_table!(:items){
|
43
|
+
INTEGRATION_DB.create_table!(:items){Integer :number}
|
56
44
|
schema = INTEGRATION_DB.schema(:items, :reload=>true)
|
57
45
|
schema.should be_a_kind_of(Array)
|
58
46
|
schema.length.should == 1
|
@@ -69,35 +57,96 @@ describe "Database schema parser" do
|
|
69
57
|
end
|
70
58
|
|
71
59
|
specify "should parse primary keys from the schema properly" do
|
72
|
-
INTEGRATION_DB.create_table!(:items){
|
60
|
+
INTEGRATION_DB.create_table!(:items){Integer :number}
|
73
61
|
INTEGRATION_DB.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == []
|
74
62
|
INTEGRATION_DB.create_table!(:items){primary_key :number}
|
75
63
|
INTEGRATION_DB.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == [:number]
|
76
|
-
INTEGRATION_DB.create_table!(:items){
|
64
|
+
INTEGRATION_DB.create_table!(:items){Integer :number1; Integer :number2; primary_key [:number1, :number2]}
|
77
65
|
INTEGRATION_DB.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == [:number1, :number2]
|
78
66
|
end
|
79
67
|
|
80
68
|
specify "should parse NULL/NOT NULL from the schema properly" do
|
81
|
-
INTEGRATION_DB.create_table!(:items){
|
69
|
+
INTEGRATION_DB.create_table!(:items){Integer :number, :null=>true}
|
82
70
|
INTEGRATION_DB.schema(:items).first.last[:allow_null].should == true
|
83
|
-
INTEGRATION_DB.create_table!(:items){
|
71
|
+
INTEGRATION_DB.create_table!(:items){Integer :number, :null=>false}
|
84
72
|
INTEGRATION_DB.schema(:items).first.last[:allow_null].should == false
|
85
73
|
end
|
86
74
|
|
87
75
|
specify "should parse defaults from the schema properly" do
|
88
|
-
INTEGRATION_DB.create_table!(:items){
|
76
|
+
INTEGRATION_DB.create_table!(:items){Integer :number}
|
89
77
|
INTEGRATION_DB.schema(:items).first.last[:default].should == nil
|
90
|
-
INTEGRATION_DB.create_table!(:items){
|
78
|
+
INTEGRATION_DB.create_table!(:items){Integer :number, :default=>0}
|
91
79
|
INTEGRATION_DB.schema(:items).first.last[:default].to_s.should == "0"
|
92
|
-
INTEGRATION_DB.create_table!(:items){
|
93
|
-
INTEGRATION_DB.schema(:items).first.last[:default].
|
80
|
+
INTEGRATION_DB.create_table!(:items){String :a, :default=>"blah"}
|
81
|
+
INTEGRATION_DB.schema(:items).first.last[:default].should include('blah')
|
82
|
+
end
|
83
|
+
|
84
|
+
specify "should parse types from the schema properly" do
|
85
|
+
INTEGRATION_DB.create_table!(:items){Integer :number}
|
86
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :integer
|
87
|
+
INTEGRATION_DB.create_table!(:items){Fixnum :number}
|
88
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :integer
|
89
|
+
INTEGRATION_DB.create_table!(:items){Bignum :number}
|
90
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :integer
|
91
|
+
INTEGRATION_DB.create_table!(:items){Float :number}
|
92
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :float
|
93
|
+
INTEGRATION_DB.create_table!(:items){BigDecimal :number}
|
94
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :decimal
|
95
|
+
INTEGRATION_DB.create_table!(:items){Numeric :number}
|
96
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :decimal
|
97
|
+
INTEGRATION_DB.create_table!(:items){String :number}
|
98
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :string
|
99
|
+
INTEGRATION_DB.create_table!(:items){Date :number}
|
100
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :date
|
101
|
+
INTEGRATION_DB.create_table!(:items){Time :number}
|
102
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :datetime
|
103
|
+
INTEGRATION_DB.create_table!(:items){DateTime :number}
|
104
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :datetime
|
105
|
+
INTEGRATION_DB.create_table!(:items){File :number}
|
106
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :blob
|
107
|
+
INTEGRATION_DB.create_table!(:items){TrueClass :number}
|
108
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :boolean
|
109
|
+
INTEGRATION_DB.create_table!(:items){FalseClass :number}
|
110
|
+
INTEGRATION_DB.schema(:items).first.last[:type].should == :boolean
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if INTEGRATION_DB.respond_to?(:indexes)
|
116
|
+
describe "Database index parsing" do
|
117
|
+
after do
|
118
|
+
INTEGRATION_DB.drop_table(:items)
|
119
|
+
end
|
120
|
+
|
121
|
+
specify "should parse indexes into a hash" do
|
122
|
+
INTEGRATION_DB.create_table!(:items){Integer :n; Integer :a}
|
123
|
+
INTEGRATION_DB.indexes(:items).should == {}
|
124
|
+
INTEGRATION_DB.add_index(:items, :n)
|
125
|
+
INTEGRATION_DB.indexes(:items).should == {:items_n_index=>{:columns=>[:n], :unique=>false}}
|
126
|
+
INTEGRATION_DB.drop_index(:items, :n)
|
127
|
+
INTEGRATION_DB.indexes(:items).should == {}
|
128
|
+
INTEGRATION_DB.add_index(:items, :n, :unique=>true, :name=>:blah_blah_index)
|
129
|
+
INTEGRATION_DB.indexes(:items).should == {:blah_blah_index=>{:columns=>[:n], :unique=>true}}
|
130
|
+
INTEGRATION_DB.add_index(:items, [:n, :a])
|
131
|
+
INTEGRATION_DB.indexes(:items).should == {:blah_blah_index=>{:columns=>[:n], :unique=>true}, :items_n_a_index=>{:columns=>[:n, :a], :unique=>false}}
|
132
|
+
INTEGRATION_DB.drop_index(:items, :n, :name=>:blah_blah_index)
|
133
|
+
INTEGRATION_DB.indexes(:items).should == {:items_n_a_index=>{:columns=>[:n, :a], :unique=>false}}
|
134
|
+
INTEGRATION_DB.drop_index(:items, [:n, :a])
|
135
|
+
INTEGRATION_DB.indexes(:items).should == {}
|
136
|
+
end
|
137
|
+
|
138
|
+
specify "should not include a primary key index" do
|
139
|
+
INTEGRATION_DB.create_table!(:items){primary_key :n}
|
140
|
+
INTEGRATION_DB.indexes(:items).should == {}
|
141
|
+
INTEGRATION_DB.create_table!(:items){Integer :n; Integer :a; primary_key [:n, :a]}
|
142
|
+
INTEGRATION_DB.indexes(:items).should == {}
|
94
143
|
end
|
95
144
|
end
|
96
145
|
end
|
97
146
|
|
98
147
|
describe "Database schema modifiers" do
|
99
148
|
before do
|
100
|
-
INTEGRATION_DB.create_table!(:items){
|
149
|
+
INTEGRATION_DB.create_table!(:items){Integer :number}
|
101
150
|
@ds = INTEGRATION_DB[:items]
|
102
151
|
@ds.insert([10])
|
103
152
|
clear_sqls
|
@@ -118,7 +167,7 @@ describe "Database schema modifiers" do
|
|
118
167
|
INTEGRATION_DB.alter_table(:items){add_column :name, :text}
|
119
168
|
INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :name]
|
120
169
|
@ds.columns!.should == [:number, :name]
|
121
|
-
unless INTEGRATION_DB.
|
170
|
+
unless INTEGRATION_DB.database_type == :sqlite
|
122
171
|
INTEGRATION_DB.alter_table(:items){add_primary_key :id}
|
123
172
|
INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :name, :id]
|
124
173
|
@ds.columns!.should == [:number, :name, :id]
|
@@ -131,8 +180,8 @@ describe "Database schema modifiers" do
|
|
131
180
|
specify "should remove columns from tables correctly" do
|
132
181
|
INTEGRATION_DB.create_table!(:items) do
|
133
182
|
primary_key :id
|
134
|
-
|
135
|
-
|
183
|
+
String :name
|
184
|
+
Integer :number
|
136
185
|
foreign_key :item_id, :items
|
137
186
|
end
|
138
187
|
@ds.insert(:number=>10)
|