sequel 5.3.0 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +30 -0
  3. data/bin/sequel +13 -0
  4. data/doc/cheat_sheet.rdoc +1 -0
  5. data/doc/dataset_filtering.rdoc +1 -1
  6. data/doc/querying.rdoc +8 -11
  7. data/doc/release_notes/5.4.0.txt +80 -0
  8. data/doc/testing.rdoc +2 -0
  9. data/lib/sequel/adapters/shared/db2.rb +6 -5
  10. data/lib/sequel/adapters/shared/mssql.rb +5 -8
  11. data/lib/sequel/adapters/shared/mysql.rb +4 -8
  12. data/lib/sequel/adapters/shared/oracle.rb +1 -1
  13. data/lib/sequel/adapters/shared/postgres.rb +5 -3
  14. data/lib/sequel/adapters/shared/sqlanywhere.rb +1 -6
  15. data/lib/sequel/adapters/shared/sqlite.rb +2 -0
  16. data/lib/sequel/database/connecting.rb +1 -1
  17. data/lib/sequel/database/schema_methods.rb +10 -1
  18. data/lib/sequel/dataset/query.rb +1 -2
  19. data/lib/sequel/extensions/date_arithmetic.rb +27 -10
  20. data/lib/sequel/extensions/datetime_parse_to_time.rb +37 -0
  21. data/lib/sequel/extensions/index_caching.rb +107 -0
  22. data/lib/sequel/extensions/null_dataset.rb +3 -1
  23. data/lib/sequel/extensions/pg_timestamptz.rb +26 -0
  24. data/lib/sequel/model/base.rb +2 -2
  25. data/lib/sequel/plugins/class_table_inheritance.rb +11 -3
  26. data/lib/sequel/plugins/json_serializer.rb +2 -2
  27. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  28. data/lib/sequel/version.rb +1 -1
  29. data/spec/adapters/postgres_spec.rb +1 -1
  30. data/spec/adapters/spec_helper.rb +3 -0
  31. data/spec/adapters/sqlite_spec.rb +1 -1
  32. data/spec/bin_spec.rb +9 -0
  33. data/spec/core/connection_pool_spec.rb +2 -2
  34. data/spec/core/dataset_spec.rb +1 -6
  35. data/spec/extensions/class_table_inheritance_spec.rb +52 -2
  36. data/spec/extensions/date_arithmetic_spec.rb +15 -1
  37. data/spec/extensions/datetime_parse_to_time_spec.rb +169 -0
  38. data/spec/extensions/index_caching_spec.rb +66 -0
  39. data/spec/extensions/json_serializer_spec.rb +5 -0
  40. data/spec/extensions/null_dataset_spec.rb +5 -0
  41. data/spec/extensions/pg_extended_date_support_spec.rb +4 -0
  42. data/spec/extensions/pg_timestamptz_spec.rb +17 -0
  43. data/spec/extensions/xml_serializer_spec.rb +7 -0
  44. data/spec/integration/dataset_test.rb +6 -0
  45. data/spec/integration/prepared_statement_test.rb +1 -1
  46. data/spec/integration/schema_test.rb +19 -17
  47. data/spec/integration/spec_helper.rb +4 -0
  48. data/spec/model/record_spec.rb +28 -0
  49. metadata +11 -3
@@ -87,6 +87,10 @@ describe "date_arithmetic extension" do
87
87
  db.literal(Sequel.date_add(:a, @h0)).must_equal "CAST(a AS timestamp)"
88
88
  db.literal(Sequel.date_add(:a, @h1)).must_equal "(CAST(a AS timestamp) + CAST('1 days ' AS interval))"
89
89
  db.literal(Sequel.date_add(:a, @h2)).must_equal "(CAST(a AS timestamp) + CAST('1 years 1 months 1 days 1 hours 1 minutes 1 seconds ' AS interval))"
90
+
91
+ db.literal(Sequel.date_add(:a, @h0, :cast=>:timestamptz)).must_equal "CAST(a AS timestamptz)"
92
+ db.literal(Sequel.date_sub(:a, @h0, :cast=>:timestamptz)).must_equal "CAST(a AS timestamptz)"
93
+ db.literal(Sequel.date_add(:a, @h2, :cast=>:timestamptz)).must_equal "(CAST(a AS timestamptz) + CAST('1 years 1 months 1 days 1 hours 1 minutes 1 seconds ' AS interval))"
90
94
  end
91
95
 
92
96
  it "should correctly literalize on SQLite" do
@@ -101,6 +105,7 @@ describe "date_arithmetic extension" do
101
105
  db.literal(Sequel.date_add(:a, @h0)).must_equal "CAST(a AS DATETIME)"
102
106
  db.literal(Sequel.date_add(:a, @h1)).must_equal "DATE_ADD(a, INTERVAL 1 DAY)"
103
107
  db.literal(Sequel.date_add(:a, @h2)).must_equal "DATE_ADD(DATE_ADD(DATE_ADD(DATE_ADD(DATE_ADD(DATE_ADD(a, INTERVAL 1 YEAR), INTERVAL 1 MONTH), INTERVAL 1 DAY), INTERVAL 1 HOUR), INTERVAL 1 MINUTE), INTERVAL 1 SECOND)"
108
+ db.literal(Sequel.date_add(:a, @h0, :cast=>:timestamp)).must_equal "CAST(a AS timestamp)"
104
109
  end
105
110
 
106
111
  it "should correctly literalize on HSQLDB" do
@@ -110,6 +115,9 @@ describe "date_arithmetic extension" do
110
115
  db.literal(Sequel.date_add(:a, @h0)).must_equal "CAST(CAST(a AS timestamp) AS timestamp)"
111
116
  db.literal(Sequel.date_add(:a, @h1)).must_equal "DATE_ADD(CAST(a AS timestamp), INTERVAL 1 DAY)"
112
117
  db.literal(Sequel.date_add(:a, @h2)).must_equal "DATE_ADD(DATE_ADD(DATE_ADD(DATE_ADD(DATE_ADD(DATE_ADD(CAST(a AS timestamp), INTERVAL 1 YEAR), INTERVAL 1 MONTH), INTERVAL 1 DAY), INTERVAL 1 HOUR), INTERVAL 1 MINUTE), INTERVAL 1 SECOND)"
118
+
119
+ db.literal(Sequel.date_add(:a, @h0, :cast=>:datetime)).must_equal "CAST(CAST(a AS datetime) AS datetime)"
120
+ db.literal(Sequel.date_add(:a, @h2, :cast=>:datetime)).must_equal "DATE_ADD(DATE_ADD(DATE_ADD(DATE_ADD(DATE_ADD(DATE_ADD(CAST(a AS datetime), INTERVAL 1 YEAR), INTERVAL 1 MONTH), INTERVAL 1 DAY), INTERVAL 1 HOUR), INTERVAL 1 MINUTE), INTERVAL 1 SECOND)"
113
121
  end
114
122
 
115
123
  it "should correctly literalize on MSSQL" do
@@ -117,6 +125,7 @@ describe "date_arithmetic extension" do
117
125
  db.literal(Sequel.date_add(:A, @h0)).must_equal "CAST(A AS datetime)"
118
126
  db.literal(Sequel.date_add(:A, @h1)).must_equal "DATEADD(day, 1, A)"
119
127
  db.literal(Sequel.date_add(:A, @h2)).must_equal "DATEADD(second, 1, DATEADD(minute, 1, DATEADD(hour, 1, DATEADD(day, 1, DATEADD(month, 1, DATEADD(year, 1, A))))))"
128
+ db.literal(Sequel.date_add(:A, @h0, :cast=>:timestamp)).must_equal "CAST(A AS timestamp)"
120
129
  end
121
130
 
122
131
  it "should correctly literalize on H2" do
@@ -126,6 +135,7 @@ describe "date_arithmetic extension" do
126
135
  db.literal(Sequel.date_add(:a, @h0)).must_equal "CAST(a AS timestamp)"
127
136
  db.literal(Sequel.date_add(:a, @h1)).must_equal "DATEADD('day', 1, a)"
128
137
  db.literal(Sequel.date_add(:a, @h2)).must_equal "DATEADD('second', 1, DATEADD('minute', 1, DATEADD('hour', 1, DATEADD('day', 1, DATEADD('month', 1, DATEADD('year', 1, a))))))"
138
+ db.literal(Sequel.date_add(:a, @h0, :cast=>:datetime)).must_equal "CAST(a AS datetime)"
129
139
  end
130
140
 
131
141
  it "should correctly literalize on access" do
@@ -143,6 +153,7 @@ describe "date_arithmetic extension" do
143
153
  db.literal(Sequel.date_add(:a, @h1)).must_equal "{fn timestampadd(SQL_TSI_DAY, 1, timestamp(a))}"
144
154
  db.literal(Sequel.date_add(:a, @h2)).must_equal "{fn timestampadd(SQL_TSI_SECOND, 1, timestamp({fn timestampadd(SQL_TSI_MINUTE, 1, timestamp({fn timestampadd(SQL_TSI_HOUR, 1, timestamp({fn timestampadd(SQL_TSI_DAY, 1, timestamp({fn timestampadd(SQL_TSI_MONTH, 1, timestamp({fn timestampadd(SQL_TSI_YEAR, 1, timestamp(a))}))}))}))}))}))}"
145
155
  db.literal(Sequel.date_add(Date.civil(2012, 11, 12), @h1)).must_equal "{fn timestampadd(SQL_TSI_DAY, 1, timestamp((CAST('2012-11-12' AS varchar(255)) || ' 00:00:00')))}"
156
+ db.literal(Sequel.date_add(:a, @h0, :cast=>:datetime)).must_equal "CAST(a AS datetime)"
146
157
  end
147
158
 
148
159
  it "should correctly literalize on Oracle" do
@@ -150,13 +161,16 @@ describe "date_arithmetic extension" do
150
161
  db.literal(Sequel.date_add(:A, @h0)).must_equal "CAST(A AS timestamp)"
151
162
  db.literal(Sequel.date_add(:A, @h1)).must_equal "(A + INTERVAL '1' DAY)"
152
163
  db.literal(Sequel.date_add(:A, @h2)).must_equal "(A + INTERVAL '1' YEAR + INTERVAL '1' MONTH + INTERVAL '1' DAY + INTERVAL '1' HOUR + INTERVAL '1' MINUTE + INTERVAL '1' SECOND)"
164
+ db.literal(Sequel.date_add(:A, @h0, :cast=>:datetime)).must_equal "CAST(A AS datetime)"
153
165
  end
154
166
 
155
167
  it "should correctly literalize on DB2" do
156
168
  db = dbf.call(:db2)
157
169
  db.literal(Sequel.date_add(:A, @h0)).must_equal "CAST(A AS timestamp)"
158
170
  db.literal(Sequel.date_add(:A, @h1)).must_equal "(CAST(A AS timestamp) + 1 days)"
159
- db.literal(Sequel.date_add(:A, @h2)).must_equal "(CAST(A AS timestamp) + 1 years + 1 months + 1 days + 1 hours + 1 minutes + 1 seconds)"
171
+ db.literal(Sequel.date_add(:A, @h0)).must_equal "CAST(A AS timestamp)"
172
+ db.literal(Sequel.date_add(:A, @h1, :cast=>:datetime)).must_equal "(CAST(A AS datetime) + 1 days)"
173
+ db.literal(Sequel.date_add(:A, @h2, :cast=>:datetime)).must_equal "(CAST(A AS datetime) + 1 years + 1 months + 1 days + 1 hours + 1 minutes + 1 seconds)"
160
174
  end
161
175
 
162
176
  it "should raise error if literalizing on an unsupported database" do
@@ -0,0 +1,169 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe "datetime_parse_to_time extension" do
4
+ before(:all) do
5
+ Sequel.extension :datetime_parse_to_time
6
+ end
7
+ after(:all) do
8
+ # Can't undo the adding of the module to Sequel, so removing the
9
+ # method in the module is the only way to fix it.
10
+ Sequel::DateTimeParseToTime.send(:remove_method, :convert_input_timestamp)
11
+ end
12
+
13
+ before do
14
+ @db = Sequel::Database.new
15
+ @dataset = @db.dataset.with_extend do
16
+ def supports_timestamp_timezones?; true end
17
+ def supports_timestamp_usecs?; false end
18
+ end
19
+ @utc_time = Time.utc(2010, 1, 2, 3, 4, 5)
20
+ @local_time = Time.local(2010, 1, 2, 3, 4, 5)
21
+ @offset = sprintf("%+03i%02i", *(@local_time.utc_offset/60).divmod(60))
22
+ @dt_offset = @local_time.utc_offset/Rational(86400, 1)
23
+ @utc_datetime = DateTime.new(2010, 1, 2, 3, 4, 5)
24
+ @local_datetime = DateTime.new(2010, 1, 2, 3, 4, 5, @dt_offset)
25
+ end
26
+ after do
27
+ Sequel.default_timezone = nil
28
+ Sequel.datetime_class = Time
29
+ end
30
+
31
+ it "should handle conversions during invalid localtimes" do
32
+ # This only checks of a couple of times that may be invalid.
33
+ # You can run with TZ=Europe/Berlin or TZ=US/Pacific
34
+ Sequel.database_timezone = :utc
35
+ Sequel.database_to_application_timestamp("2017-03-26 02:30:00").getutc.hour.must_equal 2
36
+ Sequel.database_to_application_timestamp("2017-03-12 02:30:00").getutc.hour.must_equal 2
37
+ end
38
+
39
+ it "should handle an database timezone of :utc when literalizing values" do
40
+ Sequel.database_timezone = :utc
41
+ @dataset.literal(Time.utc(2010, 1, 2, 3, 4, 5)).must_equal "'2010-01-02 03:04:05+0000'"
42
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, 5)).must_equal "'2010-01-02 03:04:05+0000'"
43
+ end
44
+
45
+ it "should handle an database timezone of :local when literalizing values" do
46
+ Sequel.database_timezone = :local
47
+ @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5)).must_equal "'2010-01-02 03:04:05#{@offset}'"
48
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, 5, @dt_offset)).must_equal "'2010-01-02 03:04:05#{@offset}'"
49
+ end
50
+
51
+ it "should have Database#timezone override Sequel.database_timezone" do
52
+ Sequel.database_timezone = :local
53
+ @db.timezone = :utc
54
+ @dataset.literal(Time.utc(2010, 1, 2, 3, 4, 5)).must_equal "'2010-01-02 03:04:05+0000'"
55
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, 5)).must_equal "'2010-01-02 03:04:05+0000'"
56
+
57
+ Sequel.database_timezone = :utc
58
+ @db.timezone = :local
59
+ @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5)).must_equal "'2010-01-02 03:04:05#{@offset}'"
60
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, 5, @dt_offset)).must_equal "'2010-01-02 03:04:05#{@offset}'"
61
+ end
62
+
63
+ it "should handle converting database timestamps into application timestamps" do
64
+ Sequel.database_timezone = :utc
65
+ Sequel.application_timezone = :local
66
+ t = Time.now.utc
67
+ Sequel.database_to_application_timestamp(t).to_s.must_equal t.getlocal.to_s
68
+ Sequel.database_to_application_timestamp(t.to_s).to_s.must_equal t.getlocal.to_s
69
+ Sequel.database_to_application_timestamp(t.strftime('%Y-%m-%d %H:%M:%S')).to_s.must_equal t.getlocal.to_s
70
+
71
+ Sequel.datetime_class = DateTime
72
+ dt = DateTime.now
73
+ dt2 = dt.new_offset(0)
74
+ Sequel.database_to_application_timestamp(dt2).to_s.must_equal dt.to_s
75
+ Sequel.database_to_application_timestamp(dt2.to_s).to_s.must_equal dt.to_s
76
+ Sequel.database_to_application_timestamp(dt2.strftime('%Y-%m-%d %H:%M:%S')).to_s.must_equal dt.to_s
77
+
78
+ Sequel.datetime_class = Time
79
+ Sequel.database_timezone = :local
80
+ Sequel.application_timezone = :utc
81
+ Sequel.database_to_application_timestamp(t.getlocal).to_s.must_equal t.to_s
82
+ Sequel.database_to_application_timestamp(t.getlocal.to_s).to_s.must_equal t.to_s
83
+ Sequel.database_to_application_timestamp(t.getlocal.strftime('%Y-%m-%d %H:%M:%S')).to_s.must_equal t.to_s
84
+
85
+ Sequel.datetime_class = DateTime
86
+ Sequel.database_to_application_timestamp(dt).to_s.must_equal dt2.to_s
87
+ Sequel.database_to_application_timestamp(dt.to_s).to_s.must_equal dt2.to_s
88
+ Sequel.database_to_application_timestamp(dt.strftime('%Y-%m-%d %H:%M:%S')).to_s.must_equal dt2.to_s
89
+ end
90
+
91
+ it "should handle typecasting timestamp columns" do
92
+ Sequel.typecast_timezone = :utc
93
+ Sequel.application_timezone = :local
94
+ t = Time.now.utc
95
+ @db.typecast_value(:datetime, t).to_s.must_equal t.getlocal.to_s
96
+ @db.typecast_value(:datetime, t.to_s).to_s.must_equal t.getlocal.to_s
97
+ @db.typecast_value(:datetime, t.strftime('%Y-%m-%d %H:%M:%S')).to_s.must_equal t.getlocal.to_s
98
+
99
+ Sequel.datetime_class = DateTime
100
+ dt = DateTime.now
101
+ dt2 = dt.new_offset(0)
102
+ @db.typecast_value(:datetime, dt2).to_s.must_equal dt.to_s
103
+ @db.typecast_value(:datetime, dt2.to_s).to_s.must_equal dt.to_s
104
+ @db.typecast_value(:datetime, dt2.strftime('%Y-%m-%d %H:%M:%S')).to_s.must_equal dt.to_s
105
+
106
+ Sequel.datetime_class = Time
107
+ Sequel.typecast_timezone = :local
108
+ Sequel.application_timezone = :utc
109
+ @db.typecast_value(:datetime, t.getlocal).to_s.must_equal t.to_s
110
+ @db.typecast_value(:datetime, t.getlocal.to_s).to_s.must_equal t.to_s
111
+ @db.typecast_value(:datetime, t.getlocal.strftime('%Y-%m-%d %H:%M:%S')).to_s.must_equal t.to_s
112
+
113
+ Sequel.datetime_class = DateTime
114
+ @db.typecast_value(:datetime, dt).to_s.must_equal dt2.to_s
115
+ @db.typecast_value(:datetime, dt.to_s).to_s.must_equal dt2.to_s
116
+ @db.typecast_value(:datetime, dt.strftime('%Y-%m-%d %H:%M:%S')).to_s.must_equal dt2.to_s
117
+ end
118
+
119
+ it "should handle converting database timestamp columns from an array of values" do
120
+ Sequel.database_timezone = :utc
121
+ Sequel.application_timezone = :local
122
+ t = Time.now.utc
123
+ Sequel.database_to_application_timestamp([t.year, t.mon, t.day, t.hour, t.min, t.sec]).to_s.must_equal t.getlocal.to_s
124
+
125
+ Sequel.datetime_class = DateTime
126
+ dt = DateTime.now
127
+ dt2 = dt.new_offset(0)
128
+ Sequel.database_to_application_timestamp([dt2.year, dt2.mon, dt2.day, dt2.hour, dt2.min, dt2.sec]).to_s.must_equal dt.to_s
129
+
130
+ Sequel.datetime_class = Time
131
+ Sequel.database_timezone = :local
132
+ Sequel.application_timezone = :utc
133
+ t = t.getlocal
134
+ Sequel.database_to_application_timestamp([t.year, t.mon, t.day, t.hour, t.min, t.sec]).to_s.must_equal t.getutc.to_s
135
+
136
+ Sequel.datetime_class = DateTime
137
+ Sequel.database_to_application_timestamp([dt.year, dt.mon, dt.day, dt.hour, dt.min, dt.sec]).to_s.must_equal dt2.to_s
138
+ end
139
+
140
+ it "should raise an InvalidValue error when an error occurs while converting a timestamp" do
141
+ proc{Sequel.database_to_application_timestamp([0, 0, 0, 0, 0, 0])}.must_raise(Sequel::InvalidValue)
142
+ end
143
+
144
+ it "should raise an error when attempting to typecast to a timestamp from an unsupported type" do
145
+ proc{Sequel.database_to_application_timestamp(Object.new)}.must_raise(Sequel::InvalidValue)
146
+ end
147
+
148
+ it "should raise an InvalidValue error when the DateTime class is used and when a bad application timezone is used when attempting to convert timestamps" do
149
+ Sequel.application_timezone = :blah
150
+ Sequel.datetime_class = DateTime
151
+ proc{Sequel.database_to_application_timestamp('2009-06-01 10:20:30')}.must_raise(Sequel::InvalidValue)
152
+ end
153
+
154
+ it "should raise an InvalidValue error when the DateTime class is used and when a bad database timezone is used when attempting to convert timestamps" do
155
+ Sequel.database_timezone = :blah
156
+ Sequel.datetime_class = DateTime
157
+ proc{Sequel.database_to_application_timestamp('2009-06-01 10:20:30')}.must_raise(Sequel::InvalidValue)
158
+ end
159
+
160
+ it "should have Sequel.default_timezone= should set all other timezones" do
161
+ Sequel.database_timezone.must_be_nil
162
+ Sequel.application_timezone.must_be_nil
163
+ Sequel.typecast_timezone.must_be_nil
164
+ Sequel.default_timezone = :utc
165
+ Sequel.database_timezone.must_equal :utc
166
+ Sequel.application_timezone.must_equal :utc
167
+ Sequel.typecast_timezone.must_equal :utc
168
+ end
169
+ end
@@ -0,0 +1,66 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe "index_caching extension" do
4
+ before do
5
+ @db = Sequel.connect('mock://postgres').extension(:index_caching)
6
+ @indexes = {'"table"'=>{:table_idx_unique=>{:columns=>[:first_col, :second_col], :unique=>true, :deferrable=>nil}}}
7
+ @filename = "spec/files/test_indexes_#$$.dump"
8
+ @db.instance_variable_set(:@indexes, @indexes)
9
+ end
10
+ after do
11
+ File.delete(@filename) if File.exist?(@filename)
12
+ end
13
+
14
+ it "#indexes should return cached index information" do
15
+ @db.indexes(:table).must_equal @indexes['"table"']
16
+ @db.indexes(:table, {}).must_equal @indexes['"table"']
17
+ end
18
+
19
+ it "#indexes should skip cached information if given options" do
20
+ @db.indexes(:table, :schema=>:b).must_equal({})
21
+ end
22
+
23
+ it "Database should remove cached indexes when schema is changed" do
24
+ @db.create_table(:table){Integer :a}
25
+ @db.indexes(:table).must_equal({})
26
+ end
27
+
28
+ it "Database#freeze should allow cached information to work" do
29
+ @db.freeze.indexes(:table).must_equal @indexes['"table"']
30
+ end
31
+
32
+ it "Database#freeze should allow removing index information" do
33
+ @db.freeze
34
+ @db.create_table(:table){Integer :a}
35
+ @db.indexes(:table).must_equal({})
36
+ end
37
+
38
+ it "Database#dump_index_cache should dump the index cache to the given file" do
39
+ File.exist?(@filename).must_equal false
40
+ @db.dump_index_cache(@filename)
41
+ File.exist?(@filename).must_equal true
42
+ File.size(@filename).must_be :>, 0
43
+ end
44
+
45
+ it "Database#load_index_cache should load the index cache from the given file dumped by #dump_index_cache" do
46
+ @db.dump_index_cache(@filename)
47
+ db = Sequel::Database.new.extension(:index_caching)
48
+ db.load_index_cache(@filename)
49
+ db.extension(:index_caching)
50
+ @db.instance_variable_get(:@indexes).must_equal @indexes
51
+ end
52
+
53
+ it "Database#dump_index_cache? should dump the index cache to the given file unless the file exists" do
54
+ File.open(@filename, 'wb'){|f|}
55
+ File.size(@filename).must_equal 0
56
+ @db.dump_index_cache?(@filename)
57
+ File.size(@filename).must_equal 0
58
+ end
59
+
60
+ it "Database#load_index_cache? should load the index cache from the given file if it exists" do
61
+ db = Sequel::Database.new.extension(:index_caching)
62
+ File.exist?(@filename).must_equal false
63
+ db.load_index_cache?(@filename)
64
+ db.instance_variable_get(:@indexes).must_equal({})
65
+ end
66
+ end
@@ -187,6 +187,11 @@ describe "Sequel::Plugins::JsonSerializer" do
187
187
  Album.array_from_json(Album.dataset.to_json(:only=>:name)).must_equal [Album.load(:name=>@album.name)]
188
188
  end
189
189
 
190
+ it "should have dataset to_json method work with eager_graph datasets" do
191
+ ds = Album.dataset.eager_graph(:artist).with_fetch(:id=>1, :name=>'RF', :artist_id=>2, :artist_id_0=>2, :artist_name=>'YM')
192
+ Sequel.parse_json(ds.to_json(:only=>:name, :include=>{:artist=>{:only=>:name}})).must_equal [{"name"=>"RF", "artist"=>{"name"=>"YM"}}]
193
+ end
194
+
190
195
  it "should have dataset to_json method work with naked datasets" do
191
196
  ds = Album.dataset.naked.with_fetch(:id=>1, :name=>'RF', :artist_id=>2)
192
197
  Sequel.parse_json(ds.to_json).must_equal [@album.values.inject({}){|h, (k, v)| h[k.to_s] = v; h}]
@@ -21,6 +21,11 @@ describe "null_dataset extension" do
21
21
  @i.must_equal 0
22
22
  end
23
23
 
24
+ it "nullify should be a cached dataset" do
25
+ ds = @db[:table]
26
+ ds.nullify.object_id.must_equal(ds.nullify.object_id)
27
+ end
28
+
24
29
  it "should make insert be a noop" do
25
30
  @ds.insert(1).must_be_nil
26
31
  end
@@ -105,6 +105,10 @@ describe "pg_extended_date_support extension" do
105
105
  @db.literal(-Date::Infinity.new).must_equal "'-infinity'"
106
106
  end
107
107
 
108
+ it "should raise errors for literalizing random Objects" do
109
+ proc{@db.literal(Object.new)}.must_raise Sequel::Error
110
+ end
111
+
108
112
  it "should format BC dates" do
109
113
  @db.literal(Date.new(-1091, 10, 20)).must_equal "'1092-10-20 BC'"
110
114
  @db.literal(Date.new(1092, 10, 20)).must_equal "'1092-10-20'"
@@ -0,0 +1,17 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe "pg_timestamptz extension" do
4
+ before do
5
+ @db = Sequel.mock(:host=>'postgres').extension :pg_timestamptz
6
+ end
7
+
8
+ it "should use timestamptz as default timestamp type" do
9
+ @db.create_table(:t){Time :t; DateTime :tz; Time :ot, :only_time=>true}
10
+ @db.sqls.must_equal ['CREATE TABLE "t" ("t" timestamptz, "tz" timestamptz, "ot" time)']
11
+ end
12
+
13
+ it "should use timestamptz when casting" do
14
+ @db.get(Sequel.cast('a', Time))
15
+ @db.sqls.must_equal ["SELECT CAST('a' AS timestamptz) AS \"v\" LIMIT 1"]
16
+ end
17
+ end
@@ -172,6 +172,13 @@ describe "Sequel::Plugins::XmlSerializer" do
172
172
  x.first.albums.must_equal [a]
173
173
  end
174
174
 
175
+ it "should work correctly for eager graphed datasets" do
176
+ ds = Album.dataset.eager_graph(:artist).with_fetch(:id=>1, :name=>'RF', :artist_id=>2, :artist_id_0=>2, :artist_name=>'YJM')
177
+ albums = Album.array_from_xml(ds.to_xml(:only=>:name, :include=>{:artist=>{:only=>:name}}), :associations=>:artist)
178
+ albums.must_equal [Album.load(:name=>@album.name)]
179
+ albums.first.artist.must_equal Artist.load(:name=>@artist.name)
180
+ end
181
+
175
182
  it "should raise an error if the dataset does not have a row_proc" do
176
183
  proc{Album.dataset.naked.to_xml}.must_raise(Sequel::Error)
177
184
  end
@@ -1217,6 +1217,7 @@ describe "Sequel::Dataset convenience methods" do
1217
1217
  @ds.as_hash([:a, :c], :b).must_equal([1, 3]=>2, [5, 7]=>6)
1218
1218
  @ds.as_hash(:a, [:b, :c]).must_equal(1=>[2, 3], 5=>[6, 7])
1219
1219
  @ds.as_hash([:a, :c], [:b, :d]).must_equal([1, 3]=>[2, 4], [5, 7]=>[6, 8])
1220
+ @ds.extension(:null_dataset).nullify.as_hash([:a, :c], [:b, :d]).must_equal({})
1220
1221
 
1221
1222
  @ds.as_hash(:a, :b, :hash => (tmp = {})).must_be_same_as(tmp)
1222
1223
  end
@@ -1232,6 +1233,7 @@ describe "Sequel::Dataset convenience methods" do
1232
1233
  ds.to_hash_groups([:a, :c], :d).must_equal([1, 3]=>[4, 9], [5, 7]=>[8])
1233
1234
  ds.to_hash_groups(:a, [:b, :d]).must_equal(1=>[[2, 4], [2, 9]], 5=>[[6, 8]])
1234
1235
  ds.to_hash_groups([:a, :c], [:b, :d]).must_equal([1, 3]=>[[2, 4], [2, 9]], [5, 7]=>[[6, 8]])
1236
+ @ds.extension(:null_dataset).nullify.to_hash_groups([:a, :c], [:b, :d]).must_equal({})
1235
1237
 
1236
1238
  ds.to_hash_groups(:a, :d, :hash => (tmp = {})).must_be_same_as(tmp)
1237
1239
  end
@@ -1241,6 +1243,7 @@ describe "Sequel::Dataset convenience methods" do
1241
1243
  @ds.select_map(:b).must_equal [2, 6]
1242
1244
  @ds.select_map([:a]).must_equal [[1], [5]]
1243
1245
  @ds.select_map([:a, :b]).must_equal [[1, 2], [5, 6]]
1246
+ @ds.extension(:null_dataset).nullify.select_map([:a, :b]).must_equal []
1244
1247
 
1245
1248
  @ds.select_map(Sequel[:a].as(:e)).must_equal [1, 5]
1246
1249
  @ds.select_map(Sequel[:b].as(:e)).must_equal [2, 6]
@@ -1258,6 +1261,7 @@ describe "Sequel::Dataset convenience methods" do
1258
1261
  @ds.select_order_map(Sequel.qualify(:a, :b).as(:e)).must_equal [2, 6]
1259
1262
  @ds.select_order_map([:a]).must_equal [[1], [5]]
1260
1263
  @ds.select_order_map([Sequel.desc(:a), :b]).must_equal [[5, 6], [1, 2]]
1264
+ @ds.extension(:null_dataset).nullify.select_order_map(:a).must_equal []
1261
1265
 
1262
1266
  @ds.select_order_map(Sequel[:a].as(:e)).must_equal [1, 5]
1263
1267
  @ds.select_order_map(Sequel[:b].as(:e)).must_equal [2, 6]
@@ -1278,6 +1282,7 @@ describe "Sequel::Dataset convenience methods" do
1278
1282
  @ds.select_hash(:a, [:b, :c]).must_equal(1=>[2, 3], 5=>[6, 7])
1279
1283
  @ds.select_hash([:a, :c], [:b, :d]).must_equal([1, 3]=>[2, 4], [5, 7]=>[6, 8])
1280
1284
  @ds.select_hash(:a, :b, :hash => (tmp = {})).must_be_same_as(tmp)
1285
+ @ds.extension(:null_dataset).nullify.select_hash(:a, :b).must_equal({})
1281
1286
  end
1282
1287
 
1283
1288
  it "should have working #select_hash_groups" do
@@ -1292,6 +1297,7 @@ describe "Sequel::Dataset convenience methods" do
1292
1297
  ds.select_hash_groups(:a, [:b, :d]).must_equal(1=>[[2, 4], [2, 9]], 5=>[[6, 8]])
1293
1298
  ds.select_hash_groups([:a, :c], [:b, :d]).must_equal([1, 3]=>[[2, 4], [2, 9]], [5, 7]=>[[6, 8]])
1294
1299
  ds.select_hash_groups(:a, :d, :hash => (tmp = {})).must_be_same_as(tmp)
1300
+ @ds.extension(:null_dataset).nullify.select_hash_groups(:a, :d).must_equal({})
1295
1301
  end
1296
1302
  end
1297
1303
 
@@ -319,7 +319,7 @@ describe "Bound Argument Types" do
319
319
  TrueClass :b
320
320
  end
321
321
  @ds = @db[:items]
322
- @vs = {:d=>Date.civil(2010, 10, 11), :dt=>DateTime.civil(2010, 10, 12, 13, 14, 15), :f=>1.0, :s=>'str', :t=>Time.at(20101010), :file=>Sequel::SQL::Blob.new('blob'), :b=>true}
322
+ @vs = {:d=>Date.civil(2010, 10, 11), :dt=>DateTime.civil(2010, 10, 12, 13, 14, 15), :f=>1.0, :s=>'str', :t=>Time.at(Time.now.to_i), :file=>Sequel::SQL::Blob.new('blob'), :b=>true}
323
323
  end
324
324
  before do
325
325
  @ds.delete
@@ -189,23 +189,25 @@ describe "Database index parsing" do
189
189
  end
190
190
 
191
191
  it "should parse indexes into a hash" do
192
- # Delete :deferrable entry, since not all adapters implement it
193
- f = lambda{h = DB.indexes(:items); h.values.each{|h2| h2.delete(:deferrable)}; h}
194
-
195
- DB.create_table!(:items){Integer :n; Integer :a}
196
- f.call.must_equal({})
197
- DB.add_index(:items, :n)
198
- f.call.must_equal(:items_n_index=>{:columns=>[:n], :unique=>false})
199
- DB.drop_index(:items, :n)
200
- f.call.must_equal({})
201
- DB.add_index(:items, :n, :unique=>true, :name=>:blah_blah_index)
202
- f.call.must_equal(:blah_blah_index=>{:columns=>[:n], :unique=>true})
203
- DB.add_index(:items, [:n, :a])
204
- f.call.must_equal(:blah_blah_index=>{:columns=>[:n], :unique=>true}, :items_n_a_index=>{:columns=>[:n, :a], :unique=>false})
205
- DB.drop_index(:items, :n, :name=>:blah_blah_index)
206
- f.call.must_equal(:items_n_a_index=>{:columns=>[:n, :a], :unique=>false})
207
- DB.drop_index(:items, [:n, :a])
208
- f.call.must_equal({})
192
+ [:items, Sequel.identifier(:items)].each do |table|
193
+ # Delete :deferrable entry, since not all adapters implement it
194
+ f = lambda{h = DB.indexes(table); h.values.each{|h2| h2.delete(:deferrable)}; h}
195
+
196
+ DB.create_table!(table){Integer :n; Integer :a}
197
+ f.call.must_equal({})
198
+ DB.add_index(table, :n)
199
+ f.call.must_equal(:items_n_index=>{:columns=>[:n], :unique=>false})
200
+ DB.drop_index(table, :n)
201
+ f.call.must_equal({})
202
+ DB.add_index(table, :n, :unique=>true, :name=>:blah_blah_index)
203
+ f.call.must_equal(:blah_blah_index=>{:columns=>[:n], :unique=>true})
204
+ DB.add_index(table, [:n, :a])
205
+ f.call.must_equal(:blah_blah_index=>{:columns=>[:n], :unique=>true}, :items_n_a_index=>{:columns=>[:n, :a], :unique=>false})
206
+ DB.drop_index(table, :n, :name=>:blah_blah_index)
207
+ f.call.must_equal(:items_n_a_index=>{:columns=>[:n, :a], :unique=>false})
208
+ DB.drop_index(table, [:n, :a])
209
+ f.call.must_equal({})
210
+ end
209
211
  end
210
212
 
211
213
  it "should not include a primary key index" do