sequel 5.3.0 → 5.4.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.
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