sequel 3.38.0 → 3.39.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 +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
|