sequel 5.19.0 → 5.24.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.
- checksums.yaml +4 -4
- data/CHANGELOG +102 -0
- data/doc/dataset_filtering.rdoc +15 -0
- data/doc/opening_databases.rdoc +5 -1
- data/doc/release_notes/5.20.0.txt +89 -0
- data/doc/release_notes/5.21.0.txt +87 -0
- data/doc/release_notes/5.22.0.txt +48 -0
- data/doc/release_notes/5.23.0.txt +56 -0
- data/doc/release_notes/5.24.0.txt +56 -0
- data/doc/sharding.rdoc +2 -0
- data/doc/testing.rdoc +1 -0
- data/doc/transactions.rdoc +38 -0
- data/lib/sequel/adapters/ado.rb +27 -19
- data/lib/sequel/adapters/jdbc.rb +7 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -2
- data/lib/sequel/adapters/jdbc/postgresql.rb +1 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +29 -0
- data/lib/sequel/adapters/mysql2.rb +2 -3
- data/lib/sequel/adapters/shared/mssql.rb +7 -7
- data/lib/sequel/adapters/shared/postgres.rb +37 -19
- data/lib/sequel/adapters/shared/sqlite.rb +27 -3
- data/lib/sequel/adapters/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +12 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -0
- data/lib/sequel/database/logging.rb +7 -1
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +12 -3
- data/lib/sequel/database/schema_methods.rb +2 -0
- data/lib/sequel/database/transactions.rb +57 -5
- data/lib/sequel/dataset.rb +4 -2
- data/lib/sequel/dataset/actions.rb +3 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +4 -1
- data/lib/sequel/dataset/query.rb +5 -1
- data/lib/sequel/dataset/sql.rb +11 -7
- data/lib/sequel/extensions/named_timezones.rb +52 -8
- data/lib/sequel/extensions/pg_array.rb +4 -0
- data/lib/sequel/extensions/pg_json.rb +387 -123
- data/lib/sequel/extensions/pg_range.rb +3 -2
- data/lib/sequel/extensions/pg_row.rb +3 -1
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/extensions/server_block.rb +15 -4
- data/lib/sequel/model/associations.rb +35 -9
- data/lib/sequel/model/plugins.rb +104 -0
- data/lib/sequel/plugins/association_dependencies.rb +3 -3
- data/lib/sequel/plugins/association_pks.rb +14 -4
- data/lib/sequel/plugins/association_proxies.rb +3 -2
- data/lib/sequel/plugins/class_table_inheritance.rb +11 -0
- data/lib/sequel/plugins/composition.rb +13 -9
- data/lib/sequel/plugins/finder.rb +2 -2
- data/lib/sequel/plugins/hook_class_methods.rb +17 -5
- data/lib/sequel/plugins/insert_conflict.rb +72 -0
- data/lib/sequel/plugins/inverted_subsets.rb +2 -2
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +147 -59
- data/lib/sequel/plugins/rcte_tree.rb +6 -0
- data/lib/sequel/plugins/static_cache.rb +8 -3
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/subset_conditions.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +5 -3
- data/lib/sequel/sql.rb +15 -3
- data/lib/sequel/timezones.rb +50 -11
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +24 -0
- data/spec/adapters/mysql_spec.rb +0 -5
- data/spec/adapters/postgres_spec.rb +319 -1
- data/spec/bin_spec.rb +1 -1
- data/spec/core/database_spec.rb +123 -2
- data/spec/core/dataset_spec.rb +33 -1
- data/spec/core/expression_filters_spec.rb +25 -1
- data/spec/core/schema_spec.rb +24 -0
- data/spec/extensions/class_table_inheritance_spec.rb +30 -8
- data/spec/extensions/core_refinements_spec.rb +1 -1
- data/spec/extensions/hook_class_methods_spec.rb +22 -0
- data/spec/extensions/insert_conflict_spec.rb +103 -0
- data/spec/extensions/migration_spec.rb +13 -0
- data/spec/extensions/named_timezones_spec.rb +109 -2
- data/spec/extensions/pg_auto_constraint_validations_spec.rb +45 -0
- data/spec/extensions/pg_json_spec.rb +218 -29
- data/spec/extensions/pg_range_spec.rb +76 -9
- data/spec/extensions/rcte_tree_spec.rb +6 -0
- data/spec/extensions/s_spec.rb +1 -1
- data/spec/extensions/schema_dumper_spec.rb +4 -2
- data/spec/extensions/server_block_spec.rb +38 -0
- data/spec/extensions/spec_helper.rb +8 -1
- data/spec/extensions/static_cache_cache_spec.rb +35 -0
- data/spec/integration/dataset_test.rb +25 -9
- data/spec/integration/plugin_test.rb +42 -0
- data/spec/integration/schema_test.rb +7 -2
- data/spec/integration/transaction_test.rb +50 -0
- data/spec/model/associations_spec.rb +84 -4
- data/spec/model/plugins_spec.rb +111 -0
- metadata +16 -2
data/spec/bin_spec.rb
CHANGED
|
@@ -86,7 +86,7 @@ Begin creating indexes
|
|
|
86
86
|
Finished creating indexes
|
|
87
87
|
Begin adding foreign key constraints
|
|
88
88
|
Finished adding foreign key constraints
|
|
89
|
-
Database copy finished in \\d
|
|
89
|
+
Database copy finished in \\d+\\.\\d+ seconds
|
|
90
90
|
END
|
|
91
91
|
DB2.tables.sort_by{|t| t.to_s}.must_equal [:a, :b]
|
|
92
92
|
DB[:a].all.must_equal [{:a=>1, :name=>'foo'}]
|
data/spec/core/database_spec.rb
CHANGED
|
@@ -264,6 +264,25 @@ describe "Database#log_connection_yield" do
|
|
|
264
264
|
@o.logs.first.first.must_equal :info
|
|
265
265
|
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah; \[1, 2\]\z/)
|
|
266
266
|
end
|
|
267
|
+
|
|
268
|
+
it "should log without a logger defined by forcing skip_logging? to return false" do
|
|
269
|
+
@db.logger = nil
|
|
270
|
+
@db.extend(Module.new do
|
|
271
|
+
def skip_logging?
|
|
272
|
+
false
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def log_duration(*)
|
|
276
|
+
self.did_log = true
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
attr_accessor :did_log
|
|
280
|
+
end)
|
|
281
|
+
|
|
282
|
+
@db.log_connection_yield('some sql', @conn) {}
|
|
283
|
+
|
|
284
|
+
@db.did_log.must_equal true
|
|
285
|
+
end
|
|
267
286
|
end
|
|
268
287
|
|
|
269
288
|
describe "Database#uri" do
|
|
@@ -1140,15 +1159,86 @@ describe "Database#transaction with savepoint support" do
|
|
|
1140
1159
|
end
|
|
1141
1160
|
|
|
1142
1161
|
it "should support after_rollback inside savepoints" do
|
|
1143
|
-
@db.transaction do
|
|
1162
|
+
@db.transaction(:rollback=>:always) do
|
|
1144
1163
|
@db.after_rollback{@db.execute('foo')}
|
|
1145
1164
|
@db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('bar')}}
|
|
1146
1165
|
@db.after_rollback{@db.execute('baz')}
|
|
1147
|
-
raise Sequel::Rollback
|
|
1148
1166
|
end
|
|
1149
1167
|
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'RELEASE SAVEPOINT autopoint_1', 'ROLLBACK', 'foo', 'bar', 'baz']
|
|
1150
1168
|
end
|
|
1151
1169
|
|
|
1170
|
+
it "should run after_commit if savepoint rolled back" do
|
|
1171
|
+
@db.transaction do
|
|
1172
|
+
@db.after_commit{@db.execute('foo')}
|
|
1173
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_commit{@db.execute('bar')}}
|
|
1174
|
+
end
|
|
1175
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT', 'foo', 'bar']
|
|
1176
|
+
end
|
|
1177
|
+
|
|
1178
|
+
it "should not run after_commit if savepoint rolled back and :savepoint option used" do
|
|
1179
|
+
@db.transaction do
|
|
1180
|
+
@db.after_commit{@db.execute('foo')}
|
|
1181
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_commit(:savepoint=>true){@db.execute('bar')}}
|
|
1182
|
+
end
|
|
1183
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT', 'foo']
|
|
1184
|
+
end
|
|
1185
|
+
|
|
1186
|
+
it "should not run after_commit if higher-level savepoint rolled back and :savepoint option used" do
|
|
1187
|
+
@db.transaction do
|
|
1188
|
+
@db.after_commit{@db.execute('foo')}
|
|
1189
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){@db.execute('bar')}}}
|
|
1190
|
+
end
|
|
1191
|
+
@db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "ROLLBACK TO SAVEPOINT autopoint_1", "COMMIT", "foo"]
|
|
1192
|
+
end
|
|
1193
|
+
|
|
1194
|
+
it "should not run after_commit if transaction rolled back and :savepoint option used" do
|
|
1195
|
+
@db.transaction(:rollback=>:always) do
|
|
1196
|
+
@db.after_commit{@db.execute('foo')}
|
|
1197
|
+
@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){@db.execute('bar')}}}
|
|
1198
|
+
end
|
|
1199
|
+
@db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_1", "ROLLBACK"]
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
it "should run after_rollback if savepoint rolls back" do
|
|
1203
|
+
@db.transaction(:rollback=>:always) do
|
|
1204
|
+
@db.after_rollback{@db.execute('foo')}
|
|
1205
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback{@db.execute('bar')}}
|
|
1206
|
+
@db.after_rollback{@db.execute('baz')}
|
|
1207
|
+
end
|
|
1208
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK', 'foo', 'bar', 'baz']
|
|
1209
|
+
end
|
|
1210
|
+
|
|
1211
|
+
it "should run after_rollback when savepoint rolls back if :savepoint option used" do
|
|
1212
|
+
@db.transaction(:rollback=>:always) do
|
|
1213
|
+
@db.after_rollback{@db.execute('foo')}
|
|
1214
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}
|
|
1215
|
+
@db.after_rollback{@db.execute('baz')}
|
|
1216
|
+
end
|
|
1217
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'bar', 'ROLLBACK', 'foo', 'baz']
|
|
1218
|
+
end
|
|
1219
|
+
|
|
1220
|
+
it "should run after_rollback if savepoint rolled back and :savepoint option used, even if transaction commits" do
|
|
1221
|
+
@db.transaction do
|
|
1222
|
+
@db.after_commit{@db.execute('foo')}
|
|
1223
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}
|
|
1224
|
+
end
|
|
1225
|
+
@db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'bar', 'COMMIT', 'foo']
|
|
1226
|
+
end
|
|
1227
|
+
|
|
1228
|
+
it "should run after_rollback if higher-level savepoint rolled back and :savepoint option used" do
|
|
1229
|
+
@db.transaction do
|
|
1230
|
+
@db.transaction(:savepoint=>true, :rollback=>:always){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}}
|
|
1231
|
+
end
|
|
1232
|
+
@db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "ROLLBACK TO SAVEPOINT autopoint_1", "bar", "COMMIT"]
|
|
1233
|
+
end
|
|
1234
|
+
|
|
1235
|
+
it "should run after_rollback if transaction rolled back and :savepoint option used" do
|
|
1236
|
+
@db.transaction(:rollback=>:always) do
|
|
1237
|
+
@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}}
|
|
1238
|
+
end
|
|
1239
|
+
@db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_1", "ROLLBACK", "bar"]
|
|
1240
|
+
end
|
|
1241
|
+
|
|
1152
1242
|
it "should raise an error if you attempt to use after_commit inside a savepoint in a prepared transaction" do
|
|
1153
1243
|
@db.define_singleton_method(:supports_prepared_transactions?){true}
|
|
1154
1244
|
proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_commit{@db.execute('foo')}}}}.must_raise(Sequel::Error)
|
|
@@ -2002,6 +2092,18 @@ describe "Database#typecast_value" do
|
|
|
2002
2092
|
proc{@db.typecast_value(:datetime, 4)}.must_raise(Sequel::InvalidValue)
|
|
2003
2093
|
end
|
|
2004
2094
|
|
|
2095
|
+
it "should raise an InvalidValue when given an invalid timezone value" do
|
|
2096
|
+
begin
|
|
2097
|
+
Sequel.default_timezone = :blah
|
|
2098
|
+
proc{@db.typecast_value(:datetime, [2019, 2, 3, 4, 5, 6])}.must_raise(Sequel::InvalidValue)
|
|
2099
|
+
Sequel.datetime_class = DateTime
|
|
2100
|
+
proc{@db.typecast_value(:datetime, [2019, 2, 3, 4, 5, 6])}.must_raise(Sequel::InvalidValue)
|
|
2101
|
+
ensure
|
|
2102
|
+
Sequel.default_timezone = nil
|
|
2103
|
+
Sequel.datetime_class = Time
|
|
2104
|
+
end
|
|
2105
|
+
end
|
|
2106
|
+
|
|
2005
2107
|
it "should handle integers with leading 0 as base 10" do
|
|
2006
2108
|
@db.typecast_value(:integer, "013").must_equal 13
|
|
2007
2109
|
@db.typecast_value(:integer, "08").must_equal 8
|
|
@@ -2246,6 +2348,17 @@ describe "Database#typecast_value" do
|
|
|
2246
2348
|
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14).must_equal Time.local(2011, 10, 11, 12, 13, 14)
|
|
2247
2349
|
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000).must_equal Time.local(2011, 10, 11, 12, 13, 14, 500000)
|
|
2248
2350
|
|
|
2351
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :offset=>Rational(1, 2)).must_equal Time.new(2011, 10, 11, 12, 13, 14, 43200)
|
|
2352
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000, :offset=>Rational(1, 2)).must_equal Time.new(2011, 10, 11, 12, 13, 14.5, 43200)
|
|
2353
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'offset'=>Rational(1, 2)).must_equal Time.new(2011, 10, 11, 12, 13, 14, 43200)
|
|
2354
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000, 'offset'=>Rational(1, 2)).must_equal Time.new(2011, 10, 11, 12, 13, 14.5, 43200)
|
|
2355
|
+
|
|
2356
|
+
Sequel.default_timezone = :utc
|
|
2357
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14).must_equal Time.utc(2011, 10, 11, 12, 13, 14)
|
|
2358
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000).must_equal Time.utc(2011, 10, 11, 12, 13, 14, 500000)
|
|
2359
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14).must_equal Time.utc(2011, 10, 11, 12, 13, 14)
|
|
2360
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000).must_equal Time.utc(2011, 10, 11, 12, 13, 14, 500000)
|
|
2361
|
+
|
|
2249
2362
|
Sequel.datetime_class = DateTime
|
|
2250
2363
|
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14)
|
|
2251
2364
|
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2))
|
|
@@ -2255,8 +2368,16 @@ describe "Database#typecast_value" do
|
|
|
2255
2368
|
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000, :offset=>Rational(1, 2)).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2), Rational(1, 2))
|
|
2256
2369
|
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'offset'=>Rational(1, 2)).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14, Rational(1, 2))
|
|
2257
2370
|
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000, 'offset'=>Rational(1, 2)).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2), Rational(1, 2))
|
|
2371
|
+
|
|
2372
|
+
Sequel.default_timezone = :local
|
|
2373
|
+
offset = Rational(Time.local(2011, 10, 11, 12, 13, 14).utc_offset, 86400)
|
|
2374
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14, offset)
|
|
2375
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2), offset)
|
|
2376
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14, offset)
|
|
2377
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2), offset)
|
|
2258
2378
|
ensure
|
|
2259
2379
|
Sequel.datetime_class = Time
|
|
2380
|
+
Sequel.default_timezone = nil
|
|
2260
2381
|
end
|
|
2261
2382
|
end
|
|
2262
2383
|
|
data/spec/core/dataset_spec.rb
CHANGED
|
@@ -3434,6 +3434,16 @@ describe "Dataset#multi_insert" do
|
|
|
3434
3434
|
'COMMIT']
|
|
3435
3435
|
end
|
|
3436
3436
|
|
|
3437
|
+
it "should handle :return=>:primary_key option if dataset has a row_proc" do
|
|
3438
|
+
@db.autoid = 1
|
|
3439
|
+
@ds.with_row_proc(lambda{|h| Object.new}).multi_insert(@list, :return=>:primary_key).must_equal [1, 2, 3]
|
|
3440
|
+
@db.sqls.must_equal ['BEGIN',
|
|
3441
|
+
"INSERT INTO items (name) VALUES ('abc')",
|
|
3442
|
+
"INSERT INTO items (name) VALUES ('def')",
|
|
3443
|
+
"INSERT INTO items (name) VALUES ('ghi')",
|
|
3444
|
+
'COMMIT']
|
|
3445
|
+
end
|
|
3446
|
+
|
|
3437
3447
|
with_symbol_splitting "should handle splittable symbols for tables" do
|
|
3438
3448
|
@ds = @ds.from(:sch__tab)
|
|
3439
3449
|
@ds.multi_insert(@list)
|
|
@@ -3715,7 +3725,7 @@ end
|
|
|
3715
3725
|
|
|
3716
3726
|
describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #execute" do
|
|
3717
3727
|
before do
|
|
3718
|
-
@db = Sequel.mock(:servers=>{:read_only=>{}}, :autoid=>1)
|
|
3728
|
+
@db = Sequel.mock(:servers=>{:read_only=>{}, :r1=>{}}, :autoid=>1)
|
|
3719
3729
|
@ds = @db[:items]
|
|
3720
3730
|
end
|
|
3721
3731
|
|
|
@@ -3753,6 +3763,18 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #ex
|
|
|
3753
3763
|
@ds.for_update.send(:execute, 'SELECT 1')
|
|
3754
3764
|
@db.sqls.must_equal ["SELECT 1"]
|
|
3755
3765
|
end
|
|
3766
|
+
|
|
3767
|
+
[:execute, :execute_dui, :execute_insert, :execute_ddl].each do |meth|
|
|
3768
|
+
it "##{meth} should respect explicit :server option" do
|
|
3769
|
+
@ds.send(meth, 'SELECT 1', :server=>:r1)
|
|
3770
|
+
@db.sqls.must_equal ["SELECT 1 -- r1"]
|
|
3771
|
+
end
|
|
3772
|
+
|
|
3773
|
+
it "##{meth} should respect dataset's :server option if :server option not given" do
|
|
3774
|
+
@ds.server(:r1).send(meth, 'SELECT 1')
|
|
3775
|
+
@db.sqls.must_equal ["SELECT 1 -- r1"]
|
|
3776
|
+
end
|
|
3777
|
+
end
|
|
3756
3778
|
end
|
|
3757
3779
|
|
|
3758
3780
|
describe "Dataset#with_sql_*" do
|
|
@@ -4483,6 +4505,16 @@ describe "Sequel timezone support" do
|
|
|
4483
4505
|
proc{Sequel.database_to_application_timestamp(Object.new)}.must_raise(Sequel::InvalidValue)
|
|
4484
4506
|
end
|
|
4485
4507
|
|
|
4508
|
+
it "should raise an InvalidValue error when the Time class is used and when a bad application timezone is used when attempting to convert timestamps" do
|
|
4509
|
+
Sequel.application_timezone = :blah
|
|
4510
|
+
proc{Sequel.database_to_application_timestamp('2009-06-01 10:20:30')}.must_raise(Sequel::InvalidValue)
|
|
4511
|
+
end
|
|
4512
|
+
|
|
4513
|
+
it "should raise an InvalidValue error when the Time class is used and when a bad database timezone is used when attempting to convert timestamps" do
|
|
4514
|
+
Sequel.database_timezone = :blah
|
|
4515
|
+
proc{Sequel.database_to_application_timestamp('2009-06-01 10:20:30')}.must_raise(Sequel::InvalidValue)
|
|
4516
|
+
end
|
|
4517
|
+
|
|
4486
4518
|
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
|
|
4487
4519
|
Sequel.application_timezone = :blah
|
|
4488
4520
|
Sequel.datetime_class = DateTime
|
|
@@ -526,11 +526,35 @@ describe "Blockless Ruby Filters" do
|
|
|
526
526
|
dsc.new(@d.db).literal(Sequel.trim(:a)).must_equal 'trimFOO(lower(a))'
|
|
527
527
|
end
|
|
528
528
|
|
|
529
|
-
it "should endless ranges" do
|
|
529
|
+
it "should handle endless ranges" do
|
|
530
530
|
endless = eval('1..')
|
|
531
531
|
@d.l{x =~ endless}.must_equal '(x >= 1)'
|
|
532
532
|
@d.l(:x => endless).must_equal '(x >= 1)'
|
|
533
|
+
|
|
534
|
+
endless = eval('1...')
|
|
535
|
+
@d.l{x =~ endless}.must_equal '(x >= 1)'
|
|
536
|
+
@d.l(:x => endless).must_equal '(x >= 1)'
|
|
533
537
|
end if RUBY_VERSION >= '2.6'
|
|
538
|
+
|
|
539
|
+
it "should handle startless ranges" do
|
|
540
|
+
endless = eval('..1')
|
|
541
|
+
@d.l{x =~ endless}.must_equal '(x <= 1)'
|
|
542
|
+
@d.l(:x => endless).must_equal '(x <= 1)'
|
|
543
|
+
|
|
544
|
+
endless = eval('...1')
|
|
545
|
+
@d.l{x =~ endless}.must_equal '(x < 1)'
|
|
546
|
+
@d.l(:x => endless).must_equal '(x < 1)'
|
|
547
|
+
end if RUBY_VERSION >= '2.7'
|
|
548
|
+
|
|
549
|
+
it "should handle startless, endless ranges" do
|
|
550
|
+
endless = eval('nil..nil')
|
|
551
|
+
@d.l{x =~ endless}.must_equal '(1 = 1)'
|
|
552
|
+
@d.l(:x => endless).must_equal '(1 = 1)'
|
|
553
|
+
|
|
554
|
+
endless = eval('nil...nil')
|
|
555
|
+
@d.l{x =~ endless}.must_equal '(1 = 1)'
|
|
556
|
+
@d.l(:x => endless).must_equal '(1 = 1)'
|
|
557
|
+
end if RUBY_VERSION >= '2.7'
|
|
534
558
|
end
|
|
535
559
|
|
|
536
560
|
describe Sequel::SQL::VirtualRow do
|
data/spec/core/schema_spec.rb
CHANGED
|
@@ -240,6 +240,24 @@ describe "DB#create_table" do
|
|
|
240
240
|
@db.sqls.must_equal ["CREATE TABLE cats (id integer, name text, UNIQUE (name) DEFERRABLE INITIALLY IMMEDIATE)"]
|
|
241
241
|
end
|
|
242
242
|
|
|
243
|
+
it "should handle deferred unique column constraints" do
|
|
244
|
+
@db.create_table(:cats) do
|
|
245
|
+
integer :id, :unique=>true, :unique_deferrable=>true
|
|
246
|
+
integer :i, :unique=>true, :unique_deferrable=>:immediate
|
|
247
|
+
integer :j, :unique=>true, :unique_deferrable=>false
|
|
248
|
+
end
|
|
249
|
+
@db.sqls.must_equal ["CREATE TABLE cats (id integer UNIQUE DEFERRABLE INITIALLY DEFERRED, i integer UNIQUE DEFERRABLE INITIALLY IMMEDIATE, j integer UNIQUE NOT DEFERRABLE)"]
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it "should handle deferred primary key column constraints" do
|
|
253
|
+
@db.create_table(:cats) do
|
|
254
|
+
integer :id, :primary_key=>true, :primary_key_deferrable=>true
|
|
255
|
+
integer :i, :primary_key=>true, :primary_key_deferrable=>:immediate
|
|
256
|
+
integer :j, :primary_key=>true, :primary_key_deferrable=>false
|
|
257
|
+
end
|
|
258
|
+
@db.sqls.must_equal ["CREATE TABLE cats (id integer PRIMARY KEY DEFERRABLE INITIALLY DEFERRED, i integer PRIMARY KEY DEFERRABLE INITIALLY IMMEDIATE, j integer PRIMARY KEY NOT DEFERRABLE)"]
|
|
259
|
+
end
|
|
260
|
+
|
|
243
261
|
it "should accept unsigned definition" do
|
|
244
262
|
@db.create_table(:cats) do
|
|
245
263
|
integer :value, :unsigned => true
|
|
@@ -1777,17 +1795,21 @@ describe "Schema Parser" do
|
|
|
1777
1795
|
@db.schema(:text).first.last[:type].must_equal :string
|
|
1778
1796
|
@db.schema(:date).first.last[:type].must_equal :date
|
|
1779
1797
|
@db.schema(:datetime).first.last[:type].must_equal :datetime
|
|
1798
|
+
@db.schema(:smalldatetime).first.last[:type].must_equal :datetime
|
|
1780
1799
|
@db.schema(:timestamp).first.last[:type].must_equal :datetime
|
|
1781
1800
|
@db.schema(:"timestamp with time zone").first.last[:type].must_equal :datetime
|
|
1782
1801
|
@db.schema(:"timestamp without time zone").first.last[:type].must_equal :datetime
|
|
1783
1802
|
@db.schema(:time).first.last[:type].must_equal :time
|
|
1784
1803
|
@db.schema(:"time with time zone").first.last[:type].must_equal :time
|
|
1785
1804
|
@db.schema(:"time without time zone").first.last[:type].must_equal :time
|
|
1805
|
+
@db.schema(:bool).first.last[:type].must_equal :boolean
|
|
1786
1806
|
@db.schema(:boolean).first.last[:type].must_equal :boolean
|
|
1787
1807
|
@db.schema(:real).first.last[:type].must_equal :float
|
|
1788
1808
|
@db.schema(:float).first.last[:type].must_equal :float
|
|
1809
|
+
@db.schema(:"float unsigned").first.last[:type].must_equal :float
|
|
1789
1810
|
@db.schema(:double).first.last[:type].must_equal :float
|
|
1790
1811
|
@db.schema(:"double(1,2)").first.last[:type].must_equal :float
|
|
1812
|
+
@db.schema(:"double(1,2) unsigned").first.last[:type].must_equal :float
|
|
1791
1813
|
@db.schema(:"double precision").first.last[:type].must_equal :float
|
|
1792
1814
|
@db.schema(:number).first.last[:type].must_equal :decimal
|
|
1793
1815
|
@db.schema(:numeric).first.last[:type].must_equal :decimal
|
|
@@ -1801,6 +1823,8 @@ describe "Schema Parser" do
|
|
|
1801
1823
|
@db.schema(:nchar).first.last[:type].must_equal :string
|
|
1802
1824
|
@db.schema(:nvarchar).first.last[:type].must_equal :string
|
|
1803
1825
|
@db.schema(:ntext).first.last[:type].must_equal :string
|
|
1826
|
+
@db.schema(:clob).first.last[:type].must_equal :string
|
|
1827
|
+
@db.schema(:ntext).first.last[:type].must_equal :string
|
|
1804
1828
|
@db.schema(:smalldatetime).first.last[:type].must_equal :datetime
|
|
1805
1829
|
@db.schema(:binary).first.last[:type].must_equal :blob
|
|
1806
1830
|
@db.schema(:varbinary).first.last[:type].must_equal :blob
|
|
@@ -5,8 +5,8 @@ describe "class_table_inheritance plugin" do
|
|
|
5
5
|
@db = Sequel.mock(:numrows=>1, :autoid=>proc{|sql| 1})
|
|
6
6
|
def @db.supports_schema_parsing?() true end
|
|
7
7
|
def @db.schema(table, opts={})
|
|
8
|
-
{:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
|
|
9
|
-
:managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}] ],
|
|
8
|
+
{:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string, :allow_null=>false}], [:kind, {:type=>:string}]],
|
|
9
|
+
:managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer, :allow_null=>false}] ],
|
|
10
10
|
:executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
|
|
11
11
|
:staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
|
|
12
12
|
}[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
|
|
@@ -23,7 +23,9 @@ describe "class_table_inheritance plugin" do
|
|
|
23
23
|
}[opts[:from] + (opts[:join] || []).map{|x| x.table}]
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
base = Sequel::Model(@db)
|
|
27
|
+
base.plugin :auto_validations if @use_auto_validations
|
|
28
|
+
class ::Employee < base
|
|
27
29
|
def _save_refresh; @values[:id] = 1 end
|
|
28
30
|
def self.columns
|
|
29
31
|
dataset.columns || dataset.opts[:from].first.expression.columns
|
|
@@ -114,6 +116,26 @@ describe "class_table_inheritance plugin" do
|
|
|
114
116
|
"SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id) WHERE (employees.kind IN ('Ceo'))) AS employees WHERE (id = 1) LIMIT 1"]
|
|
115
117
|
end
|
|
116
118
|
|
|
119
|
+
describe "with auto_validations plugin" do
|
|
120
|
+
before(:all) do
|
|
121
|
+
@use_auto_validations = true
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it "should work" do
|
|
125
|
+
e = Employee.new
|
|
126
|
+
e.valid?.must_equal false
|
|
127
|
+
e.errors.must_equal(:name=>["is not present"])
|
|
128
|
+
|
|
129
|
+
e = Manager.new
|
|
130
|
+
e.valid?.must_equal false
|
|
131
|
+
e.errors.must_equal(:name=>["is not present"], :num_staff=>["is not present"])
|
|
132
|
+
|
|
133
|
+
e = Executive.new
|
|
134
|
+
e.valid?.must_equal false
|
|
135
|
+
e.errors.must_equal(:name=>["is not present"], :num_staff=>["is not present"])
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
117
139
|
it "should return rows with the current class if sti_key is nil" do
|
|
118
140
|
Employee.plugin :class_table_inheritance
|
|
119
141
|
Employee.dataset.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}, {:kind=>'Intern'}]).all.map{|x| x.class}.must_equal [Employee, Employee, Employee, Employee, Employee, Employee]
|
|
@@ -232,11 +254,11 @@ describe "class_table_inheritance plugin" do
|
|
|
232
254
|
end
|
|
233
255
|
|
|
234
256
|
it "should include schema for columns for tables for ancestor classes" do
|
|
235
|
-
Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string})
|
|
236
|
-
Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer})
|
|
237
|
-
Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer}, :num_managers=>{:type=>:integer})
|
|
238
|
-
Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :manager_id=>{:type=>:integer})
|
|
239
|
-
Intern.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string})
|
|
257
|
+
Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string})
|
|
258
|
+
Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer, :allow_null=>false})
|
|
259
|
+
Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer, :allow_null=>false}, :num_managers=>{:type=>:integer})
|
|
260
|
+
Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string}, :manager_id=>{:type=>:integer})
|
|
261
|
+
Intern.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string})
|
|
240
262
|
end
|
|
241
263
|
|
|
242
264
|
it "should use the correct primary key (which should have the same name in all subclasses)" do
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require_relative "spec_helper"
|
|
2
2
|
|
|
3
|
-
if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby')
|
|
3
|
+
if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') || (RUBY_ENGINE == 'jruby' && (JRUBY_VERSION >= '9.3' || (JRUBY_VERSION.match(/\A9\.2\.(\d+)/) && $1.to_i >= 7)))
|
|
4
4
|
Sequel.extension :core_refinements, :pg_array, :pg_hstore, :pg_row, :pg_range, :pg_row_ops, :pg_range_ops, :pg_array_ops, :pg_hstore_ops, :pg_json, :pg_json_ops
|
|
5
5
|
using Sequel::CoreRefinements
|
|
6
6
|
|
|
@@ -22,6 +22,28 @@ describe Sequel::Model, "hook_class_methods plugin" do
|
|
|
22
22
|
hooks.values.all?(&:frozen?).must_equal true
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
deprecated ".hook_blocks method should yield each hook block" do
|
|
26
|
+
c = model_class.call Sequel::Model
|
|
27
|
+
a = []
|
|
28
|
+
c.hook_blocks(:before_save){|b| a << b}
|
|
29
|
+
a.must_equal []
|
|
30
|
+
|
|
31
|
+
pr = proc{adds << 'hi'}
|
|
32
|
+
c.before_save(&pr)
|
|
33
|
+
a = []
|
|
34
|
+
c.hook_blocks(:before_save){|b| a << b}
|
|
35
|
+
a.must_equal [pr]
|
|
36
|
+
|
|
37
|
+
c.before_save(&pr)
|
|
38
|
+
a = []
|
|
39
|
+
c.hook_blocks(:before_save){|b| a << b}
|
|
40
|
+
a.must_equal [pr, pr]
|
|
41
|
+
|
|
42
|
+
a = []
|
|
43
|
+
c.hook_blocks(:after_save){|b| a << b}
|
|
44
|
+
a.must_equal []
|
|
45
|
+
end
|
|
46
|
+
|
|
25
47
|
it "should be definable using a block" do
|
|
26
48
|
adds = []
|
|
27
49
|
c = model_class.call Sequel::Model do
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require_relative "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "insert_conflict plugin" do
|
|
4
|
+
def model_class(adapter)
|
|
5
|
+
db = Sequel.mock(:host=>adapter, :fetch=>{:id=>1, :s=>2}, :autoid=>1)
|
|
6
|
+
db.extend_datasets{def quote_identifiers?; false end}
|
|
7
|
+
model = Class.new(Sequel::Model)
|
|
8
|
+
model.dataset = db[:t]
|
|
9
|
+
model.columns :id, :s, :o
|
|
10
|
+
model.plugin :insert_conflict
|
|
11
|
+
db.sqls
|
|
12
|
+
model
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def model_class_plugin_first(adapter)
|
|
16
|
+
model = Class.new(Sequel::Model)
|
|
17
|
+
model.plugin :insert_conflict
|
|
18
|
+
model = Class.new(model)
|
|
19
|
+
db = Sequel.mock(:host=>adapter, :fetch=>{:id=>1, :s=>2}, :autoid=>1)
|
|
20
|
+
db.extend_datasets{def quote_identifiers?; false end}
|
|
21
|
+
model.dataset = db[:t]
|
|
22
|
+
model.columns :id, :s, :o
|
|
23
|
+
db.sqls
|
|
24
|
+
model
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should use INSERT ON CONFLICT when inserting on PostgreSQL" do
|
|
28
|
+
model = model_class(:postgres)
|
|
29
|
+
model.new(:s=>'A', :o=>1).insert_conflict.save
|
|
30
|
+
model.db.sqls.must_equal ["INSERT INTO t (s, o) VALUES ('A', 1) ON CONFLICT DO NOTHING RETURNING *"]
|
|
31
|
+
|
|
32
|
+
model.new(:s=>'A', :o=>1).insert_conflict(:target=>:s, :update => {:o => Sequel[:excluded][:o]}).save
|
|
33
|
+
model.db.sqls.must_equal ["INSERT INTO t (s, o) VALUES ('A', 1) ON CONFLICT (s) DO UPDATE SET o = excluded.o RETURNING *"]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should use INSERT ON CONFLICT when inserting on SQLITE" do
|
|
37
|
+
model = model_class(:sqlite)
|
|
38
|
+
model.new(:s=>'A', :o=>1).insert_conflict.save
|
|
39
|
+
model.db.sqls.must_equal ["INSERT INTO t (s, o) VALUES ('A', 1) ON CONFLICT DO NOTHING",
|
|
40
|
+
"SELECT * FROM t WHERE (id = 1) LIMIT 1"]
|
|
41
|
+
|
|
42
|
+
model.new(:s=>'A', :o=>1).insert_conflict(:target=>:s, :update => {:o => Sequel[:excluded][:o]}).save
|
|
43
|
+
model.db.sqls.must_equal ["INSERT INTO t (s, o) VALUES ('A', 1) ON CONFLICT (s) DO UPDATE SET o = excluded.o",
|
|
44
|
+
"SELECT * FROM t WHERE (id = 2) LIMIT 1"]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should raise Error if calling insert_conflict on a model instance that isn't new" do
|
|
48
|
+
m = model_class(:postgres).load(:s=>'A', :o=>1)
|
|
49
|
+
proc{m.insert_conflict}.must_raise Sequel::Error
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should raise if loading plugin into a model class with a dataset that doesn't support insert_conflict" do
|
|
53
|
+
model = Class.new(Sequel::Model)
|
|
54
|
+
model.dataset = Sequel.mock[:t]
|
|
55
|
+
proc{model.plugin :insert_conflict}.must_raise Sequel::Error
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should work if loading into a model class without a dataset on PostgreSQL" do
|
|
59
|
+
model = model_class_plugin_first(:postgres)
|
|
60
|
+
model.new(:s=>'A', :o=>1).insert_conflict.save
|
|
61
|
+
model.db.sqls.must_equal ["INSERT INTO t (s, o) VALUES ('A', 1) ON CONFLICT DO NOTHING RETURNING *"]
|
|
62
|
+
|
|
63
|
+
model.new(:s=>'A', :o=>1).insert_conflict(:target=>:s, :update => {:o => Sequel[:excluded][:o]}).save
|
|
64
|
+
model.db.sqls.must_equal ["INSERT INTO t (s, o) VALUES ('A', 1) ON CONFLICT (s) DO UPDATE SET o = excluded.o RETURNING *"]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should work if loading into a model class without a dataset on SQLITE" do
|
|
68
|
+
model = model_class_plugin_first(:sqlite)
|
|
69
|
+
model.new(:s=>'A', :o=>1).insert_conflict.save
|
|
70
|
+
model.db.sqls.must_equal ["INSERT INTO t (s, o) VALUES ('A', 1) ON CONFLICT DO NOTHING",
|
|
71
|
+
"SELECT * FROM t WHERE (id = 1) LIMIT 1"]
|
|
72
|
+
|
|
73
|
+
model.new(:s=>'A', :o=>1).insert_conflict(:target=>:s, :update => {:o => Sequel[:excluded][:o]}).save
|
|
74
|
+
model.db.sqls.must_equal ["INSERT INTO t (s, o) VALUES ('A', 1) ON CONFLICT (s) DO UPDATE SET o = excluded.o",
|
|
75
|
+
"SELECT * FROM t WHERE (id = 2) LIMIT 1"]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should work if the prepared_statements plugin is loaded before" do
|
|
79
|
+
db = Sequel.mock(:host=>'sqlite', :fetch=>{:id=>1, :s=>2}, :autoid=>1, :numrows=>1)
|
|
80
|
+
db.extend_datasets{def quote_identifiers?; false end}
|
|
81
|
+
model = Class.new(Sequel::Model)
|
|
82
|
+
model.dataset = db[:t]
|
|
83
|
+
model.columns :id, :s
|
|
84
|
+
model.plugin :prepared_statements
|
|
85
|
+
model.plugin :insert_conflict
|
|
86
|
+
db.sqls
|
|
87
|
+
model.create(:s=>'a').update(:s=>'b')
|
|
88
|
+
db.sqls.must_equal ["INSERT INTO t (s) VALUES ('a')", "SELECT * FROM t WHERE (id = 1) LIMIT 1", "UPDATE t SET s = 'b' WHERE (id = 1)"]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "should work if the prepared_statements plugin is loaded after" do
|
|
92
|
+
db = Sequel.mock(:host=>'postgres', :fetch=>{:id=>1, :s=>2}, :autoid=>1, :numrows=>1)
|
|
93
|
+
db.extend_datasets{def quote_identifiers?; false end}
|
|
94
|
+
model = Class.new(Sequel::Model)
|
|
95
|
+
model.dataset = db[:t]
|
|
96
|
+
model.columns :id, :s
|
|
97
|
+
model.plugin :insert_conflict
|
|
98
|
+
model.plugin :prepared_statements
|
|
99
|
+
db.sqls
|
|
100
|
+
model.create(:s=>'a').update(:s=>'b')
|
|
101
|
+
db.sqls.must_equal ["INSERT INTO t (s) VALUES ('a') RETURNING *", "UPDATE t SET s = 'b' WHERE (id = 1)"]
|
|
102
|
+
end
|
|
103
|
+
end
|