sequel 3.38.0 → 3.39.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 +2 -2
- data/bin/sequel +12 -2
- data/doc/advanced_associations.rdoc +1 -1
- data/doc/association_basics.rdoc +13 -0
- data/doc/release_notes/3.39.0.txt +237 -0
- data/doc/schema_modification.rdoc +4 -4
- data/lib/sequel/adapters/jdbc/derby.rb +1 -0
- data/lib/sequel/adapters/mock.rb +5 -0
- data/lib/sequel/adapters/mysql.rb +8 -1
- data/lib/sequel/adapters/mysql2.rb +10 -3
- data/lib/sequel/adapters/postgres.rb +72 -8
- data/lib/sequel/adapters/shared/db2.rb +1 -0
- data/lib/sequel/adapters/shared/mssql.rb +57 -0
- data/lib/sequel/adapters/shared/mysql.rb +95 -19
- data/lib/sequel/adapters/shared/oracle.rb +14 -0
- data/lib/sequel/adapters/shared/postgres.rb +63 -24
- data/lib/sequel/adapters/shared/sqlite.rb +6 -9
- data/lib/sequel/connection_pool/sharded_threaded.rb +8 -3
- data/lib/sequel/connection_pool/threaded.rb +9 -4
- data/lib/sequel/database/query.rb +60 -48
- data/lib/sequel/database/schema_generator.rb +13 -6
- data/lib/sequel/database/schema_methods.rb +65 -12
- data/lib/sequel/dataset/actions.rb +22 -4
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/graph.rb +2 -3
- data/lib/sequel/dataset/misc.rb +2 -2
- data/lib/sequel/dataset/query.rb +0 -2
- data/lib/sequel/dataset/sql.rb +33 -12
- data/lib/sequel/extensions/constraint_validations.rb +451 -0
- data/lib/sequel/extensions/eval_inspect.rb +17 -2
- data/lib/sequel/extensions/pg_array_ops.rb +15 -5
- data/lib/sequel/extensions/pg_interval.rb +2 -2
- data/lib/sequel/extensions/pg_row_ops.rb +18 -0
- data/lib/sequel/extensions/schema_dumper.rb +3 -11
- data/lib/sequel/model/associations.rb +3 -2
- data/lib/sequel/model/base.rb +57 -13
- data/lib/sequel/model/exceptions.rb +20 -2
- data/lib/sequel/plugins/constraint_validations.rb +198 -0
- data/lib/sequel/plugins/defaults_setter.rb +15 -1
- data/lib/sequel/plugins/dirty.rb +2 -2
- data/lib/sequel/plugins/identity_map.rb +12 -8
- data/lib/sequel/plugins/subclasses.rb +19 -1
- data/lib/sequel/plugins/tree.rb +3 -3
- data/lib/sequel/plugins/validation_helpers.rb +24 -4
- data/lib/sequel/sql.rb +64 -24
- data/lib/sequel/timezones.rb +10 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +26 -25
- data/spec/adapters/mysql_spec.rb +57 -23
- data/spec/adapters/oracle_spec.rb +34 -49
- data/spec/adapters/postgres_spec.rb +226 -128
- data/spec/adapters/sqlite_spec.rb +50 -49
- data/spec/core/connection_pool_spec.rb +22 -0
- data/spec/core/database_spec.rb +53 -47
- data/spec/core/dataset_spec.rb +36 -32
- data/spec/core/expression_filters_spec.rb +14 -2
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/object_graph_spec.rb +0 -13
- data/spec/core/schema_spec.rb +64 -5
- data/spec/core_extensions_spec.rb +1 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
- data/spec/extensions/constraint_validations_spec.rb +316 -0
- data/spec/extensions/defaults_setter_spec.rb +24 -0
- data/spec/extensions/eval_inspect_spec.rb +9 -0
- data/spec/extensions/identity_map_spec.rb +11 -2
- data/spec/extensions/pg_array_ops_spec.rb +9 -0
- data/spec/extensions/pg_row_ops_spec.rb +11 -1
- data/spec/extensions/pg_row_plugin_spec.rb +4 -0
- data/spec/extensions/schema_dumper_spec.rb +8 -5
- data/spec/extensions/subclasses_spec.rb +14 -0
- data/spec/extensions/validation_helpers_spec.rb +15 -2
- data/spec/integration/dataset_test.rb +75 -1
- data/spec/integration/plugin_test.rb +146 -0
- data/spec/integration/schema_test.rb +34 -0
- data/spec/model/dataset_methods_spec.rb +38 -0
- data/spec/model/hooks_spec.rb +6 -0
- data/spec/model/validations_spec.rb +27 -2
- metadata +8 -2
@@ -18,6 +18,7 @@ describe "An SQLite database" do
|
|
18
18
|
@fk = @db.foreign_keys
|
19
19
|
end
|
20
20
|
after do
|
21
|
+
@db.drop_table?(:fk)
|
21
22
|
@db.foreign_keys = @fk
|
22
23
|
@db.case_sensitive_like = true
|
23
24
|
Sequel.datetime_class = Time
|
@@ -74,16 +75,14 @@ describe "An SQLite database" do
|
|
74
75
|
@db.foreign_keys = false
|
75
76
|
end
|
76
77
|
|
77
|
-
if
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
86
|
-
end
|
78
|
+
specify "should enforce foreign key integrity if foreign_keys pragma is set" do
|
79
|
+
@db.foreign_keys = true
|
80
|
+
@db.create_table!(:fk){primary_key :id; foreign_key :parent_id, :fk}
|
81
|
+
@db[:fk].insert(1, nil)
|
82
|
+
@db[:fk].insert(2, 1)
|
83
|
+
@db[:fk].insert(3, 3)
|
84
|
+
proc{@db[:fk].insert(4, 5)}.should raise_error(Sequel::Error)
|
85
|
+
end if SQLITE_DB.sqlite_version >= 30619
|
87
86
|
|
88
87
|
specify "should not enforce foreign key integrity if foreign_keys pragma is unset" do
|
89
88
|
@db.foreign_keys = false
|
@@ -93,24 +92,22 @@ describe "An SQLite database" do
|
|
93
92
|
end
|
94
93
|
|
95
94
|
specify "should support a use_timestamp_timezones setting" do
|
96
|
-
@db.create_table!(:
|
97
|
-
@db[:
|
98
|
-
@db[:
|
95
|
+
@db.create_table!(:fk){Time :time}
|
96
|
+
@db[:fk].insert(Time.now)
|
97
|
+
@db[:fk].get(Sequel.cast(:time, String)).should =~ /[-+]\d\d\d\d\z/
|
99
98
|
@db.use_timestamp_timezones = false
|
100
|
-
@db[:
|
101
|
-
@db[:
|
102
|
-
@db[:
|
99
|
+
@db[:fk].delete
|
100
|
+
@db[:fk].insert(Time.now)
|
101
|
+
@db[:fk].get(Sequel.cast(:time, String)).should_not =~ /[-+]\d\d\d\d\z/
|
103
102
|
@db.use_timestamp_timezones = true
|
104
103
|
end
|
105
104
|
|
106
105
|
specify "should provide a list of existing tables" do
|
107
|
-
@db.drop_table?(:
|
106
|
+
@db.drop_table?(:fk)
|
108
107
|
@db.tables.should be_a_kind_of(Array)
|
109
|
-
@db.tables.should_not include(:
|
110
|
-
@db.create_table! :
|
111
|
-
|
112
|
-
end
|
113
|
-
@db.tables.should include(:testing)
|
108
|
+
@db.tables.should_not include(:fk)
|
109
|
+
@db.create_table!(:fk){String :name}
|
110
|
+
@db.tables.should include(:fk)
|
114
111
|
end
|
115
112
|
|
116
113
|
specify "should support getting and setting the synchronous pragma" do
|
@@ -136,23 +133,23 @@ describe "An SQLite database" do
|
|
136
133
|
end
|
137
134
|
|
138
135
|
cspecify "should support timestamps and datetimes and respect datetime_class", :do, :jdbc, :amalgalite, :swift do
|
139
|
-
@db.create_table!(:
|
136
|
+
@db.create_table!(:fk){timestamp :t; datetime :d}
|
140
137
|
t1 = Time.at(1)
|
141
|
-
@db[:
|
142
|
-
@db[:
|
143
|
-
@db[:
|
138
|
+
@db[:fk] << {:t => t1, :d => t1}
|
139
|
+
@db[:fk].map(:t).should == [t1]
|
140
|
+
@db[:fk].map(:d).should == [t1]
|
144
141
|
Sequel.datetime_class = DateTime
|
145
142
|
t2 = Sequel.string_to_datetime(t1.iso8601)
|
146
|
-
@db[:
|
147
|
-
@db[:
|
143
|
+
@db[:fk].map(:t).should == [t2]
|
144
|
+
@db[:fk].map(:d).should == [t2]
|
148
145
|
end
|
149
146
|
|
150
147
|
specify "should support sequential primary keys" do
|
151
|
-
@db.create_table!(:
|
152
|
-
@db[:
|
153
|
-
@db[:
|
154
|
-
@db[:
|
155
|
-
@db[:
|
148
|
+
@db.create_table!(:fk) {primary_key :id; text :name}
|
149
|
+
@db[:fk] << {:name => 'abc'}
|
150
|
+
@db[:fk] << {:name => 'def'}
|
151
|
+
@db[:fk] << {:name => 'ghi'}
|
152
|
+
@db[:fk].order(:name).all.should == [
|
156
153
|
{:id => 1, :name => 'abc'},
|
157
154
|
{:id => 2, :name => 'def'},
|
158
155
|
{:id => 3, :name => 'ghi'}
|
@@ -160,8 +157,21 @@ describe "An SQLite database" do
|
|
160
157
|
end
|
161
158
|
|
162
159
|
specify "should correctly parse the schema" do
|
163
|
-
@db.create_table!(:
|
164
|
-
@db.schema(:
|
160
|
+
@db.create_table!(:fk) {timestamp :t}
|
161
|
+
@db.schema(:fk, :reload=>true).should == [[:t, {:type=>:datetime, :allow_null=>true, :default=>nil, :ruby_default=>nil, :db_type=>"timestamp", :primary_key=>false}]]
|
162
|
+
end
|
163
|
+
|
164
|
+
specify "should handle and return BigDecimal values for numeric columns" do
|
165
|
+
SQLITE_DB.create_table!(:fk){numeric :d}
|
166
|
+
d = SQLITE_DB[:fk]
|
167
|
+
d.insert(:d=>BigDecimal.new('80.0'))
|
168
|
+
d.insert(:d=>BigDecimal.new('NaN'))
|
169
|
+
d.insert(:d=>BigDecimal.new('Infinity'))
|
170
|
+
d.insert(:d=>BigDecimal.new('-Infinity'))
|
171
|
+
ds = d.all
|
172
|
+
ds.shift.should == {:d=>BigDecimal.new('80.0')}
|
173
|
+
ds.map{|x| x[:d].to_s}.should == %w'NaN Infinity -Infinity'
|
174
|
+
SQLITE_DB
|
165
175
|
end
|
166
176
|
end
|
167
177
|
|
@@ -265,20 +275,6 @@ describe "An SQLite dataset" do
|
|
265
275
|
end
|
266
276
|
end
|
267
277
|
|
268
|
-
describe "An SQLite numeric column" do
|
269
|
-
specify "should handle and return BigDecimal values" do
|
270
|
-
SQLITE_DB.create_table!(:d){numeric :d}
|
271
|
-
d = SQLITE_DB[:d]
|
272
|
-
d.insert(:d=>BigDecimal.new('80.0'))
|
273
|
-
d.insert(:d=>BigDecimal.new('NaN'))
|
274
|
-
d.insert(:d=>BigDecimal.new('Infinity'))
|
275
|
-
d.insert(:d=>BigDecimal.new('-Infinity'))
|
276
|
-
ds = d.all
|
277
|
-
ds.shift.should == {:d=>BigDecimal.new('80.0')}
|
278
|
-
ds.map{|x| x[:d].to_s}.should == %w'NaN Infinity -Infinity'
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
278
|
describe "An SQLite dataset AS clause" do
|
283
279
|
specify "should use a string literal for :col___alias" do
|
284
280
|
SQLITE_DB.literal(:c___a).should == "`c` AS 'a'"
|
@@ -407,6 +403,9 @@ describe "A SQLite database" do
|
|
407
403
|
integer :value
|
408
404
|
end
|
409
405
|
end
|
406
|
+
after do
|
407
|
+
@db.drop_table?(:test2)
|
408
|
+
end
|
410
409
|
|
411
410
|
specify "should support add_column operations" do
|
412
411
|
@db.add_column :test2, :xyz, :text
|
@@ -533,6 +532,7 @@ describe "A SQLite database" do
|
|
533
532
|
@db.from(table_name).all.should == [{:"s s"=>1}]
|
534
533
|
@db.rename_column table_name, :"s s", :"t t"
|
535
534
|
@db.from(table_name).all.should == [{:"t t"=>1}]
|
535
|
+
@db.drop_table?(table_name)
|
536
536
|
end
|
537
537
|
|
538
538
|
specify "should choose a temporary table name that isn't already used when dropping or renaming columns" do
|
@@ -574,6 +574,7 @@ describe "A SQLite database" do
|
|
574
574
|
@db[:test3_backup1].columns.should == [:k]
|
575
575
|
@db[:test3_backup2].columns.should == [:l]
|
576
576
|
@db.loggers.delete(l)
|
577
|
+
@db.drop_table?(:test3, :test3_backup0, :test3_backup1, :test3_backup2)
|
577
578
|
end
|
578
579
|
|
579
580
|
specify "should support add_index" do
|
@@ -365,6 +365,28 @@ shared_examples_for "A threaded connection pool" do
|
|
365
365
|
Thread.new{@pool.hold{|cc2| cc2.should == c}}
|
366
366
|
end
|
367
367
|
end
|
368
|
+
|
369
|
+
specify "should not store connections if :connection_handling=>:disconnect" do
|
370
|
+
@pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:connection_handling=>:disconnect)){@invoked_count += 1}
|
371
|
+
d = []
|
372
|
+
@pool.disconnection_proc = proc{|c| d << c}
|
373
|
+
c = @pool.hold do |cc|
|
374
|
+
cc.should == 1
|
375
|
+
Thread.new{@pool.hold{|cc2| cc2.should == 2}}.join
|
376
|
+
d.should == [2]
|
377
|
+
@pool.hold{|cc3| cc3.should == 1}
|
378
|
+
end
|
379
|
+
@pool.size.should == 0
|
380
|
+
d.should == [2, 1]
|
381
|
+
|
382
|
+
@pool.hold{|cc| cc.should == 3}
|
383
|
+
@pool.size.should == 0
|
384
|
+
d.should == [2, 1, 3]
|
385
|
+
|
386
|
+
@pool.hold{|cc| cc.should == 4}
|
387
|
+
@pool.size.should == 0
|
388
|
+
d.should == [2, 1, 3, 4]
|
389
|
+
end
|
368
390
|
end
|
369
391
|
|
370
392
|
describe "Threaded Unsharded Connection Pool" do
|
data/spec/core/database_spec.rb
CHANGED
@@ -1726,16 +1726,17 @@ describe "Database#typecast_value" do
|
|
1726
1726
|
end
|
1727
1727
|
|
1728
1728
|
specify "should typecast datetime values to Sequel.datetime_class with correct timezone handling" do
|
1729
|
-
t = Time.utc(2011, 1, 2, 3, 4, 5) # UTC Time
|
1730
|
-
t2 = Time.mktime(2011, 1, 2, 3, 4, 5) # Local Time
|
1731
|
-
t3 = Time.utc(2011, 1, 2, 3, 4, 5) - (t - t2) # Local Time in UTC Time
|
1732
|
-
t4 = Time.mktime(2011, 1, 2, 3, 4, 5) + (t - t2) # UTC Time in Local Time
|
1733
|
-
|
1729
|
+
t = Time.utc(2011, 1, 2, 3, 4, 5, 500000) # UTC Time
|
1730
|
+
t2 = Time.mktime(2011, 1, 2, 3, 4, 5, 500000) # Local Time
|
1731
|
+
t3 = Time.utc(2011, 1, 2, 3, 4, 5, 500000) - (t - t2) # Local Time in UTC Time
|
1732
|
+
t4 = Time.mktime(2011, 1, 2, 3, 4, 5, 500000) + (t - t2) # UTC Time in Local Time
|
1733
|
+
secs = defined?(Rational) ? Rational(11, 2) : 5.5
|
1734
1734
|
r1 = defined?(Rational) ? Rational(t2.utc_offset, 86400) : t2.utc_offset/86400.0
|
1735
1735
|
r2 = defined?(Rational) ? Rational((t - t2).to_i, 86400) : (t - t2).to_i/86400.0
|
1736
|
-
|
1737
|
-
|
1738
|
-
|
1736
|
+
dt = DateTime.civil(2011, 1, 2, 3, 4, secs)
|
1737
|
+
dt2 = DateTime.civil(2011, 1, 2, 3, 4, secs, r1)
|
1738
|
+
dt3 = DateTime.civil(2011, 1, 2, 3, 4, secs) - r2
|
1739
|
+
dt4 = DateTime.civil(2011, 1, 2, 3, 4, secs, r1) + r2
|
1739
1740
|
|
1740
1741
|
t.should == t4
|
1741
1742
|
t2.should == t3
|
@@ -1751,25 +1752,26 @@ describe "Database#typecast_value" do
|
|
1751
1752
|
v.offset.should == o.offset
|
1752
1753
|
end
|
1753
1754
|
end
|
1755
|
+
@db.extend_datasets(Module.new{def supports_timestamp_timezones?; true; end})
|
1754
1756
|
begin
|
1755
1757
|
@db.typecast_value(:datetime, dt).should == t
|
1756
1758
|
@db.typecast_value(:datetime, dt2).should == t2
|
1757
1759
|
@db.typecast_value(:datetime, t).should == t
|
1758
1760
|
@db.typecast_value(:datetime, t2).should == t2
|
1759
|
-
@db.typecast_value(:datetime, dt
|
1760
|
-
@db.typecast_value(:datetime, dt.strftime('%F %T')).should == t2
|
1761
|
+
@db.typecast_value(:datetime, @db.literal(dt)[1...-1]).should == t
|
1762
|
+
@db.typecast_value(:datetime, dt.strftime('%F %T.%N')).should == t2
|
1761
1763
|
@db.typecast_value(:datetime, Date.civil(2011, 1, 2)).should == Time.mktime(2011, 1, 2, 0, 0, 0)
|
1762
|
-
@db.typecast_value(:datetime, :year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec).should == t2
|
1764
|
+
@db.typecast_value(:datetime, :year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000).should == t2
|
1763
1765
|
|
1764
1766
|
Sequel.datetime_class = DateTime
|
1765
1767
|
@db.typecast_value(:datetime, dt).should == dt
|
1766
1768
|
@db.typecast_value(:datetime, dt2).should == dt2
|
1767
1769
|
@db.typecast_value(:datetime, t).should == dt
|
1768
1770
|
@db.typecast_value(:datetime, t2).should == dt2
|
1769
|
-
@db.typecast_value(:datetime, dt
|
1770
|
-
@db.typecast_value(:datetime, dt.strftime('%F %T')).should == dt
|
1771
|
+
@db.typecast_value(:datetime, @db.literal(dt)[1...-1]).should == dt
|
1772
|
+
@db.typecast_value(:datetime, dt.strftime('%F %T.%N')).should == dt
|
1771
1773
|
@db.typecast_value(:datetime, Date.civil(2011, 1, 2)).should == DateTime.civil(2011, 1, 2, 0, 0, 0)
|
1772
|
-
@db.typecast_value(:datetime, :year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec).should == dt
|
1774
|
+
@db.typecast_value(:datetime, :year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000).should == dt
|
1773
1775
|
|
1774
1776
|
Sequel.application_timezone = :utc
|
1775
1777
|
Sequel.typecast_timezone = :local
|
@@ -1778,20 +1780,20 @@ describe "Database#typecast_value" do
|
|
1778
1780
|
check[dt2, t3]
|
1779
1781
|
check[t, t]
|
1780
1782
|
check[t2, t3]
|
1781
|
-
check[dt
|
1782
|
-
check[dt.strftime('%F %T'), t3]
|
1783
|
+
check[@db.literal(dt)[1...-1], t]
|
1784
|
+
check[dt.strftime('%F %T.%N'), t3]
|
1783
1785
|
check[Date.civil(2011, 1, 2), Time.utc(2011, 1, 2, 0, 0, 0)]
|
1784
|
-
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, t3]
|
1786
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t3]
|
1785
1787
|
|
1786
1788
|
Sequel.datetime_class = DateTime
|
1787
1789
|
check[dt, dt]
|
1788
1790
|
check[dt2, dt3]
|
1789
1791
|
check[t, dt]
|
1790
1792
|
check[t2, dt3]
|
1791
|
-
check[dt
|
1792
|
-
check[dt.strftime('%F %T'), dt3]
|
1793
|
+
check[@db.literal(dt)[1...-1], dt]
|
1794
|
+
check[dt.strftime('%F %T.%N'), dt3]
|
1793
1795
|
check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0)]
|
1794
|
-
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, dt3]
|
1796
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt3]
|
1795
1797
|
|
1796
1798
|
Sequel.typecast_timezone = :utc
|
1797
1799
|
Sequel.datetime_class = Time
|
@@ -1799,20 +1801,20 @@ describe "Database#typecast_value" do
|
|
1799
1801
|
check[dt2, t3]
|
1800
1802
|
check[t, t]
|
1801
1803
|
check[t2, t3]
|
1802
|
-
check[dt
|
1803
|
-
check[dt.strftime('%F %T'), t]
|
1804
|
+
check[@db.literal(dt)[1...-1], t]
|
1805
|
+
check[dt.strftime('%F %T.%N'), t]
|
1804
1806
|
check[Date.civil(2011, 1, 2), Time.utc(2011, 1, 2, 0, 0, 0)]
|
1805
|
-
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, t]
|
1807
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t]
|
1806
1808
|
|
1807
1809
|
Sequel.datetime_class = DateTime
|
1808
1810
|
check[dt, dt]
|
1809
1811
|
check[dt2, dt3]
|
1810
1812
|
check[t, dt]
|
1811
1813
|
check[t2, dt3]
|
1812
|
-
check[dt
|
1813
|
-
check[dt.strftime('%F %T'), dt]
|
1814
|
+
check[@db.literal(dt)[1...-1], dt]
|
1815
|
+
check[dt.strftime('%F %T.%N'), dt]
|
1814
1816
|
check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0)]
|
1815
|
-
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, dt]
|
1817
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt]
|
1816
1818
|
|
1817
1819
|
Sequel.application_timezone = :local
|
1818
1820
|
Sequel.datetime_class = Time
|
@@ -1820,20 +1822,20 @@ describe "Database#typecast_value" do
|
|
1820
1822
|
check[dt2, t2]
|
1821
1823
|
check[t, t4]
|
1822
1824
|
check[t2, t2]
|
1823
|
-
check[dt
|
1824
|
-
check[dt.strftime('%F %T'), t4]
|
1825
|
+
check[@db.literal(dt)[1...-1], t4]
|
1826
|
+
check[dt.strftime('%F %T.%N'), t4]
|
1825
1827
|
check[Date.civil(2011, 1, 2), Time.local(2011, 1, 2, 0, 0, 0)]
|
1826
|
-
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, t4]
|
1828
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t4]
|
1827
1829
|
|
1828
1830
|
Sequel.datetime_class = DateTime
|
1829
1831
|
check[dt, dt4]
|
1830
1832
|
check[dt2, dt2]
|
1831
1833
|
check[t, dt4]
|
1832
1834
|
check[t2, dt2]
|
1833
|
-
check[dt
|
1834
|
-
check[dt.strftime('%F %T'), dt4]
|
1835
|
+
check[@db.literal(dt)[1...-1], dt4]
|
1836
|
+
check[dt.strftime('%F %T.%N'), dt4]
|
1835
1837
|
check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0, r1)]
|
1836
|
-
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, dt4]
|
1838
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt4]
|
1837
1839
|
|
1838
1840
|
Sequel.typecast_timezone = :local
|
1839
1841
|
Sequel.datetime_class = Time
|
@@ -1841,20 +1843,20 @@ describe "Database#typecast_value" do
|
|
1841
1843
|
check[dt2, t2]
|
1842
1844
|
check[t, t4]
|
1843
1845
|
check[t2, t2]
|
1844
|
-
check[dt
|
1845
|
-
check[dt.strftime('%F %T'), t2]
|
1846
|
+
check[@db.literal(dt)[1...-1], t4]
|
1847
|
+
check[dt.strftime('%F %T.%N'), t2]
|
1846
1848
|
check[Date.civil(2011, 1, 2), Time.local(2011, 1, 2, 0, 0, 0)]
|
1847
|
-
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, t2]
|
1849
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t2]
|
1848
1850
|
|
1849
1851
|
Sequel.datetime_class = DateTime
|
1850
1852
|
check[dt, dt4]
|
1851
1853
|
check[dt2, dt2]
|
1852
1854
|
check[t, dt4]
|
1853
1855
|
check[t2, dt2]
|
1854
|
-
check[dt
|
1855
|
-
check[dt.strftime('%F %T'), dt2]
|
1856
|
+
check[@db.literal(dt)[1...-1], dt4]
|
1857
|
+
check[dt.strftime('%F %T.%N'), dt2]
|
1856
1858
|
check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0, r1)]
|
1857
|
-
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, dt2]
|
1859
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt2]
|
1858
1860
|
|
1859
1861
|
ensure
|
1860
1862
|
Sequel.default_timezone = nil
|
@@ -2063,8 +2065,7 @@ end
|
|
2063
2065
|
describe "Database#column_schema_to_ruby_default" do
|
2064
2066
|
specify "should handle converting many default formats" do
|
2065
2067
|
db = Sequel::Database.new
|
2066
|
-
|
2067
|
-
p = lambda{|d,t| m.call(d,t)}
|
2068
|
+
p = lambda{|d,t| db.send(:column_schema_to_ruby_default, d, t)}
|
2068
2069
|
p[nil, :integer].should be_nil
|
2069
2070
|
p['1', :integer].should == 1
|
2070
2071
|
p['-1', :integer].should == -1
|
@@ -2085,14 +2086,20 @@ describe "Database#column_schema_to_ruby_default" do
|
|
2085
2086
|
p["'\\a''b'", :string].should == "\\a'b"
|
2086
2087
|
p["'NULL'", :string].should == "NULL"
|
2087
2088
|
p["'2009-10-29'", :date].should == Date.new(2009,10,29)
|
2088
|
-
p["CURRENT_TIMESTAMP", :date].should
|
2089
|
-
p["
|
2089
|
+
p["CURRENT_TIMESTAMP", :date].should == Sequel::CURRENT_DATE
|
2090
|
+
p["CURRENT_DATE", :date].should == Sequel::CURRENT_DATE
|
2091
|
+
p["now()", :date].should == Sequel::CURRENT_DATE
|
2092
|
+
p["getdate()", :date].should == Sequel::CURRENT_DATE
|
2093
|
+
p["CURRENT_TIMESTAMP", :datetime].should == Sequel::CURRENT_TIMESTAMP
|
2094
|
+
p["CURRENT_DATE", :datetime].should == Sequel::CURRENT_TIMESTAMP
|
2095
|
+
p["now()", :datetime].should == Sequel::CURRENT_TIMESTAMP
|
2096
|
+
p["getdate()", :datetime].should == Sequel::CURRENT_TIMESTAMP
|
2090
2097
|
p["'2009-10-29T10:20:30-07:00'", :datetime].should == DateTime.parse('2009-10-29T10:20:30-07:00')
|
2091
2098
|
p["'2009-10-29 10:20:30'", :datetime].should == DateTime.parse('2009-10-29 10:20:30')
|
2092
2099
|
p["'10:20:30'", :time].should == Time.parse('10:20:30')
|
2093
2100
|
p["NaN", :float].should be_nil
|
2094
2101
|
|
2095
|
-
db.
|
2102
|
+
db = Sequel.mock(:host=>'postgres')
|
2096
2103
|
p["''::text", :string].should == ""
|
2097
2104
|
p["'\\a''b'::character varying", :string].should == "\\a'b"
|
2098
2105
|
p["'a'::bpchar", :string].should == "a"
|
@@ -2105,7 +2112,7 @@ describe "Database#column_schema_to_ruby_default" do
|
|
2105
2112
|
p["'2009-10-29 10:20:30.241343'::timestamp without time zone", :datetime].should == DateTime.parse('2009-10-29 10:20:30.241343')
|
2106
2113
|
p["'10:20:30'::time without time zone", :time].should == Time.parse('10:20:30')
|
2107
2114
|
|
2108
|
-
db.
|
2115
|
+
db = Sequel.mock(:host=>'mysql')
|
2109
2116
|
p["\\a'b", :string].should == "\\a'b"
|
2110
2117
|
p["a", :string].should == "a"
|
2111
2118
|
p["NULL", :string].should == "NULL"
|
@@ -2114,11 +2121,10 @@ describe "Database#column_schema_to_ruby_default" do
|
|
2114
2121
|
p["2009-10-29", :date].should == Date.new(2009,10,29)
|
2115
2122
|
p["2009-10-29 10:20:30", :datetime].should == DateTime.parse('2009-10-29 10:20:30')
|
2116
2123
|
p["10:20:30", :time].should == Time.parse('10:20:30')
|
2117
|
-
p["CURRENT_DATE", :date].should be_nil
|
2118
|
-
p["CURRENT_TIMESTAMP", :datetime].should be_nil
|
2119
2124
|
p["a", :enum].should == "a"
|
2125
|
+
p["a,b", :set].should == "a,b"
|
2120
2126
|
|
2121
|
-
db.
|
2127
|
+
db = Sequel.mock(:host=>'mssql')
|
2122
2128
|
p["(N'a')", :string].should == "a"
|
2123
2129
|
p["((-12))", :integer].should == -12
|
2124
2130
|
p["((12.1))", :float].should == 12.1
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -241,16 +241,6 @@ describe "A simple dataset" do
|
|
241
241
|
should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
|
242
242
|
end
|
243
243
|
|
244
|
-
specify "should format an insert statement with an object that respond_to? :values" do
|
245
|
-
v = Object.new
|
246
|
-
def v.values; {:a => 1}; end
|
247
|
-
|
248
|
-
@dataset.insert_sql(v).should == "INSERT INTO test (a) VALUES (1)"
|
249
|
-
|
250
|
-
def v.values; {}; end
|
251
|
-
@dataset.insert_sql(v).should == "INSERT INTO test DEFAULT VALUES"
|
252
|
-
end
|
253
|
-
|
254
244
|
specify "should format an insert statement with an arbitrary value" do
|
255
245
|
@dataset.insert_sql(123).should == "INSERT INTO test VALUES (123)"
|
256
246
|
end
|
@@ -338,7 +328,7 @@ end
|
|
338
328
|
|
339
329
|
describe "Dataset#exists" do
|
340
330
|
before do
|
341
|
-
@ds1 = Sequel
|
331
|
+
@ds1 = Sequel.mock[:test]
|
342
332
|
@ds2 = @ds1.filter(Sequel.expr(:price) < 100)
|
343
333
|
@ds3 = @ds1.filter(Sequel.expr(:price) > 50)
|
344
334
|
end
|
@@ -358,7 +348,7 @@ end
|
|
358
348
|
|
359
349
|
describe "Dataset#where" do
|
360
350
|
before do
|
361
|
-
@dataset = Sequel
|
351
|
+
@dataset = Sequel.mock[:test]
|
362
352
|
@d1 = @dataset.where(:region => 'Asia')
|
363
353
|
@d2 = @dataset.where('region = ?', 'Asia')
|
364
354
|
@d3 = @dataset.where("a = 1")
|
@@ -1836,6 +1826,25 @@ describe "Dataset#count" do
|
|
1836
1826
|
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LIMIT 1']
|
1837
1827
|
end
|
1838
1828
|
|
1829
|
+
specify "should accept an argument" do
|
1830
|
+
@dataset.count(:foo).should == 1
|
1831
|
+
@db.sqls.should == ['SELECT COUNT(foo) AS count FROM test LIMIT 1']
|
1832
|
+
end
|
1833
|
+
|
1834
|
+
specify "should work with a nil argument" do
|
1835
|
+
@dataset.count(nil).should == 1
|
1836
|
+
@db.sqls.should == ['SELECT COUNT(NULL) AS count FROM test LIMIT 1']
|
1837
|
+
end
|
1838
|
+
|
1839
|
+
specify "should accept a virtual row block" do
|
1840
|
+
@dataset.count{foo(bar)}.should == 1
|
1841
|
+
@db.sqls.should == ['SELECT COUNT(foo(bar)) AS count FROM test LIMIT 1']
|
1842
|
+
end
|
1843
|
+
|
1844
|
+
specify "should raise an Error if given an argument and a block" do
|
1845
|
+
proc{@dataset.count(:foo){foo(bar)}}.should raise_error(Sequel::Error)
|
1846
|
+
end
|
1847
|
+
|
1839
1848
|
specify "should include the where clause if it's there" do
|
1840
1849
|
@dataset.filter(Sequel.expr(:abc) < 30).count.should == 1
|
1841
1850
|
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test WHERE (abc < 30) LIMIT 1']
|
@@ -2159,12 +2168,6 @@ describe "Dataset#join_table" do
|
|
2159
2168
|
'RIGHT OUTER JOIN (SELECT * FROM attributes WHERE (name = \'blah\')) AS "t3" ON ("t3"."attribute_id" = "t2"."id")'
|
2160
2169
|
end
|
2161
2170
|
|
2162
|
-
specify "should support joining objects that respond to :table_name" do
|
2163
|
-
ds = Object.new
|
2164
|
-
def ds.table_name; :categories end
|
2165
|
-
@d.join(ds, :item_id => :id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
|
2166
|
-
end
|
2167
|
-
|
2168
2171
|
specify "should support using an SQL String as the join condition" do
|
2169
2172
|
@d.join(:categories, "c.item_id = items.id", :c).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
2170
2173
|
end
|
@@ -2323,6 +2326,13 @@ describe "Dataset#insert_multiple" do
|
|
2323
2326
|
specify "should return array of inserted ids" do
|
2324
2327
|
@ds.insert_multiple(['aa', 5, 3, {:a => 2}]).should == [2, 3, 4, 5]
|
2325
2328
|
end
|
2329
|
+
|
2330
|
+
specify "should work exactly like in metioned in the example" do
|
2331
|
+
@ds.insert_multiple([{:x=>1}, {:x=>2}]){|row| row[:y] = row[:x] * 2 ; row }
|
2332
|
+
sqls = @db.sqls
|
2333
|
+
["INSERT INTO items (x, y) VALUES (1, 2)", "INSERT INTO items (y, x) VALUES (2, 1)"].should include(sqls[0])
|
2334
|
+
["INSERT INTO items (x, y) VALUES (2, 4)", "INSERT INTO items (y, x) VALUES (4, 2)"].should include(sqls[1])
|
2335
|
+
end
|
2326
2336
|
end
|
2327
2337
|
|
2328
2338
|
describe "Dataset aggregate methods" do
|
@@ -3055,18 +3065,6 @@ describe "Dataset#insert_sql" do
|
|
3055
3065
|
specify "should accept an array of columns and an LiteralString" do
|
3056
3066
|
@ds.insert_sql([:a, :b, :c], Sequel.lit('VALUES (1, 2, 3)')).should == "INSERT INTO items (a, b, c) VALUES (1, 2, 3)"
|
3057
3067
|
end
|
3058
|
-
|
3059
|
-
specify "should accept an object that responds to values and returns a hash by using that hash as the columns and values" do
|
3060
|
-
o = Object.new
|
3061
|
-
def o.values; {:c=>'d'}; end
|
3062
|
-
@ds.insert_sql(o).should == "INSERT INTO items (c) VALUES ('d')"
|
3063
|
-
end
|
3064
|
-
|
3065
|
-
specify "should accept an object that responds to values and returns something other than a hash by using the object itself as a single value" do
|
3066
|
-
o = Date.civil(2000, 1, 1)
|
3067
|
-
def o.values; self; end
|
3068
|
-
@ds.insert_sql(o).should == "INSERT INTO items VALUES ('2000-01-01')"
|
3069
|
-
end
|
3070
3068
|
end
|
3071
3069
|
|
3072
3070
|
describe "Dataset#inspect" do
|
@@ -3108,7 +3106,7 @@ end
|
|
3108
3106
|
|
3109
3107
|
describe "Dataset#grep" do
|
3110
3108
|
before do
|
3111
|
-
@ds = Sequel
|
3109
|
+
@ds = Sequel.mock[:posts]
|
3112
3110
|
end
|
3113
3111
|
|
3114
3112
|
specify "should format a SQL filter correctly" do
|
@@ -3155,7 +3153,13 @@ describe "Dataset#grep" do
|
|
3155
3153
|
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE ((title ILIKE 'abc') AND (body ILIKE 'abc') AND (title ILIKE 'def') AND (body ILIKE 'def'))"
|
3156
3154
|
end
|
3157
3155
|
|
3158
|
-
specify "should support regexps
|
3156
|
+
specify "should not support regexps if the database doesn't supports it" do
|
3157
|
+
proc{@ds.grep(:title, /ruby/).sql}.should raise_error(Sequel::InvalidOperation)
|
3158
|
+
proc{@ds.grep(:title, [/^ruby/, 'ruby']).sql}.should raise_error(Sequel::InvalidOperation)
|
3159
|
+
end
|
3160
|
+
|
3161
|
+
specify "should support regexps if the database supports it" do
|
3162
|
+
def @ds.supports_regexp?; true end
|
3159
3163
|
@ds.grep(:title, /ruby/).sql.should == "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
|
3160
3164
|
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
|
3161
3165
|
end
|