sequel 3.46.0 → 3.47.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +96 -0
- data/Rakefile +7 -1
- data/bin/sequel +6 -4
- data/doc/active_record.rdoc +1 -1
- data/doc/advanced_associations.rdoc +14 -35
- data/doc/association_basics.rdoc +66 -4
- data/doc/migration.rdoc +4 -0
- data/doc/opening_databases.rdoc +6 -0
- data/doc/postgresql.rdoc +302 -0
- data/doc/release_notes/3.47.0.txt +270 -0
- data/doc/security.rdoc +6 -0
- data/lib/sequel/adapters/ibmdb.rb +9 -9
- data/lib/sequel/adapters/jdbc.rb +22 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +7 -2
- data/lib/sequel/adapters/mock.rb +2 -0
- data/lib/sequel/adapters/postgres.rb +44 -13
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/adapters/shared/mysql.rb +2 -2
- data/lib/sequel/adapters/shared/postgres.rb +94 -55
- data/lib/sequel/adapters/shared/sqlite.rb +3 -1
- data/lib/sequel/adapters/sqlite.rb +2 -2
- data/lib/sequel/adapters/utils/pg_types.rb +1 -14
- data/lib/sequel/adapters/utils/split_alter_table.rb +3 -3
- data/lib/sequel/connection_pool/threaded.rb +1 -1
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/connecting.rb +2 -2
- data/lib/sequel/database/features.rb +5 -0
- data/lib/sequel/database/misc.rb +47 -5
- data/lib/sequel/database/query.rb +2 -2
- data/lib/sequel/dataset/actions.rb +4 -2
- data/lib/sequel/dataset/misc.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +1 -1
- data/lib/sequel/dataset/query.rb +8 -6
- data/lib/sequel/dataset/sql.rb +8 -6
- data/lib/sequel/extensions/constraint_validations.rb +5 -2
- data/lib/sequel/extensions/migration.rb +10 -8
- data/lib/sequel/extensions/pagination.rb +3 -0
- data/lib/sequel/extensions/pg_array.rb +85 -25
- data/lib/sequel/extensions/pg_hstore.rb +8 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +4 -1
- data/lib/sequel/extensions/pg_inet.rb +16 -13
- data/lib/sequel/extensions/pg_interval.rb +6 -2
- data/lib/sequel/extensions/pg_json.rb +18 -11
- data/lib/sequel/extensions/pg_range.rb +17 -2
- data/lib/sequel/extensions/pg_range_ops.rb +7 -5
- data/lib/sequel/extensions/pg_row.rb +29 -12
- data/lib/sequel/extensions/pretty_table.rb +3 -0
- data/lib/sequel/extensions/query.rb +3 -0
- data/lib/sequel/extensions/schema_caching.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +3 -1
- data/lib/sequel/extensions/select_remove.rb +3 -0
- data/lib/sequel/model.rb +8 -2
- data/lib/sequel/model/associations.rb +39 -27
- data/lib/sequel/model/base.rb +99 -38
- data/lib/sequel/model/plugins.rb +25 -0
- data/lib/sequel/plugins/association_autoreloading.rb +27 -22
- data/lib/sequel/plugins/association_dependencies.rb +1 -7
- data/lib/sequel/plugins/auto_validations.rb +110 -0
- data/lib/sequel/plugins/boolean_readers.rb +1 -6
- data/lib/sequel/plugins/caching.rb +6 -13
- data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
- data/lib/sequel/plugins/composition.rb +14 -7
- data/lib/sequel/plugins/constraint_validations.rb +2 -13
- data/lib/sequel/plugins/defaults_setter.rb +1 -6
- data/lib/sequel/plugins/dirty.rb +8 -0
- data/lib/sequel/plugins/error_splitter.rb +54 -0
- data/lib/sequel/plugins/force_encoding.rb +1 -5
- data/lib/sequel/plugins/hook_class_methods.rb +1 -6
- data/lib/sequel/plugins/input_transformer.rb +79 -0
- data/lib/sequel/plugins/instance_filters.rb +7 -1
- data/lib/sequel/plugins/instance_hooks.rb +7 -1
- data/lib/sequel/plugins/json_serializer.rb +5 -10
- data/lib/sequel/plugins/lazy_attributes.rb +20 -7
- data/lib/sequel/plugins/list.rb +1 -6
- data/lib/sequel/plugins/many_through_many.rb +1 -2
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +23 -39
- data/lib/sequel/plugins/optimistic_locking.rb +1 -5
- data/lib/sequel/plugins/pg_row.rb +4 -2
- data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -7
- data/lib/sequel/plugins/prepared_statements.rb +1 -5
- data/lib/sequel/plugins/prepared_statements_safe.rb +2 -11
- data/lib/sequel/plugins/rcte_tree.rb +2 -2
- data/lib/sequel/plugins/serialization.rb +11 -13
- data/lib/sequel/plugins/serialization_modification_detection.rb +13 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/static_cache.rb +67 -19
- data/lib/sequel/plugins/string_stripper.rb +7 -27
- data/lib/sequel/plugins/subclasses.rb +3 -5
- data/lib/sequel/plugins/tactical_eager_loading.rb +2 -2
- data/lib/sequel/plugins/timestamps.rb +2 -7
- data/lib/sequel/plugins/touch.rb +5 -8
- data/lib/sequel/plugins/tree.rb +1 -6
- data/lib/sequel/plugins/typecast_on_load.rb +1 -5
- data/lib/sequel/plugins/update_primary_key.rb +26 -14
- data/lib/sequel/plugins/validation_class_methods.rb +31 -16
- data/lib/sequel/plugins/validation_helpers.rb +50 -26
- data/lib/sequel/plugins/xml_serializer.rb +3 -6
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +131 -15
- data/spec/adapters/sqlite_spec.rb +1 -1
- data/spec/core/connection_pool_spec.rb +16 -17
- data/spec/core/database_spec.rb +111 -40
- data/spec/core/dataset_spec.rb +65 -74
- data/spec/core/expression_filters_spec.rb +6 -5
- data/spec/core/object_graph_spec.rb +0 -1
- data/spec/core/schema_spec.rb +23 -23
- data/spec/core/spec_helper.rb +5 -1
- data/spec/extensions/association_dependencies_spec.rb +1 -1
- data/spec/extensions/association_proxies_spec.rb +1 -1
- data/spec/extensions/auto_validations_spec.rb +90 -0
- data/spec/extensions/caching_spec.rb +6 -0
- data/spec/extensions/class_table_inheritance_spec.rb +8 -1
- data/spec/extensions/composition_spec.rb +12 -5
- data/spec/extensions/constraint_validations_spec.rb +4 -4
- data/spec/extensions/core_refinements_spec.rb +29 -79
- data/spec/extensions/dirty_spec.rb +14 -0
- data/spec/extensions/error_splitter_spec.rb +18 -0
- data/spec/extensions/identity_map_spec.rb +0 -1
- data/spec/extensions/input_transformer_spec.rb +54 -0
- data/spec/extensions/instance_filters_spec.rb +6 -0
- data/spec/extensions/instance_hooks_spec.rb +12 -1
- data/spec/extensions/json_serializer_spec.rb +0 -1
- data/spec/extensions/lazy_attributes_spec.rb +64 -55
- data/spec/extensions/looser_typecasting_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +3 -4
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +53 -15
- data/spec/extensions/migration_spec.rb +16 -0
- data/spec/extensions/null_dataset_spec.rb +1 -1
- data/spec/extensions/pg_array_spec.rb +48 -1
- data/spec/extensions/pg_hstore_ops_spec.rb +10 -2
- data/spec/extensions/pg_hstore_spec.rb +5 -0
- data/spec/extensions/pg_inet_spec.rb +5 -0
- data/spec/extensions/pg_interval_spec.rb +7 -3
- data/spec/extensions/pg_json_spec.rb +6 -1
- data/spec/extensions/pg_range_ops_spec.rb +4 -1
- data/spec/extensions/pg_range_spec.rb +5 -0
- data/spec/extensions/pg_row_plugin_spec.rb +13 -0
- data/spec/extensions/pg_row_spec.rb +28 -19
- data/spec/extensions/pg_typecast_on_load_spec.rb +6 -1
- data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
- data/spec/extensions/query_literals_spec.rb +1 -1
- data/spec/extensions/rcte_tree_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +2 -2
- data/spec/extensions/serialization_modification_detection_spec.rb +8 -0
- data/spec/extensions/serialization_spec.rb +15 -1
- data/spec/extensions/sharding_spec.rb +1 -1
- data/spec/extensions/single_table_inheritance_spec.rb +1 -1
- data/spec/extensions/static_cache_spec.rb +59 -9
- data/spec/extensions/tactical_eager_loading_spec.rb +19 -4
- data/spec/extensions/update_primary_key_spec.rb +17 -1
- data/spec/extensions/validation_class_methods_spec.rb +25 -0
- data/spec/extensions/validation_helpers_spec.rb +59 -3
- data/spec/integration/associations_test.rb +5 -5
- data/spec/integration/eager_loader_test.rb +32 -63
- data/spec/integration/model_test.rb +2 -2
- data/spec/integration/plugin_test.rb +88 -56
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/schema_test.rb +1 -1
- data/spec/integration/timezone_test.rb +0 -1
- data/spec/integration/transaction_test.rb +0 -1
- data/spec/model/association_reflection_spec.rb +1 -1
- data/spec/model/associations_spec.rb +106 -84
- data/spec/model/base_spec.rb +4 -4
- data/spec/model/eager_loading_spec.rb +8 -8
- data/spec/model/model_spec.rb +27 -9
- data/spec/model/plugins_spec.rb +71 -0
- data/spec/model/record_spec.rb +99 -13
- metadata +12 -2
@@ -66,7 +66,7 @@ describe "constraint_validations extension" do
|
|
66
66
|
@db.sqls.should == ["DELETE FROM cv WHERE (table = 'foo')"]
|
67
67
|
end
|
68
68
|
|
69
|
-
it "should raise an error without deleting if attempting to drop validations
|
69
|
+
it "should raise an error without deleting if attempting to drop validations without table, column, or constraint" do
|
70
70
|
proc{@db.drop_constraint_validations_for({})}.should raise_error(Sequel::Error)
|
71
71
|
@db.sqls.should == []
|
72
72
|
end
|
@@ -97,7 +97,7 @@ describe "constraint_validations extension" do
|
|
97
97
|
@db.create_table(:foo){String :name; validate{presence :name, :allow_nil=>true}}
|
98
98
|
sqls = @db.sqls
|
99
99
|
parse_insert(sqls.slice!(1)).should == {:validation_type=>"presence", :column=>"name", :table=>"foo", :allow_nil=>'t'}
|
100
|
-
sqls.should == ["BEGIN", "COMMIT", "CREATE TABLE foo (name varchar(255), CHECK (trim(name) != ''))"]
|
100
|
+
sqls.should == ["BEGIN", "COMMIT", "CREATE TABLE foo (name varchar(255), CHECK ((name IS NULL) OR (trim(name) != '')))"]
|
101
101
|
end
|
102
102
|
|
103
103
|
it "should handle :name option when adding validations" do
|
@@ -193,7 +193,7 @@ describe "constraint_validations extension" do
|
|
193
193
|
it "should support :format constraint validation" do
|
194
194
|
@db = Sequel.mock(:host=>'postgres')
|
195
195
|
@db.extension(:constraint_validations)
|
196
|
-
@db.create_table(:foo){String :name; validate{format
|
196
|
+
@db.create_table(:foo){String :name; validate{format(/^foo.*/, :name)}}
|
197
197
|
sqls = @db.sqls
|
198
198
|
parse_insert(sqls.slice!(1)).should == {:validation_type=>"format", :column=>"name", :table=>"foo", :argument=>'^foo.*'}
|
199
199
|
sqls.should == ["BEGIN", "COMMIT", "CREATE TABLE foo (name text, CHECK ((name IS NOT NULL) AND (name ~ '^foo.*')))"]
|
@@ -202,7 +202,7 @@ describe "constraint_validations extension" do
|
|
202
202
|
it "should support :format constraint validation with case insensitive format" do
|
203
203
|
@db = Sequel.mock(:host=>'postgres')
|
204
204
|
@db.extension(:constraint_validations)
|
205
|
-
@db.create_table(:foo){String :name; validate{format
|
205
|
+
@db.create_table(:foo){String :name; validate{format(/^foo.*/i, :name)}}
|
206
206
|
sqls = @db.sqls
|
207
207
|
parse_insert(sqls.slice!(1)).should == {:validation_type=>"iformat", :column=>"name", :table=>"foo", :argument=>'^foo.*'}
|
208
208
|
sqls.should == ["BEGIN", "COMMIT", "CREATE TABLE foo (name text, CHECK ((name IS NOT NULL) AND (name ~* '^foo.*')))"]
|
@@ -16,45 +16,6 @@ describe "Core refinements" do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
if RUBY_VERSION < '1.9.0'
|
20
|
-
it "should not allow inequality operations on true, false, or nil" do
|
21
|
-
@d.lit(:x > 1).should == "(x > 1)"
|
22
|
-
@d.lit(:x < true).should == "(x < 't')"
|
23
|
-
@d.lit(:x >= false).should == "(x >= 'f')"
|
24
|
-
@d.lit(:x <= nil).should == "(x <= NULL)"
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should not allow inequality operations on boolean complex expressions" do
|
28
|
-
@d.lit(:x > (:y > 5)).should == "(x > (y > 5))"
|
29
|
-
@d.lit(:x < (:y < 5)).should == "(x < (y < 5))"
|
30
|
-
@d.lit(:x >= (:y >= 5)).should == "(x >= (y >= 5))"
|
31
|
-
@d.lit(:x <= (:y <= 5)).should == "(x <= (y <= 5))"
|
32
|
-
@d.lit(:x > {:y => nil}).should == "(x > (y IS NULL))"
|
33
|
-
@d.lit(:x < ~{:y => nil}).should == "(x < (y IS NOT NULL))"
|
34
|
-
@d.lit(:x >= {:y => 5}).should == "(x >= (y = 5))"
|
35
|
-
@d.lit(:x <= ~{:y => 5}).should == "(x <= (y != 5))"
|
36
|
-
@d.lit(:x >= {:y => [1,2,3]}).should == "(x >= (y IN (1, 2, 3)))"
|
37
|
-
@d.lit(:x <= ~{:y => [1,2,3]}).should == "(x <= (y NOT IN (1, 2, 3)))"
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should support >, <, >=, and <= via Symbol#>,<,>=,<=" do
|
41
|
-
@d.l(:x > 100).should == '(x > 100)'
|
42
|
-
@d.l(:x < 100.01).should == '(x < 100.01)'
|
43
|
-
@d.l(:x >= 100000000000000000000000000000000000).should == '(x >= 100000000000000000000000000000000000)'
|
44
|
-
@d.l(:x <= 100).should == '(x <= 100)'
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should support negation of >, <, >=, and <= via Symbol#~" do
|
48
|
-
@d.l(~(:x > 100)).should == '(x <= 100)'
|
49
|
-
@d.l(~(:x < 100.01)).should == '(x >= 100.01)'
|
50
|
-
@d.l(~(:x >= 100000000000000000000000000000000000)).should == '(x < 100000000000000000000000000000000000)'
|
51
|
-
@d.l(~(:x <= 100)).should == '(x > 100)'
|
52
|
-
end
|
53
|
-
|
54
|
-
it "should support double negation via ~" do
|
55
|
-
@d.l(~~(:x > 100)).should == '(x > 100)'
|
56
|
-
end
|
57
|
-
end
|
58
19
|
it "should support NOT via Symbol#~" do
|
59
20
|
@d.l(~:x).should == 'NOT x'
|
60
21
|
@d.l(~:x__y).should == 'NOT x.y'
|
@@ -221,7 +182,7 @@ end
|
|
221
182
|
|
222
183
|
describe "String#lit" do
|
223
184
|
before do
|
224
|
-
@ds =
|
185
|
+
@ds = Sequel::Database.new[:t]
|
225
186
|
end
|
226
187
|
|
227
188
|
specify "should return an LiteralString object" do
|
@@ -274,13 +235,13 @@ describe "#desc" do
|
|
274
235
|
end
|
275
236
|
|
276
237
|
specify "should format a DESC clause for a column ref" do
|
277
|
-
:test.desc
|
238
|
+
@ds.literal(:test.desc).should == 'test DESC'
|
278
239
|
|
279
|
-
:items__price.desc
|
240
|
+
@ds.literal(:items__price.desc).should == 'items.price DESC'
|
280
241
|
end
|
281
242
|
|
282
243
|
specify "should format a DESC clause for a function" do
|
283
|
-
:avg.sql_function(:test).desc
|
244
|
+
@ds.literal(:avg.sql_function(:test).desc).should == 'avg(test) DESC'
|
284
245
|
end
|
285
246
|
end
|
286
247
|
|
@@ -290,13 +251,13 @@ describe "#asc" do
|
|
290
251
|
end
|
291
252
|
|
292
253
|
specify "should format a ASC clause for a column ref" do
|
293
|
-
:test.asc
|
254
|
+
@ds.literal(:test.asc).should == 'test ASC'
|
294
255
|
|
295
|
-
:items__price.asc
|
256
|
+
@ds.literal(:items__price.asc).should == 'items.price ASC'
|
296
257
|
end
|
297
258
|
|
298
259
|
specify "should format a ASC clause for a function" do
|
299
|
-
:avg.sql_function(:test).asc
|
260
|
+
@ds.literal(:avg.sql_function(:test).asc).should == 'avg(test) ASC'
|
300
261
|
end
|
301
262
|
end
|
302
263
|
|
@@ -306,17 +267,17 @@ describe "#as" do
|
|
306
267
|
end
|
307
268
|
|
308
269
|
specify "should format a AS clause for a column ref" do
|
309
|
-
:test.as(:t)
|
270
|
+
@ds.literal(:test.as(:t)).should == 'test AS t'
|
310
271
|
|
311
|
-
:items__price.as(:p)
|
272
|
+
@ds.literal(:items__price.as(:p)).should == 'items.price AS p'
|
312
273
|
end
|
313
274
|
|
314
275
|
specify "should format a AS clause for a function" do
|
315
|
-
:avg.sql_function(:test).as(:avg)
|
276
|
+
@ds.literal(:avg.sql_function(:test).as(:avg)).should == 'avg(test) AS avg'
|
316
277
|
end
|
317
278
|
|
318
279
|
specify "should format a AS clause for a literal value" do
|
319
|
-
'abc'.as(:abc)
|
280
|
+
@ds.literal('abc'.as(:abc)).should == "'abc' AS abc"
|
320
281
|
end
|
321
282
|
end
|
322
283
|
|
@@ -364,34 +325,23 @@ describe "Blob" do
|
|
364
325
|
end
|
365
326
|
end
|
366
327
|
|
367
|
-
if RUBY_VERSION < '1.9.0'
|
368
|
-
describe "Symbol#[]" do
|
369
|
-
specify "should format an SQL Function" do
|
370
|
-
ds = Sequel::Dataset.new(nil)
|
371
|
-
ds.literal(:xyz[]).should == 'xyz()'
|
372
|
-
ds.literal(:xyz[1]).should == 'xyz(1)'
|
373
|
-
ds.literal(:xyz[1, 2, :abc[3]]).should == 'xyz(1, 2, abc(3))'
|
374
|
-
end
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
328
|
describe "Symbol#*" do
|
379
329
|
before do
|
380
330
|
@ds = Sequel::Dataset.new(nil)
|
381
331
|
end
|
382
332
|
|
383
333
|
specify "should format a qualified wildcard if no argument" do
|
384
|
-
:xyz
|
385
|
-
:abc
|
334
|
+
@ds.literal(:xyz.*).should == 'xyz.*'
|
335
|
+
@ds.literal(:abc.*).should == 'abc.*'
|
386
336
|
end
|
387
337
|
|
388
338
|
specify "should format a filter expression if an argument" do
|
389
|
-
:xyz.*(3)
|
390
|
-
:abc.*(5)
|
339
|
+
@ds.literal(:xyz.*(3)).should == '(xyz * 3)'
|
340
|
+
@ds.literal(:abc.*(5)).should == '(abc * 5)'
|
391
341
|
end
|
392
342
|
|
393
343
|
specify "should support qualified symbols if no argument" do
|
394
|
-
:xyz__abc
|
344
|
+
@ds.literal(:xyz__abc.*).should == 'xyz.abc.*'
|
395
345
|
end
|
396
346
|
end
|
397
347
|
|
@@ -445,12 +395,12 @@ describe "Symbol" do
|
|
445
395
|
end
|
446
396
|
|
447
397
|
specify "should support sql_function method" do
|
448
|
-
:COUNT.sql_function('1')
|
398
|
+
@ds.literal(:COUNT.sql_function('1')).should == "COUNT('1')"
|
449
399
|
@ds.select(:COUNT.sql_function('1')).sql.should == "SELECT COUNT('1')"
|
450
400
|
end
|
451
401
|
|
452
402
|
specify "should support cast method" do
|
453
|
-
:abc.cast(:integer)
|
403
|
+
@ds.literal(:abc.cast(:integer)).should == "CAST(abc AS integer)"
|
454
404
|
end
|
455
405
|
|
456
406
|
specify "should support sql array accesses via sql_subscript" do
|
@@ -463,19 +413,19 @@ describe "Symbol" do
|
|
463
413
|
specify "should support cast_numeric and cast_string" do
|
464
414
|
x = :abc.cast_numeric
|
465
415
|
x.should be_a_kind_of(Sequel::SQL::NumericExpression)
|
466
|
-
|
416
|
+
@ds.literal(x).should == "CAST(abc AS integer)"
|
467
417
|
|
468
418
|
x = :abc.cast_numeric(:real)
|
469
419
|
x.should be_a_kind_of(Sequel::SQL::NumericExpression)
|
470
|
-
|
420
|
+
@ds.literal(x).should == "CAST(abc AS real)"
|
471
421
|
|
472
422
|
x = :abc.cast_string
|
473
423
|
x.should be_a_kind_of(Sequel::SQL::StringExpression)
|
474
|
-
|
424
|
+
@ds.literal(x).should == "CAST(abc AS varchar(255))"
|
475
425
|
|
476
426
|
x = :abc.cast_string(:varchar)
|
477
427
|
x.should be_a_kind_of(Sequel::SQL::StringExpression)
|
478
|
-
|
428
|
+
@ds.literal(x).should == "CAST(abc AS varchar(255))"
|
479
429
|
end
|
480
430
|
|
481
431
|
specify "should allow database independent types when casting" do
|
@@ -485,16 +435,16 @@ describe "Symbol" do
|
|
485
435
|
return :bar if type == String
|
486
436
|
type
|
487
437
|
end
|
488
|
-
:abc.cast(String)
|
489
|
-
:abc.cast(String)
|
490
|
-
:abc.cast_string
|
491
|
-
:abc.cast_string(Integer)
|
492
|
-
:abc.cast_numeric
|
493
|
-
:abc.cast_numeric(String)
|
438
|
+
@ds.literal(:abc.cast(String)).should == "CAST(abc AS bar)"
|
439
|
+
@ds.literal(:abc.cast(String)).should == "CAST(abc AS bar)"
|
440
|
+
@ds.literal(:abc.cast_string).should == "CAST(abc AS bar)"
|
441
|
+
@ds.literal(:abc.cast_string(Integer)).should == "CAST(abc AS foo)"
|
442
|
+
@ds.literal(:abc.cast_numeric).should == "CAST(abc AS foo)"
|
443
|
+
@ds.literal(:abc.cast_numeric(String)).should == "CAST(abc AS bar)"
|
494
444
|
end
|
495
445
|
|
496
446
|
specify "should support SQL EXTRACT function via #extract " do
|
497
|
-
:abc.extract(:year)
|
447
|
+
@ds.literal(:abc.extract(:year)).should == "extract(year FROM abc)"
|
498
448
|
end
|
499
449
|
end
|
500
450
|
|
@@ -121,6 +121,12 @@ describe "Sequel::Plugins::Dirty" do
|
|
121
121
|
o.column_change(:initial).should == [v, 'a']
|
122
122
|
end
|
123
123
|
end
|
124
|
+
|
125
|
+
it "should work when freezing objects" do
|
126
|
+
@o.freeze
|
127
|
+
@o.initial_value(:initial).should == 'i'
|
128
|
+
proc{@o.initial = 'b'}.should raise_error
|
129
|
+
end
|
124
130
|
end
|
125
131
|
|
126
132
|
describe "with new instance" do
|
@@ -158,5 +164,13 @@ describe "Sequel::Plugins::Dirty" do
|
|
158
164
|
@o.save
|
159
165
|
@o.previous_changes.should == {:initial_changed=>['ic', 'ic2'], :missing_changed=>[nil, 'mc2']}
|
160
166
|
end
|
167
|
+
|
168
|
+
it "should work when freezing objects after saving" do
|
169
|
+
@o.initial = 'a'
|
170
|
+
@o.save
|
171
|
+
@o.freeze
|
172
|
+
@o.previous_changes[:initial].should == ['i', 'a']
|
173
|
+
proc{@o.initial = 'b'}.should raise_error
|
174
|
+
end
|
161
175
|
end
|
162
176
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Plugins::ErrorSplitter" do
|
4
|
+
before do
|
5
|
+
@c = Class.new(Sequel::Model)
|
6
|
+
@c.plugin :error_splitter
|
7
|
+
@m = @c.new
|
8
|
+
def @m.validate
|
9
|
+
errors.add([:a, :b], 'is bad')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should split errors for multiple columns and assign them to each column" do
|
14
|
+
@m.valid?.should be_false
|
15
|
+
@m.errors.should == {:a=>['is bad'], :b=>['is bad']}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -183,7 +183,6 @@ describe "Sequel::Plugins::IdentityMap" do
|
|
183
183
|
end
|
184
184
|
|
185
185
|
it "should not use the identity map as a lookup cache for a one_to_one association" do
|
186
|
-
c = @c2
|
187
186
|
@c2.one_to_one :artist, :class=>@c1, :key=>:artist_id
|
188
187
|
@c.with_identity_map do
|
189
188
|
MODEL_DB.sqls.length.should == 0
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Plugins::InputTransformer" do
|
4
|
+
before do
|
5
|
+
@c = Class.new(Sequel::Model)
|
6
|
+
@c.columns :name, :b
|
7
|
+
@c.plugin(:input_transformer, :reverser){|v| v.is_a?(String) ? v.reverse : v}
|
8
|
+
@o = @c.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should apply transformation to input" do
|
12
|
+
@o.name = ' name '
|
13
|
+
@o.name.should == ' eman '
|
14
|
+
@o.name = [1, 2, 3]
|
15
|
+
@o.name.should == [1, 2, 3]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should not apply any transformers by default" do
|
19
|
+
c = Class.new(Sequel::Model)
|
20
|
+
c.columns :name, :b
|
21
|
+
c.plugin :input_transformer
|
22
|
+
c.new(:name => ' name ').name.should == ' name '
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should allow skipping of columns using .skip_input_transformer" do
|
26
|
+
@c.skip_input_transformer :reverser, :name
|
27
|
+
v = ' name '
|
28
|
+
@o.name = v
|
29
|
+
@o.name.should equal(v)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should work correctly in subclasses" do
|
33
|
+
o = Class.new(@c).new
|
34
|
+
o.name = ' name '
|
35
|
+
o.name.should == ' eman '
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should raise an error if adding input filter without name" do
|
39
|
+
proc{@c.add_input_transformer(nil){}}.should raise_error(Sequel::Error)
|
40
|
+
proc{@c.plugin(:input_transformer){}}.should raise_error(Sequel::Error)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should raise an error if adding input filter without block" do
|
44
|
+
proc{@c.add_input_transformer(:foo)}.should raise_error(Sequel::Error)
|
45
|
+
proc{@c.plugin(:input_transformer, :foo)}.should raise_error(Sequel::Error)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should apply multiple input transformers in reverse order of their call" do
|
49
|
+
@c.add_input_transformer(:add_bar){|v| v << 'bar'}
|
50
|
+
@c.add_input_transformer(:add_foo){|v| v << 'foo'}
|
51
|
+
@o.name = ' name '
|
52
|
+
@o.name.should == 'raboof eman '
|
53
|
+
end
|
54
|
+
end
|
@@ -42,4 +42,10 @@ describe "instance_filters plugin" do
|
|
42
42
|
@p.update(:name=>'Bob')
|
43
43
|
MODEL_DB.sqls.should == ["UPDATE people SET name = 'Bob' WHERE (id = 1)"]
|
44
44
|
end
|
45
|
+
|
46
|
+
specify "shouldn't allow instance filters on frozen objects" do
|
47
|
+
@p.instance_filter(:name=>'Joe')
|
48
|
+
@p.freeze
|
49
|
+
proc{@p.instance_filter(:name=>'Jim')}.should raise_error
|
50
|
+
end
|
45
51
|
end
|
@@ -176,12 +176,23 @@ describe "InstanceHooks plugin" do
|
|
176
176
|
@x.save.should_not == nil
|
177
177
|
@r.should == [2, 1, 4, 3]
|
178
178
|
end
|
179
|
+
|
180
|
+
it "should not allow addition of instance hooks to frozen instances" do
|
181
|
+
@x.after_destroy_hook{r 1}
|
182
|
+
@x.before_destroy_hook{r 2}
|
183
|
+
@x.before_update_hook{r 3}
|
184
|
+
@x.before_save_hook{r 4}
|
185
|
+
@x.freeze
|
186
|
+
proc{@x.after_destroy_hook{r 1}}.should raise_error(Sequel::Error)
|
187
|
+
proc{@x.before_destroy_hook{r 2}}.should raise_error(Sequel::Error)
|
188
|
+
proc{@x.before_update_hook{r 3}}.should raise_error(Sequel::Error)
|
189
|
+
proc{@x.before_save_hook{r 4}}.should raise_error(Sequel::Error)
|
190
|
+
end
|
179
191
|
end
|
180
192
|
|
181
193
|
describe "InstanceHooks plugin with transactions" do
|
182
194
|
before do
|
183
195
|
@db = Sequel.mock(:numrows=>1)
|
184
|
-
pr = proc{|x| r(x)}
|
185
196
|
@c = Class.new(Sequel::Model(@db[:items])) do
|
186
197
|
attr_accessor :rb
|
187
198
|
def after_save
|
@@ -182,7 +182,6 @@ describe "Sequel::Plugins::JsonSerializer" do
|
|
182
182
|
end
|
183
183
|
|
184
184
|
it "should have dataset to_json method work with naked datasets" do
|
185
|
-
album = @album
|
186
185
|
ds = Album.dataset.naked
|
187
186
|
ds._fetch = {:id=>1, :name=>'RF', :artist_id=>2}
|
188
187
|
Sequel.parse_json(ds.to_json).should == [@album.values.inject({}){|h, (k, v)| h[k.to_s] = v; h}]
|
@@ -68,17 +68,13 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
68
68
|
m.name.should == '1'
|
69
69
|
end
|
70
70
|
|
71
|
-
it "should
|
72
|
-
@c.
|
73
|
-
|
74
|
-
|
75
|
-
m.name.should == '1'
|
76
|
-
m.values.should == {:id=>1, :name=>'1'}
|
77
|
-
@db.sqls.should == ['SELECT id FROM la LIMIT 1', 'SELECT name FROM la WHERE (id = 1) LIMIT 1']
|
78
|
-
end
|
71
|
+
it "should raise error if the model has no primary key" do
|
72
|
+
m = @c.first
|
73
|
+
@c.no_primary_key
|
74
|
+
proc{m.name}.should raise_error(Sequel::Error)
|
79
75
|
end
|
80
76
|
|
81
|
-
it "should lazily load the attribute for a single model object
|
77
|
+
it "should lazily load the attribute for a single model object" do
|
82
78
|
m = @c.first
|
83
79
|
m.values.should == {:id=>1}
|
84
80
|
m.name.should == '1'
|
@@ -86,34 +82,47 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
86
82
|
@db.sqls.should == ['SELECT id FROM la LIMIT 1', 'SELECT name FROM la WHERE (id = 1) LIMIT 1']
|
87
83
|
end
|
88
84
|
|
85
|
+
it "should lazily load the attribute for a frozen model object" do
|
86
|
+
m = @c.first
|
87
|
+
m.freeze
|
88
|
+
m.name.should == '1'
|
89
|
+
@db.sqls.should == ['SELECT id FROM la LIMIT 1', 'SELECT name FROM la WHERE (id = 1) LIMIT 1']
|
90
|
+
m.name.should == '1'
|
91
|
+
@db.sqls.should == ['SELECT name FROM la WHERE (id = 1) LIMIT 1']
|
92
|
+
end
|
93
|
+
|
89
94
|
it "should not lazily load the attribute for a single model object if the value already exists" do
|
90
|
-
@c.
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
@db.sqls.should == ['SELECT id FROM la LIMIT 1']
|
97
|
-
end
|
95
|
+
m = @c.first
|
96
|
+
m.values.should == {:id=>1}
|
97
|
+
m[:name] = '1'
|
98
|
+
m.name.should == '1'
|
99
|
+
m.values.should == {:id=>1, :name=>'1'}
|
100
|
+
@db.sqls.should == ['SELECT id FROM la LIMIT 1']
|
98
101
|
end
|
99
102
|
|
100
103
|
it "should not lazily load the attribute for a single model object if it is a new record" do
|
101
|
-
@c.
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
@db.sqls.should == []
|
106
|
-
end
|
104
|
+
m = @c.new
|
105
|
+
m.values.should == {}
|
106
|
+
m.name.should == nil
|
107
|
+
@db.sqls.should == []
|
107
108
|
end
|
108
109
|
|
109
110
|
it "should eagerly load the attribute for all model objects reteived with it" do
|
110
|
-
@c.
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
111
|
+
ms = @c.all
|
112
|
+
ms.map{|m| m.values}.should == [{:id=>1}, {:id=>2}]
|
113
|
+
ms.map{|m| m.name}.should == %w'1 2'
|
114
|
+
ms.map{|m| m.values}.should == [{:id=>1, :name=>'1'}, {:id=>2, :name=>'2'}]
|
115
|
+
sqls = @db.sqls
|
116
|
+
['SELECT id, name FROM la WHERE (id IN (1, 2))',
|
117
|
+
'SELECT id, name FROM la WHERE (id IN (2, 1))'].should include(sqls.pop)
|
118
|
+
sqls.should == ['SELECT id FROM la']
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not eagerly load the attribute if model instance is frozen, and deal with other frozen instances if not frozen" do
|
122
|
+
ms = @c.all
|
123
|
+
ms.first.freeze
|
124
|
+
ms.map{|m| m.name}.should == %w'1 2'
|
125
|
+
@db.sqls.should == ['SELECT id FROM la', 'SELECT name FROM la WHERE (id = 1) LIMIT 1', 'SELECT id, name FROM la WHERE (id IN (2))']
|
117
126
|
end
|
118
127
|
|
119
128
|
it "should add the accessors to a module included in the class, so they can be easily overridden" do
|
@@ -122,35 +131,35 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
122
131
|
"#{super}-blah"
|
123
132
|
end
|
124
133
|
end
|
125
|
-
@c.
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
134
|
+
ms = @c.all
|
135
|
+
ms.map{|m| m.values}.should == [{:id=>1}, {:id=>2}]
|
136
|
+
ms.map{|m| m.name}.should == %w'1-blah 2-blah'
|
137
|
+
ms.map{|m| m.values}.should == [{:id=>1, :name=>'1'}, {:id=>2, :name=>'2'}]
|
138
|
+
sqls = @db.sqls
|
139
|
+
['SELECT id, name FROM la WHERE (id IN (1, 2))',
|
140
|
+
'SELECT id, name FROM la WHERE (id IN (2, 1))'].should include(sqls.pop)
|
141
|
+
sqls.should == ['SELECT id FROM la']
|
132
142
|
end
|
133
143
|
|
134
144
|
it "should work with the serialization plugin" do
|
135
145
|
@c.plugin :serialization, :yaml, :name
|
136
146
|
@c.instance_dataset._fetch = @ds._fetch = [[{:id=>1}, {:id=>2}], [{:id=>1, :name=>"--- 3\n"}, {:id=>2, :name=>"--- 6\n"}], [{:id=>1}], [{:name=>"--- 3\n"}]]
|
137
|
-
@
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
end
|
147
|
+
ms = @ds.all
|
148
|
+
ms.map{|m| m.values}.should == [{:id=>1}, {:id=>2}]
|
149
|
+
ms.map{|m| m.name}.should == [3,6]
|
150
|
+
ms.map{|m| m.values}.should == [{:id=>1, :name=>"--- 3\n"}, {:id=>2, :name=>"--- 6\n"}]
|
151
|
+
ms.map{|m| m.deserialized_values}.should == [{:name=>3}, {:name=>6}]
|
152
|
+
ms.map{|m| m.name}.should == [3,6]
|
153
|
+
sqls = @db.sqls
|
154
|
+
['SELECT id, name FROM la WHERE (id IN (1, 2))',
|
155
|
+
'SELECT id, name FROM la WHERE (id IN (2, 1))'].should include(sqls.pop)
|
156
|
+
sqls.should == ['SELECT id FROM la']
|
157
|
+
m = @ds.first
|
158
|
+
m.values.should == {:id=>1}
|
159
|
+
m.name.should == 3
|
160
|
+
m.values.should == {:id=>1, :name=>"--- 3\n"}
|
161
|
+
m.deserialized_values.should == {:name=>3}
|
162
|
+
m.name.should == 3
|
163
|
+
@db.sqls.should == ["SELECT id FROM la LIMIT 1", "SELECT name FROM la WHERE (id = 1) LIMIT 1"]
|
155
164
|
end
|
156
165
|
end
|