sequel 3.21.0 → 3.28.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.
- data/CHANGELOG +294 -0
- data/README.rdoc +20 -6
- data/Rakefile +20 -15
- data/doc/association_basics.rdoc +210 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +64 -27
- data/doc/opening_databases.rdoc +37 -10
- data/doc/prepared_statements.rdoc +16 -10
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/testing.rdoc +106 -0
- data/doc/transactions.rdoc +97 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado.rb +12 -1
- data/lib/sequel/adapters/amalgalite.rb +4 -0
- data/lib/sequel/adapters/db2.rb +95 -58
- data/lib/sequel/adapters/do.rb +12 -0
- data/lib/sequel/adapters/firebird.rb +25 -203
- data/lib/sequel/adapters/ibmdb.rb +440 -0
- data/lib/sequel/adapters/informix.rb +4 -19
- data/lib/sequel/adapters/jdbc/as400.rb +0 -7
- data/lib/sequel/adapters/jdbc/db2.rb +49 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +34 -0
- data/lib/sequel/adapters/jdbc/h2.rb +16 -5
- data/lib/sequel/adapters/jdbc/informix.rb +31 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
- data/lib/sequel/adapters/jdbc/mysql.rb +9 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +2 -27
- data/lib/sequel/adapters/jdbc/postgresql.rb +6 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +46 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +34 -0
- data/lib/sequel/adapters/jdbc.rb +62 -29
- data/lib/sequel/adapters/mysql.rb +22 -139
- data/lib/sequel/adapters/mysql2.rb +9 -14
- data/lib/sequel/adapters/odbc/db2.rb +21 -0
- data/lib/sequel/adapters/odbc.rb +15 -3
- data/lib/sequel/adapters/oracle.rb +17 -1
- data/lib/sequel/adapters/postgres.rb +111 -16
- data/lib/sequel/adapters/shared/access.rb +21 -0
- data/lib/sequel/adapters/shared/db2.rb +290 -0
- data/lib/sequel/adapters/shared/firebird.rb +214 -0
- data/lib/sequel/adapters/shared/informix.rb +45 -0
- data/lib/sequel/adapters/shared/mssql.rb +85 -47
- data/lib/sequel/adapters/shared/mysql.rb +50 -7
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +143 -0
- data/lib/sequel/adapters/shared/oracle.rb +0 -4
- data/lib/sequel/adapters/shared/postgres.rb +75 -43
- data/lib/sequel/adapters/shared/sqlite.rb +56 -8
- data/lib/sequel/adapters/sqlite.rb +12 -11
- data/lib/sequel/adapters/swift/mysql.rb +9 -0
- data/lib/sequel/adapters/tinytds.rb +139 -7
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +55 -0
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +6 -5
- data/lib/sequel/database/connecting.rb +5 -5
- data/lib/sequel/database/dataset.rb +1 -1
- data/lib/sequel/database/dataset_defaults.rb +1 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +38 -17
- data/lib/sequel/database/query.rb +50 -19
- data/lib/sequel/database/schema_generator.rb +8 -5
- data/lib/sequel/database/schema_methods.rb +52 -27
- data/lib/sequel/dataset/actions.rb +167 -48
- data/lib/sequel/dataset/features.rb +57 -8
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/misc.rb +39 -20
- data/lib/sequel/dataset/mutation.rb +3 -3
- data/lib/sequel/dataset/prepared_statements.rb +29 -14
- data/lib/sequel/dataset/query.rb +182 -32
- data/lib/sequel/dataset/sql.rb +31 -58
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +893 -309
- data/lib/sequel/model/base.rb +302 -105
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +13 -7
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/identity_map.rb +113 -6
- data/lib/sequel/plugins/many_through_many.rb +67 -5
- data/lib/sequel/plugins/prepared_statements.rb +140 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +12 -20
- data/lib/sequel/plugins/single_table_inheritance.rb +2 -0
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +107 -51
- data/lib/sequel/timezones.rb +12 -3
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +36 -0
- data/spec/adapters/mysql_spec.rb +36 -19
- data/spec/adapters/postgres_spec.rb +115 -28
- data/spec/adapters/spec_helper.rb +6 -0
- data/spec/adapters/sqlite_spec.rb +11 -0
- data/spec/core/connection_pool_spec.rb +62 -77
- data/spec/core/database_spec.rb +244 -287
- data/spec/core/dataset_spec.rb +383 -34
- data/spec/core/expression_filters_spec.rb +159 -41
- data/spec/core/schema_spec.rb +326 -3
- data/spec/core/spec_helper.rb +45 -0
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/identity_map_spec.rb +162 -0
- data/spec/extensions/many_through_many_spec.rb +195 -20
- data/spec/extensions/migration_spec.rb +17 -17
- data/spec/extensions/nested_attributes_spec.rb +1 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
- data/spec/extensions/prepared_statements_spec.rb +72 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +12 -20
- data/spec/extensions/serialization_modification_detection_spec.rb +36 -0
- data/spec/extensions/single_table_inheritance_spec.rb +11 -0
- data/spec/extensions/spec_helper.rb +3 -1
- data/spec/extensions/to_dot_spec.rb +3 -5
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +405 -15
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +240 -20
- data/spec/integration/plugin_test.rb +142 -5
- data/spec/integration/prepared_statement_test.rb +174 -95
- data/spec/integration/schema_test.rb +128 -16
- data/spec/integration/spec_helper.rb +15 -0
- data/spec/integration/transaction_test.rb +40 -0
- data/spec/integration/type_test.rb +16 -2
- data/spec/model/association_reflection_spec.rb +91 -0
- data/spec/model/associations_spec.rb +476 -5
- data/spec/model/base_spec.rb +91 -1
- data/spec/model/eager_loading_spec.rb +519 -31
- data/spec/model/hooks_spec.rb +161 -0
- data/spec/model/model_spec.rb +89 -2
- data/spec/model/plugins_spec.rb +17 -0
- data/spec/model/record_spec.rb +184 -12
- data/spec/model/spec_helper.rb +5 -0
- data/spec/model/validations_spec.rb +11 -0
- metadata +85 -34
data/spec/model/hooks_spec.rb
CHANGED
|
@@ -268,4 +268,165 @@ describe "Model#before_validation && Model#after_validation" do
|
|
|
268
268
|
@c.load(:id => 2233).save.should == nil
|
|
269
269
|
MODEL_DB.sqls.should == []
|
|
270
270
|
end
|
|
271
|
+
|
|
272
|
+
specify "#valid? should return false if before_validation returns false" do
|
|
273
|
+
@c.send(:define_method, :before_validation){false}
|
|
274
|
+
@c.load(:id => 2233).valid?.should == false
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
describe "Model around filters" do
|
|
279
|
+
before do
|
|
280
|
+
MODEL_DB.reset
|
|
281
|
+
|
|
282
|
+
@c = Class.new(Sequel::Model(:items))
|
|
283
|
+
@c.class_eval do
|
|
284
|
+
columns :id, :x
|
|
285
|
+
def _save_refresh(*a) end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
specify "around_create should be called around new record creation" do
|
|
290
|
+
@c.class_eval do
|
|
291
|
+
def around_create
|
|
292
|
+
MODEL_DB << 'ac_before'
|
|
293
|
+
super
|
|
294
|
+
MODEL_DB << 'ac_after'
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
@c.create(:x => 2)
|
|
298
|
+
MODEL_DB.sqls.should == [ 'ac_before', 'INSERT INTO items (x) VALUES (2)', 'ac_after' ]
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
specify "around_delete should be called around record destruction" do
|
|
302
|
+
@c.class_eval do
|
|
303
|
+
def around_destroy
|
|
304
|
+
MODEL_DB << 'ad_before'
|
|
305
|
+
super
|
|
306
|
+
MODEL_DB << 'ad_after'
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
@c.load(:id=>1, :x => 2).destroy
|
|
310
|
+
MODEL_DB.sqls.should == [ 'ad_before', 'DELETE FROM items WHERE (id = 1)', 'ad_after' ]
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
specify "around_update should be called around updating existing records" do
|
|
314
|
+
@c.class_eval do
|
|
315
|
+
def around_update
|
|
316
|
+
MODEL_DB << 'au_before'
|
|
317
|
+
super
|
|
318
|
+
MODEL_DB << 'au_after'
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
@c.load(:id=>1, :x => 2).save
|
|
322
|
+
MODEL_DB.sqls.should == [ 'au_before', 'UPDATE items SET x = 2 WHERE (id = 1)', 'au_after' ]
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
specify "around_update should be called around saving both new and existing records, around either after_create and after_update" do
|
|
326
|
+
@c.class_eval do
|
|
327
|
+
def around_update
|
|
328
|
+
MODEL_DB << 'au_before'
|
|
329
|
+
super
|
|
330
|
+
MODEL_DB << 'au_after'
|
|
331
|
+
end
|
|
332
|
+
def around_create
|
|
333
|
+
MODEL_DB << 'ac_before'
|
|
334
|
+
super
|
|
335
|
+
MODEL_DB << 'ac_after'
|
|
336
|
+
end
|
|
337
|
+
def around_save
|
|
338
|
+
MODEL_DB << 'as_before'
|
|
339
|
+
super
|
|
340
|
+
MODEL_DB << 'as_after'
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
@c.create(:x => 2)
|
|
344
|
+
MODEL_DB.sqls.should == [ 'as_before', 'ac_before', 'INSERT INTO items (x) VALUES (2)', 'ac_after', 'as_after' ]
|
|
345
|
+
MODEL_DB.sqls.clear
|
|
346
|
+
@c.load(:id=>1, :x => 2).save
|
|
347
|
+
MODEL_DB.sqls.should == [ 'as_before', 'au_before', 'UPDATE items SET x = 2 WHERE (id = 1)', 'au_after', 'as_after' ]
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
specify "around_validation should be called around validating records" do
|
|
351
|
+
@c.class_eval do
|
|
352
|
+
def around_validation
|
|
353
|
+
MODEL_DB << 'av_before'
|
|
354
|
+
super
|
|
355
|
+
MODEL_DB << 'av_after'
|
|
356
|
+
end
|
|
357
|
+
def validate
|
|
358
|
+
MODEL_DB << 'validate'
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
@c.new(:x => 2).valid?.should == true
|
|
362
|
+
MODEL_DB.sqls.should == [ 'av_before', 'validate', 'av_after' ]
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
specify "around_validation should be able to catch validation errors and modify them" do
|
|
366
|
+
@c.class_eval do
|
|
367
|
+
def validate
|
|
368
|
+
errors.add(:x, 'foo')
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
@c.new(:x => 2).valid?.should == false
|
|
372
|
+
@c.class_eval do
|
|
373
|
+
def around_validation
|
|
374
|
+
super
|
|
375
|
+
errors.clear
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
@c.new(:x => 2).valid?.should == true
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
specify "around_create that doesn't call super should raise a HookFailed" do
|
|
382
|
+
@c.send(:define_method, :around_create){}
|
|
383
|
+
proc{@c.create(:x => 2)}.should raise_error(Sequel::HookFailed)
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
specify "around_update that doesn't call super should raise a HookFailed" do
|
|
387
|
+
@c.send(:define_method, :around_update){}
|
|
388
|
+
proc{@c.load(:x => 2).save}.should raise_error(Sequel::HookFailed)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
specify "around_save that doesn't call super should raise a HookFailed" do
|
|
392
|
+
@c.send(:define_method, :around_save){}
|
|
393
|
+
proc{@c.create(:x => 2)}.should raise_error(Sequel::HookFailed)
|
|
394
|
+
proc{@c.load(:x => 2).save}.should raise_error(Sequel::HookFailed)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
specify "around_destroy that doesn't call super should raise a HookFailed" do
|
|
398
|
+
@c.send(:define_method, :around_destroy){}
|
|
399
|
+
proc{@c.load(:x => 2).destroy}.should raise_error(Sequel::HookFailed)
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
specify "around_validation that doesn't call super should raise a HookFailed" do
|
|
403
|
+
@c.send(:define_method, :around_validation){}
|
|
404
|
+
proc{@c.new.save}.should raise_error(Sequel::HookFailed)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
specify "around_validation that doesn't call super should have valid? return false" do
|
|
408
|
+
@c.send(:define_method, :around_validation){}
|
|
409
|
+
@c.new.valid?.should == false
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
specify "around_* that doesn't call super should return nil if raise_on_save_failure is false" do
|
|
413
|
+
@c.raise_on_save_failure = false
|
|
414
|
+
|
|
415
|
+
o = @c.load(:id => 1)
|
|
416
|
+
o.meta_def(:around_save){}
|
|
417
|
+
o.save.should == nil
|
|
418
|
+
|
|
419
|
+
o = @c.load(:id => 1)
|
|
420
|
+
o.meta_def(:around_update){}
|
|
421
|
+
o.save.should == nil
|
|
422
|
+
|
|
423
|
+
o = @c.new
|
|
424
|
+
o.meta_def(:around_create){}
|
|
425
|
+
o.save.should == nil
|
|
426
|
+
|
|
427
|
+
o = @c.new
|
|
428
|
+
o.meta_def(:around_validation){}
|
|
429
|
+
o.save.should == nil
|
|
430
|
+
end
|
|
431
|
+
|
|
271
432
|
end
|
data/spec/model/model_spec.rb
CHANGED
|
@@ -12,13 +12,48 @@ describe "Sequel::Model()" do
|
|
|
12
12
|
c.dataset.should == ds
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
it "should return a model subclass with a dataset with the default database and given table name if given a
|
|
15
|
+
it "should return a model subclass with a dataset with the default database and given table name if given a Symbol" do
|
|
16
16
|
c = Sequel::Model(:blah)
|
|
17
17
|
c.superclass.should == Sequel::Model
|
|
18
18
|
c.db.should == @db
|
|
19
19
|
c.table_name.should == :blah
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
it "should return a model subclass with a dataset with the default database and given table name if given a LiteralString" do
|
|
23
|
+
c = Sequel::Model('blah'.lit)
|
|
24
|
+
c.superclass.should == Sequel::Model
|
|
25
|
+
c.db.should == @db
|
|
26
|
+
c.table_name.should == 'blah'.lit
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should return a model subclass with a dataset with the default database and given table name if given an SQL::Identifier" do
|
|
30
|
+
c = Sequel::Model(:blah.identifier)
|
|
31
|
+
c.superclass.should == Sequel::Model
|
|
32
|
+
c.db.should == @db
|
|
33
|
+
c.table_name.should == :blah.identifier
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should return a model subclass with a dataset with the default database and given table name if given an SQL::QualifiedIdentifier" do
|
|
37
|
+
c = Sequel::Model(:blah.qualify(:boo))
|
|
38
|
+
c.superclass.should == Sequel::Model
|
|
39
|
+
c.db.should == @db
|
|
40
|
+
c.table_name.should == :blah.qualify(:boo)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should return a model subclass with a dataset with the default database and given table name if given an SQL::AliasedExpression" do
|
|
44
|
+
c = Sequel::Model(:blah.as(:boo))
|
|
45
|
+
c.superclass.should == Sequel::Model
|
|
46
|
+
c.db.should == @db
|
|
47
|
+
c.table_name.should == :boo
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should return a model subclass with the given dataset if given a dataset using an SQL::Identifier" do
|
|
51
|
+
ds = @db[:blah.identifier]
|
|
52
|
+
c = Sequel::Model(ds)
|
|
53
|
+
c.superclass.should == Sequel::Model
|
|
54
|
+
c.dataset.should == ds
|
|
55
|
+
end
|
|
56
|
+
|
|
22
57
|
it "should return a model subclass associated to the given database if given a database" do
|
|
23
58
|
db = Sequel::Database.new
|
|
24
59
|
c = Sequel::Model(db)
|
|
@@ -43,6 +78,27 @@ describe "Sequel::Model()" do
|
|
|
43
78
|
end.should_not raise_error
|
|
44
79
|
end
|
|
45
80
|
|
|
81
|
+
it "should work without raising an exception with an SQL::Identifier " do
|
|
82
|
+
proc do
|
|
83
|
+
class ::Album < Sequel::Model(:table.identifier); end
|
|
84
|
+
class ::Album < Sequel::Model(:table.identifier); end
|
|
85
|
+
end.should_not raise_error
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "should work without raising an exception with an SQL::QualifiedIdentifier " do
|
|
89
|
+
proc do
|
|
90
|
+
class ::Album < Sequel::Model(:table.qualify(:schema)); end
|
|
91
|
+
class ::Album < Sequel::Model(:table.qualify(:schema)); end
|
|
92
|
+
end.should_not raise_error
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "should work without raising an exception with an SQL::AliasedExpression" do
|
|
96
|
+
proc do
|
|
97
|
+
class ::Album < Sequel::Model(:table.as(:alias)); end
|
|
98
|
+
class ::Album < Sequel::Model(:table.as(:alias)); end
|
|
99
|
+
end.should_not raise_error
|
|
100
|
+
end
|
|
101
|
+
|
|
46
102
|
it "should work without raising an exception with a database" do
|
|
47
103
|
proc do
|
|
48
104
|
class ::Album < Sequel::Model(@db); end
|
|
@@ -56,6 +112,13 @@ describe "Sequel::Model()" do
|
|
|
56
112
|
class ::Album < Sequel::Model(@db[:table]); end
|
|
57
113
|
end.should_not raise_error
|
|
58
114
|
end
|
|
115
|
+
|
|
116
|
+
it "should work without raising an exception with a dataset with an SQL::Identifier" do
|
|
117
|
+
proc do
|
|
118
|
+
class ::Album < Sequel::Model(@db[:table.identifier]); end
|
|
119
|
+
class ::Album < Sequel::Model(@db[:table.identifier]); end
|
|
120
|
+
end.should_not raise_error
|
|
121
|
+
end
|
|
59
122
|
end
|
|
60
123
|
end
|
|
61
124
|
|
|
@@ -106,12 +169,36 @@ describe Sequel::Model, "dataset & schema" do
|
|
|
106
169
|
@model.table_name.should == :foo
|
|
107
170
|
end
|
|
108
171
|
|
|
109
|
-
it "set_dataset should take a
|
|
172
|
+
it "set_dataset should take a Symbol" do
|
|
110
173
|
@model.db = MODEL_DB
|
|
111
174
|
@model.set_dataset(:foo)
|
|
112
175
|
@model.table_name.should == :foo
|
|
113
176
|
end
|
|
114
177
|
|
|
178
|
+
it "set_dataset should take a LiteralString" do
|
|
179
|
+
@model.db = MODEL_DB
|
|
180
|
+
@model.set_dataset('foo'.lit)
|
|
181
|
+
@model.table_name.should == 'foo'.lit
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "set_dataset should take an SQL::Identifier" do
|
|
185
|
+
@model.db = MODEL_DB
|
|
186
|
+
@model.set_dataset(:foo.identifier)
|
|
187
|
+
@model.table_name.should == :foo.identifier
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "set_dataset should take an SQL::QualifiedIdentifier" do
|
|
191
|
+
@model.db = MODEL_DB
|
|
192
|
+
@model.set_dataset(:foo.qualify(:bar))
|
|
193
|
+
@model.table_name.should == :foo.qualify(:bar)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "set_dataset should take an SQL::AliasedExpression" do
|
|
197
|
+
@model.db = MODEL_DB
|
|
198
|
+
@model.set_dataset(:foo.as(:bar))
|
|
199
|
+
@model.table_name.should == :bar
|
|
200
|
+
end
|
|
201
|
+
|
|
115
202
|
it "table_name should respect table aliases" do
|
|
116
203
|
@model.set_dataset(:foo___x)
|
|
117
204
|
@model.table_name.should == :x
|
data/spec/model/plugins_spec.rb
CHANGED
|
@@ -233,4 +233,21 @@ describe Sequel::Model, ".plugin" do
|
|
|
233
233
|
end
|
|
234
234
|
lambda{@c.plugin m}.should_not raise_error
|
|
235
235
|
end
|
|
236
|
+
|
|
237
|
+
it "should not raise an error if plugin submodule names exist higher up in the namespace hierarchy" do
|
|
238
|
+
class ::ClassMethods; end
|
|
239
|
+
@c.plugin(m = Module.new)
|
|
240
|
+
Object.send(:remove_const, :ClassMethods)
|
|
241
|
+
@c.plugins.should include(m)
|
|
242
|
+
|
|
243
|
+
class ::InstanceMethods; end
|
|
244
|
+
@c.plugin(m = Module.new)
|
|
245
|
+
Object.send(:remove_const, :InstanceMethods)
|
|
246
|
+
@c.plugins.should include(m)
|
|
247
|
+
|
|
248
|
+
class ::DatasetMethods; end
|
|
249
|
+
@c.plugin(m = Module.new)
|
|
250
|
+
Object.send(:remove_const, :DatasetMethods)
|
|
251
|
+
@c.plugins.should include(m)
|
|
252
|
+
end
|
|
236
253
|
end
|
data/spec/model/record_spec.rb
CHANGED
|
@@ -52,6 +52,7 @@ describe "Model#save" do
|
|
|
52
52
|
|
|
53
53
|
it "should use dataset's insert_select method if present" do
|
|
54
54
|
ds = @c.dataset = @c.dataset.clone
|
|
55
|
+
def ds.supports_insert_select?() true end
|
|
55
56
|
def ds.insert_select(hash)
|
|
56
57
|
execute("INSERT INTO items (y) VALUES (2)")
|
|
57
58
|
{:y=>2}
|
|
@@ -63,6 +64,12 @@ describe "Model#save" do
|
|
|
63
64
|
MODEL_DB.sqls.should == ["INSERT INTO items (y) VALUES (2)"]
|
|
64
65
|
end
|
|
65
66
|
|
|
67
|
+
it "should not use dataset's insert_select method if specific columns are selected" do
|
|
68
|
+
ds = @c.dataset = @c.dataset.select(:y)
|
|
69
|
+
ds.should_not_receive(:insert_select)
|
|
70
|
+
@c.new(:x => 1).save
|
|
71
|
+
end
|
|
72
|
+
|
|
66
73
|
it "should use value returned by insert as the primary key and refresh the object" do
|
|
67
74
|
@c.dataset.meta_def(:insert){|h| super(h); 13}
|
|
68
75
|
o = @c.new(:x => 11)
|
|
@@ -623,6 +630,40 @@ describe "Model#pk" do
|
|
|
623
630
|
end
|
|
624
631
|
end
|
|
625
632
|
|
|
633
|
+
describe "Model#pk_or_nil" do
|
|
634
|
+
before(:each) do
|
|
635
|
+
@m = Class.new(Sequel::Model)
|
|
636
|
+
@m.columns :id, :x, :y
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
it "should be default return the value of the :id column" do
|
|
640
|
+
m = @m.load(:id => 111, :x => 2, :y => 3)
|
|
641
|
+
m.pk_or_nil.should == 111
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
it "should be return the primary key value for custom primary key" do
|
|
645
|
+
@m.set_primary_key :x
|
|
646
|
+
m = @m.load(:id => 111, :x => 2, :y => 3)
|
|
647
|
+
m.pk_or_nil.should == 2
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
it "should be return the primary key value for composite primary key" do
|
|
651
|
+
@m.set_primary_key [:y, :x]
|
|
652
|
+
m = @m.load(:id => 111, :x => 2, :y => 3)
|
|
653
|
+
m.pk_or_nil.should == [3, 2]
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
it "should raise if no primary key" do
|
|
657
|
+
@m.set_primary_key nil
|
|
658
|
+
m = @m.new(:id => 111, :x => 2, :y => 3)
|
|
659
|
+
m.pk_or_nil.should be_nil
|
|
660
|
+
|
|
661
|
+
@m.no_primary_key
|
|
662
|
+
m = @m.new(:id => 111, :x => 2, :y => 3)
|
|
663
|
+
m.pk_or_nil.should be_nil
|
|
664
|
+
end
|
|
665
|
+
end
|
|
666
|
+
|
|
626
667
|
describe "Model#pk_hash" do
|
|
627
668
|
before(:each) do
|
|
628
669
|
@m = Class.new(Sequel::Model)
|
|
@@ -716,6 +757,29 @@ describe Sequel::Model, "#set" do
|
|
|
716
757
|
MODEL_DB.sqls.should == []
|
|
717
758
|
end
|
|
718
759
|
|
|
760
|
+
it "should raise error if strict_param_setting is true and method does not exist" do
|
|
761
|
+
@o1.strict_param_setting = true
|
|
762
|
+
proc{@o1.set('foo' => 1)}.should raise_error(Sequel::Error)
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
it "should raise error if strict_param_setting is true and column is a primary key" do
|
|
766
|
+
@o1.strict_param_setting = true
|
|
767
|
+
proc{@o1.set('id' => 1)}.should raise_error(Sequel::Error)
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
it "should raise error if strict_param_setting is true and column is restricted" do
|
|
771
|
+
@o1.strict_param_setting = true
|
|
772
|
+
@c.set_restricted_columns :x
|
|
773
|
+
proc{@o1.set('x' => 1)}.should raise_error(Sequel::Error)
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
it "should not create a symbol if strict_param_setting is true and string is given" do
|
|
777
|
+
@o1.strict_param_setting = true
|
|
778
|
+
l = Symbol.all_symbols.length
|
|
779
|
+
proc{@o1.set('sadojafdso' => 1)}.should raise_error(Sequel::Error)
|
|
780
|
+
Symbol.all_symbols.length.should == l
|
|
781
|
+
end
|
|
782
|
+
|
|
719
783
|
it "#set should correctly handle cases where an instance method is added to the class" do
|
|
720
784
|
@o1.set(:x => 1)
|
|
721
785
|
@o1.values.should == {:x => 1}
|
|
@@ -739,6 +803,32 @@ describe Sequel::Model, "#set" do
|
|
|
739
803
|
@o1.set(:x => 2, :z => 3)
|
|
740
804
|
@o1.values.should == {:x => 2, :z=>3}
|
|
741
805
|
end
|
|
806
|
+
|
|
807
|
+
it "#set should correctly handle cases where a module with a setter method is included in the class" do
|
|
808
|
+
@o1.set(:x => 1)
|
|
809
|
+
@o1.values.should == {:x => 1}
|
|
810
|
+
|
|
811
|
+
@c.send(:include, Module.new do
|
|
812
|
+
def z=(v)
|
|
813
|
+
self[:z] = v
|
|
814
|
+
end
|
|
815
|
+
end)
|
|
816
|
+
@o1.set(:x => 2, :z => 3)
|
|
817
|
+
@o1.values.should == {:x => 2, :z=>3}
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
it "#set should correctly handle cases where the object extends a module with a setter method " do
|
|
821
|
+
@o1.set(:x => 1)
|
|
822
|
+
@o1.values.should == {:x => 1}
|
|
823
|
+
|
|
824
|
+
@o1.extend(Module.new do
|
|
825
|
+
def z=(v)
|
|
826
|
+
self[:z] = v
|
|
827
|
+
end
|
|
828
|
+
end)
|
|
829
|
+
@o1.set(:x => 2, :z => 3)
|
|
830
|
+
@o1.values.should == {:x => 2, :z=>3}
|
|
831
|
+
end
|
|
742
832
|
end
|
|
743
833
|
|
|
744
834
|
describe Sequel::Model, "#update" do
|
|
@@ -997,6 +1087,11 @@ describe Sequel::Model, "#exists?" do
|
|
|
997
1087
|
@model.load(:id=>2).exists?.should be_false
|
|
998
1088
|
MODEL_DB.sqls.should == ['SELECT 1 FROM items WHERE (id = 2) LIMIT 1']
|
|
999
1089
|
end
|
|
1090
|
+
|
|
1091
|
+
it "should return false without issuing a query if the model object is new" do
|
|
1092
|
+
@model.new.exists?.should be_false
|
|
1093
|
+
MODEL_DB.sqls.should == []
|
|
1094
|
+
end
|
|
1000
1095
|
end
|
|
1001
1096
|
|
|
1002
1097
|
describe Sequel::Model, "#each" do
|
|
@@ -1094,13 +1189,10 @@ describe Sequel::Model, "#hash" do
|
|
|
1094
1189
|
y = Class.new(Sequel::Model)
|
|
1095
1190
|
y.columns :id, :x
|
|
1096
1191
|
a = z.load(:id => 1, :x => 3)
|
|
1097
|
-
b = z.load(:id => 1, :x => 4)
|
|
1098
|
-
c = z.load(:id => 2, :x => 3)
|
|
1099
|
-
d = y.load(:id => 1, :x => 3)
|
|
1100
1192
|
|
|
1101
|
-
a.hash.should ==
|
|
1102
|
-
a.hash.should_not ==
|
|
1103
|
-
a.hash.should_not ==
|
|
1193
|
+
a.hash.should == z.load(:id => 1, :x => 4).hash
|
|
1194
|
+
a.hash.should_not == z.load(:id => 2, :x => 3).hash
|
|
1195
|
+
a.hash.should_not == y.load(:id => 1, :x => 3).hash
|
|
1104
1196
|
end
|
|
1105
1197
|
|
|
1106
1198
|
specify "should be the same only for objects with the same class and values if the pk is nil" do
|
|
@@ -1109,14 +1201,71 @@ describe Sequel::Model, "#hash" do
|
|
|
1109
1201
|
y = Class.new(Sequel::Model)
|
|
1110
1202
|
y.columns :id, :x
|
|
1111
1203
|
a = z.new(:x => 3)
|
|
1112
|
-
b = z.new(:x => 4)
|
|
1113
|
-
c = z.new(:x => 3)
|
|
1114
|
-
d = y.new(:x => 3)
|
|
1115
1204
|
|
|
1116
|
-
a.hash.should_not ==
|
|
1117
|
-
a.hash.should ==
|
|
1118
|
-
a.hash.should_not ==
|
|
1205
|
+
a.hash.should_not == z.new(:x => 4).hash
|
|
1206
|
+
a.hash.should == z.new(:x => 3).hash
|
|
1207
|
+
a.hash.should_not == y.new(:x => 3).hash
|
|
1208
|
+
end
|
|
1209
|
+
|
|
1210
|
+
specify "should be the same only for objects with the same class and pk if pk is composite and all values are non-NULL" do
|
|
1211
|
+
z = Class.new(Sequel::Model)
|
|
1212
|
+
z.columns :id, :id2, :x
|
|
1213
|
+
z.set_primary_key(:id, :id2)
|
|
1214
|
+
y = Class.new(Sequel::Model)
|
|
1215
|
+
y.columns :id, :id2, :x
|
|
1216
|
+
y.set_primary_key(:id, :id2)
|
|
1217
|
+
a = z.load(:id => 1, :id2=>2, :x => 3)
|
|
1218
|
+
|
|
1219
|
+
a.hash.should == z.load(:id => 1, :id2=>2, :x => 4).hash
|
|
1220
|
+
a.hash.should_not == z.load(:id => 2, :id2=>1, :x => 3).hash
|
|
1221
|
+
a.hash.should_not == y.load(:id => 1, :id2=>1, :x => 3).hash
|
|
1222
|
+
end
|
|
1223
|
+
|
|
1224
|
+
specify "should be the same only for objects with the same class and value if pk is composite and one values is NULL" do
|
|
1225
|
+
z = Class.new(Sequel::Model)
|
|
1226
|
+
z.columns :id, :id2, :x
|
|
1227
|
+
z.set_primary_key(:id, :id2)
|
|
1228
|
+
y = Class.new(Sequel::Model)
|
|
1229
|
+
y.columns :id, :id2, :x
|
|
1230
|
+
y.set_primary_key(:id, :id2)
|
|
1231
|
+
|
|
1232
|
+
a = z.load(:id => 1, :id2 => nil, :x => 3)
|
|
1233
|
+
a.hash.should == z.load(:id => 1, :id2=>nil, :x => 3).hash
|
|
1234
|
+
a.hash.should_not == z.load(:id => 1, :id2=>nil, :x => 4).hash
|
|
1235
|
+
a.hash.should_not == y.load(:id => 1, :id2=>nil, :x => 3).hash
|
|
1236
|
+
|
|
1237
|
+
a = z.load(:id =>nil, :id2 => nil, :x => 3)
|
|
1238
|
+
a.hash.should == z.load(:id => nil, :id2=>nil, :x => 3).hash
|
|
1239
|
+
a.hash.should_not == z.load(:id => nil, :id2=>nil, :x => 4).hash
|
|
1240
|
+
a.hash.should_not == y.load(:id => nil, :id2=>nil, :x => 3).hash
|
|
1241
|
+
|
|
1242
|
+
a = z.load(:id => 1, :x => 3)
|
|
1243
|
+
a.hash.should == z.load(:id => 1, :x => 3).hash
|
|
1244
|
+
a.hash.should_not == z.load(:id => 1, :id2=>nil, :x => 3).hash
|
|
1245
|
+
a.hash.should_not == z.load(:id => 1, :x => 4).hash
|
|
1246
|
+
a.hash.should_not == y.load(:id => 1, :x => 3).hash
|
|
1247
|
+
|
|
1248
|
+
a = z.load(:x => 3)
|
|
1249
|
+
a.hash.should == z.load(:x => 3).hash
|
|
1250
|
+
a.hash.should_not == z.load(:id => nil, :id2=>nil, :x => 3).hash
|
|
1251
|
+
a.hash.should_not == z.load(:x => 4).hash
|
|
1252
|
+
a.hash.should_not == y.load(:x => 3).hash
|
|
1253
|
+
end
|
|
1254
|
+
|
|
1255
|
+
specify "should be the same only for objects with the same class and values if the no primary key" do
|
|
1256
|
+
z = Class.new(Sequel::Model)
|
|
1257
|
+
z.columns :id, :x
|
|
1258
|
+
z.no_primary_key
|
|
1259
|
+
y = Class.new(Sequel::Model)
|
|
1260
|
+
y.columns :id, :x
|
|
1261
|
+
y.no_primary_key
|
|
1262
|
+
a = z.new(:x => 3)
|
|
1263
|
+
|
|
1264
|
+
a.hash.should_not == z.new(:x => 4).hash
|
|
1265
|
+
a.hash.should == z.new(:x => 3).hash
|
|
1266
|
+
a.hash.should_not == y.new(:x => 3).hash
|
|
1119
1267
|
end
|
|
1268
|
+
|
|
1120
1269
|
end
|
|
1121
1270
|
|
|
1122
1271
|
describe Sequel::Model, "#initialize" do
|
|
@@ -1161,6 +1310,29 @@ describe Sequel::Model, "#initialize" do
|
|
|
1161
1310
|
m.values.should == {:x => 2}
|
|
1162
1311
|
end
|
|
1163
1312
|
end
|
|
1313
|
+
|
|
1314
|
+
describe Sequel::Model, "#initialize_set" do
|
|
1315
|
+
before do
|
|
1316
|
+
@c = Class.new(Sequel::Model){columns :id, :x, :y}
|
|
1317
|
+
end
|
|
1318
|
+
|
|
1319
|
+
specify "should be called by initialize to set the column values" do
|
|
1320
|
+
@c.send(:define_method, :initialize_set){|h| set(:y => 3)}
|
|
1321
|
+
@c.new(:x => 2).values.should == {:y => 3}
|
|
1322
|
+
end
|
|
1323
|
+
|
|
1324
|
+
specify "should be called with the hash given to initialize " do
|
|
1325
|
+
x = nil
|
|
1326
|
+
@c.send(:define_method, :initialize_set){|y| x = y}
|
|
1327
|
+
@c.new(:x => 2)
|
|
1328
|
+
x.should == {:x => 2}
|
|
1329
|
+
end
|
|
1330
|
+
|
|
1331
|
+
specify "should not cause columns modified by the method to be considered as changed" do
|
|
1332
|
+
@c.send(:define_method, :initialize_set){|h| set(:y => 3)}
|
|
1333
|
+
@c.new(:x => 2).changed_columns.should == []
|
|
1334
|
+
end
|
|
1335
|
+
end
|
|
1164
1336
|
|
|
1165
1337
|
describe Sequel::Model, ".create" do
|
|
1166
1338
|
|
data/spec/model/spec_helper.rb
CHANGED
|
@@ -8,6 +8,11 @@ unless Sequel.const_defined?('Model')
|
|
|
8
8
|
require 'sequel/model'
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
if ENV['SEQUEL_COLUMNS_INTROSPECTION']
|
|
12
|
+
Sequel.extension :columns_introspection
|
|
13
|
+
Sequel::Dataset.introspect_all_columns
|
|
14
|
+
end
|
|
15
|
+
|
|
11
16
|
class MockDataset < Sequel::Dataset
|
|
12
17
|
def insert(*args)
|
|
13
18
|
@db.execute insert_sql(*args)
|
|
@@ -61,6 +61,17 @@ describe Sequel::Model::Errors do
|
|
|
61
61
|
msgs.should include('blow blieuh', 'blow blich', 'blay bliu')
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
specify "should not add column names for LiteralStrings" do
|
|
65
|
+
@errors.full_messages.should == []
|
|
66
|
+
|
|
67
|
+
@errors[:blow] << 'blieuh'
|
|
68
|
+
@errors[:blow] << 'blich'.lit
|
|
69
|
+
@errors[:blay] << 'bliu'
|
|
70
|
+
msgs = @errors.full_messages
|
|
71
|
+
msgs.size.should == 3
|
|
72
|
+
msgs.should include('blow blieuh', 'blich', 'blay bliu')
|
|
73
|
+
end
|
|
74
|
+
|
|
64
75
|
specify "should return the number of error messages using #count" do
|
|
65
76
|
@errors.count.should == 0
|
|
66
77
|
@errors.add(:a, 'b')
|