sequel 5.3.0 → 5.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG +30 -0
- data/bin/sequel +13 -0
- data/doc/cheat_sheet.rdoc +1 -0
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/querying.rdoc +8 -11
- data/doc/release_notes/5.4.0.txt +80 -0
- data/doc/testing.rdoc +2 -0
- data/lib/sequel/adapters/shared/db2.rb +6 -5
- data/lib/sequel/adapters/shared/mssql.rb +5 -8
- data/lib/sequel/adapters/shared/mysql.rb +4 -8
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +5 -3
- data/lib/sequel/adapters/shared/sqlanywhere.rb +1 -6
- data/lib/sequel/adapters/shared/sqlite.rb +2 -0
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +10 -1
- data/lib/sequel/dataset/query.rb +1 -2
- data/lib/sequel/extensions/date_arithmetic.rb +27 -10
- data/lib/sequel/extensions/datetime_parse_to_time.rb +37 -0
- data/lib/sequel/extensions/index_caching.rb +107 -0
- data/lib/sequel/extensions/null_dataset.rb +3 -1
- data/lib/sequel/extensions/pg_timestamptz.rb +26 -0
- data/lib/sequel/model/base.rb +2 -2
- data/lib/sequel/plugins/class_table_inheritance.rb +11 -3
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +1 -1
- data/spec/adapters/spec_helper.rb +3 -0
- data/spec/adapters/sqlite_spec.rb +1 -1
- data/spec/bin_spec.rb +9 -0
- data/spec/core/connection_pool_spec.rb +2 -2
- data/spec/core/dataset_spec.rb +1 -6
- data/spec/extensions/class_table_inheritance_spec.rb +52 -2
- data/spec/extensions/date_arithmetic_spec.rb +15 -1
- data/spec/extensions/datetime_parse_to_time_spec.rb +169 -0
- data/spec/extensions/index_caching_spec.rb +66 -0
- data/spec/extensions/json_serializer_spec.rb +5 -0
- data/spec/extensions/null_dataset_spec.rb +5 -0
- data/spec/extensions/pg_extended_date_support_spec.rb +4 -0
- data/spec/extensions/pg_timestamptz_spec.rb +17 -0
- data/spec/extensions/xml_serializer_spec.rb +7 -0
- data/spec/integration/dataset_test.rb +6 -0
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/schema_test.rb +19 -17
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/record_spec.rb +28 -0
- 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, @
|
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(
|
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
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
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
|