sequel 2.2.0 → 2.3.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 +1551 -4
- data/README +306 -19
- data/Rakefile +84 -56
- data/bin/sequel +106 -0
- data/doc/cheat_sheet.rdoc +225 -0
- data/doc/dataset_filtering.rdoc +182 -0
- data/lib/sequel_core.rb +136 -0
- data/lib/sequel_core/adapters/adapter_skeleton.rb +54 -0
- data/lib/sequel_core/adapters/ado.rb +80 -0
- data/lib/sequel_core/adapters/db2.rb +148 -0
- data/lib/sequel_core/adapters/dbi.rb +117 -0
- data/lib/sequel_core/adapters/informix.rb +78 -0
- data/lib/sequel_core/adapters/jdbc.rb +186 -0
- data/lib/sequel_core/adapters/jdbc/mysql.rb +55 -0
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +66 -0
- data/lib/sequel_core/adapters/jdbc/sqlite.rb +47 -0
- data/lib/sequel_core/adapters/mysql.rb +231 -0
- data/lib/sequel_core/adapters/odbc.rb +155 -0
- data/lib/sequel_core/adapters/odbc_mssql.rb +106 -0
- data/lib/sequel_core/adapters/openbase.rb +64 -0
- data/lib/sequel_core/adapters/oracle.rb +170 -0
- data/lib/sequel_core/adapters/postgres.rb +199 -0
- data/lib/sequel_core/adapters/shared/mysql.rb +275 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +351 -0
- data/lib/sequel_core/adapters/shared/sqlite.rb +146 -0
- data/lib/sequel_core/adapters/sqlite.rb +138 -0
- data/lib/sequel_core/connection_pool.rb +194 -0
- data/lib/sequel_core/core_ext.rb +203 -0
- data/lib/sequel_core/core_sql.rb +184 -0
- data/lib/sequel_core/database.rb +471 -0
- data/lib/sequel_core/database/schema.rb +156 -0
- data/lib/sequel_core/dataset.rb +457 -0
- data/lib/sequel_core/dataset/callback.rb +13 -0
- data/lib/sequel_core/dataset/convenience.rb +245 -0
- data/lib/sequel_core/dataset/pagination.rb +96 -0
- data/lib/sequel_core/dataset/query.rb +41 -0
- data/lib/sequel_core/dataset/schema.rb +15 -0
- data/lib/sequel_core/dataset/sql.rb +889 -0
- data/lib/sequel_core/deprecated.rb +26 -0
- data/lib/sequel_core/exceptions.rb +42 -0
- data/lib/sequel_core/migration.rb +187 -0
- data/lib/sequel_core/object_graph.rb +216 -0
- data/lib/sequel_core/pretty_table.rb +71 -0
- data/lib/sequel_core/schema.rb +2 -0
- data/lib/sequel_core/schema/generator.rb +239 -0
- data/lib/sequel_core/schema/sql.rb +325 -0
- data/lib/sequel_core/sql.rb +812 -0
- data/lib/sequel_model.rb +5 -1
- data/lib/sequel_model/association_reflection.rb +3 -8
- data/lib/sequel_model/base.rb +15 -10
- data/lib/sequel_model/inflector.rb +3 -5
- data/lib/sequel_model/plugins.rb +1 -1
- data/lib/sequel_model/record.rb +11 -3
- data/lib/sequel_model/schema.rb +4 -4
- data/lib/sequel_model/validations.rb +6 -1
- data/spec/adapters/ado_spec.rb +17 -0
- data/spec/adapters/informix_spec.rb +96 -0
- data/spec/adapters/mysql_spec.rb +764 -0
- data/spec/adapters/oracle_spec.rb +222 -0
- data/spec/adapters/postgres_spec.rb +441 -0
- data/spec/adapters/spec_helper.rb +7 -0
- data/spec/adapters/sqlite_spec.rb +400 -0
- data/spec/integration/dataset_test.rb +51 -0
- data/spec/integration/eager_loader_test.rb +702 -0
- data/spec/integration/schema_test.rb +102 -0
- data/spec/integration/spec_helper.rb +44 -0
- data/spec/integration/type_test.rb +43 -0
- data/spec/rcov.opts +2 -0
- data/spec/sequel_core/connection_pool_spec.rb +363 -0
- data/spec/sequel_core/core_ext_spec.rb +156 -0
- data/spec/sequel_core/core_sql_spec.rb +427 -0
- data/spec/sequel_core/database_spec.rb +964 -0
- data/spec/sequel_core/dataset_spec.rb +2977 -0
- data/spec/sequel_core/expression_filters_spec.rb +346 -0
- data/spec/sequel_core/migration_spec.rb +261 -0
- data/spec/sequel_core/object_graph_spec.rb +234 -0
- data/spec/sequel_core/pretty_table_spec.rb +58 -0
- data/spec/sequel_core/schema_generator_spec.rb +122 -0
- data/spec/sequel_core/schema_spec.rb +497 -0
- data/spec/sequel_core/spec_helper.rb +51 -0
- data/spec/{association_reflection_spec.rb → sequel_model/association_reflection_spec.rb} +6 -6
- data/spec/{associations_spec.rb → sequel_model/associations_spec.rb} +47 -18
- data/spec/{base_spec.rb → sequel_model/base_spec.rb} +2 -1
- data/spec/{caching_spec.rb → sequel_model/caching_spec.rb} +0 -0
- data/spec/{dataset_methods_spec.rb → sequel_model/dataset_methods_spec.rb} +13 -1
- data/spec/{eager_loading_spec.rb → sequel_model/eager_loading_spec.rb} +75 -14
- data/spec/{hooks_spec.rb → sequel_model/hooks_spec.rb} +4 -4
- data/spec/sequel_model/inflector_spec.rb +119 -0
- data/spec/{model_spec.rb → sequel_model/model_spec.rb} +30 -11
- data/spec/{plugins_spec.rb → sequel_model/plugins_spec.rb} +0 -0
- data/spec/{record_spec.rb → sequel_model/record_spec.rb} +47 -6
- data/spec/{schema_spec.rb → sequel_model/schema_spec.rb} +18 -4
- data/spec/{spec_helper.rb → sequel_model/spec_helper.rb} +3 -2
- data/spec/{validations_spec.rb → sequel_model/validations_spec.rb} +37 -17
- data/spec/spec_config.rb +9 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +110 -37
- data/spec/inflector_spec.rb +0 -34
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
unless Object.const_defined?('Sequel')
|
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
|
|
4
|
+
require 'sequel_core'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class MockDataset < Sequel::Dataset
|
|
8
|
+
def insert(*args)
|
|
9
|
+
@db.execute insert_sql(*args)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def update(*args)
|
|
13
|
+
@db.execute update_sql(*args)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def fetch_rows(sql)
|
|
17
|
+
@db.execute(sql)
|
|
18
|
+
yield({:id => 1, :x => 1})
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def quoted_identifier(c)
|
|
22
|
+
"\"#{c}\""
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class MockDatabase < Sequel::Database
|
|
27
|
+
@@quote_identifiers = false
|
|
28
|
+
attr_reader :sqls
|
|
29
|
+
|
|
30
|
+
def execute(sql)
|
|
31
|
+
@sqls ||= []
|
|
32
|
+
@sqls << sql
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def reset
|
|
36
|
+
@sqls = []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def transaction; yield; end
|
|
40
|
+
|
|
41
|
+
def dataset; MockDataset.new(self); end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class SchemaDummyDatabase < Sequel::Database
|
|
45
|
+
attr_reader :sqls
|
|
46
|
+
|
|
47
|
+
def execute(sql)
|
|
48
|
+
@sqls ||= []
|
|
49
|
+
@sqls << sql
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -3,7 +3,7 @@ require File.join(File.dirname(__FILE__), "spec_helper")
|
|
|
3
3
|
describe Sequel::Model::Associations::AssociationReflection, "#associated_class" do
|
|
4
4
|
before do
|
|
5
5
|
@c = Class.new(Sequel::Model)
|
|
6
|
-
class ParParent < Sequel::Model; end
|
|
6
|
+
class ::ParParent < Sequel::Model; end
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
it "should use the :class value if present" do
|
|
@@ -21,7 +21,7 @@ end
|
|
|
21
21
|
describe Sequel::Model::Associations::AssociationReflection, "#associated_primary_key" do
|
|
22
22
|
before do
|
|
23
23
|
@c = Class.new(Sequel::Model)
|
|
24
|
-
class ParParent < Sequel::Model; end
|
|
24
|
+
class ::ParParent < Sequel::Model; end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
it "should use the :right_primary_key value if present" do
|
|
@@ -46,9 +46,9 @@ describe Sequel::Model::Associations::AssociationReflection, "#reciprocal" do
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
it "should figure out the reciprocal if the :reciprocal value is not present" do
|
|
49
|
-
class ParParent < Sequel::Model; end
|
|
50
|
-
class ParParentTwo < Sequel::Model; end
|
|
51
|
-
class ParParentThree < Sequel::Model; end
|
|
49
|
+
class ::ParParent < Sequel::Model; end
|
|
50
|
+
class ::ParParentTwo < Sequel::Model; end
|
|
51
|
+
class ::ParParentThree < Sequel::Model; end
|
|
52
52
|
ParParent.many_to_one :par_parent_two
|
|
53
53
|
ParParentTwo.one_to_many :par_parents
|
|
54
54
|
ParParent.many_to_many :par_parent_threes
|
|
@@ -68,7 +68,7 @@ end
|
|
|
68
68
|
describe Sequel::Model::Associations::AssociationReflection, "#select" do
|
|
69
69
|
before do
|
|
70
70
|
@c = Class.new(Sequel::Model)
|
|
71
|
-
class ParParent < Sequel::Model; end
|
|
71
|
+
class ::ParParent < Sequel::Model; end
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
it "should use the :select value if present" do
|
|
@@ -4,7 +4,7 @@ describe Sequel::Model, "associate" do
|
|
|
4
4
|
it "should use explicit class if given a class, symbol, or string" do
|
|
5
5
|
MODEL_DB.reset
|
|
6
6
|
klass = Class.new(Sequel::Model(:nodes))
|
|
7
|
-
class ParParent < Sequel::Model
|
|
7
|
+
class ::ParParent < Sequel::Model
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
klass.associate :many_to_one, :par_parent0, :class=>ParParent
|
|
@@ -48,6 +48,7 @@ describe Sequel::Model, "many_to_one" do
|
|
|
48
48
|
MODEL_DB.reset
|
|
49
49
|
|
|
50
50
|
@c2 = Class.new(Sequel::Model(:nodes)) do
|
|
51
|
+
unrestrict_primary_key
|
|
51
52
|
columns :id, :parent_id, :par_parent_id, :blah
|
|
52
53
|
end
|
|
53
54
|
|
|
@@ -66,7 +67,7 @@ describe Sequel::Model, "many_to_one" do
|
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
it "should use implicit class if omitted" do
|
|
69
|
-
class ParParent < Sequel::Model
|
|
70
|
+
class ::ParParent < Sequel::Model
|
|
70
71
|
end
|
|
71
72
|
|
|
72
73
|
@c2.many_to_one :par_parent
|
|
@@ -79,7 +80,7 @@ describe Sequel::Model, "many_to_one" do
|
|
|
79
80
|
end
|
|
80
81
|
|
|
81
82
|
it "should use class inside module if given as a string" do
|
|
82
|
-
module Par
|
|
83
|
+
module ::Par
|
|
83
84
|
class Parent < Sequel::Model
|
|
84
85
|
end
|
|
85
86
|
end
|
|
@@ -263,10 +264,29 @@ describe Sequel::Model, "many_to_one" do
|
|
|
263
264
|
MODEL_DB.sqls.should == []
|
|
264
265
|
end
|
|
265
266
|
|
|
267
|
+
it "should get all matching records and only return the first if :key option is set to nil" do
|
|
268
|
+
c2 = @c2
|
|
269
|
+
@c2.one_to_many :children, :class => @c2, :key=>:parent_id
|
|
270
|
+
@c2.many_to_one :first_grand_parent, :class => @c2, :key=>nil, :eager_graph=>:children, :dataset=>proc{c2.filter(:children_id=>parent_id)}
|
|
271
|
+
ds = @c2.dataset
|
|
272
|
+
def ds.columns
|
|
273
|
+
[:id, :parent_id, :par_parent_id, :blah]
|
|
274
|
+
end
|
|
275
|
+
def ds.fetch_rows(sql, &block)
|
|
276
|
+
MODEL_DB.sqls << sql
|
|
277
|
+
yield({:id=>1, :parent_id=>0, :par_parent_id=>3, :blah=>4, :children_id=>2, :children_parent_id=>1, :children_par_parent_id=>5, :children_blah=>6})
|
|
278
|
+
end
|
|
279
|
+
p = @c2.new(:parent_id=>2)
|
|
280
|
+
fgp = p.first_grand_parent
|
|
281
|
+
MODEL_DB.sqls.should == ["SELECT nodes.id, nodes.parent_id, nodes.par_parent_id, nodes.blah, children.id AS children_id, children.parent_id AS children_parent_id, children.par_parent_id AS children_par_parent_id, children.blah AS children_blah FROM nodes LEFT OUTER JOIN nodes AS children ON (children.parent_id = nodes.id) WHERE (children_id = 2)"]
|
|
282
|
+
fgp.values.should == {:id=>1, :parent_id=>0, :par_parent_id=>3, :blah=>4}
|
|
283
|
+
fgp.children.first.values.should == {:id=>2, :parent_id=>1, :par_parent_id=>5, :blah=>6}
|
|
284
|
+
end
|
|
285
|
+
|
|
266
286
|
it "should not create the setter method if :read_only option is used" do
|
|
267
287
|
@c2.many_to_one :parent, :class => @c2, :read_only=>true
|
|
268
|
-
@c2.instance_methods.should(include('parent'))
|
|
269
|
-
@c2.instance_methods.should_not(include('parent='))
|
|
288
|
+
@c2.instance_methods.collect{|x| x.to_s}.should(include('parent'))
|
|
289
|
+
@c2.instance_methods.collect{|x| x.to_s}.should_not(include('parent='))
|
|
270
290
|
end
|
|
271
291
|
|
|
272
292
|
it "should raise an error if trying to set a model object that doesn't have a valid primary key" do
|
|
@@ -292,7 +312,7 @@ describe Sequel::Model, "many_to_one" do
|
|
|
292
312
|
|
|
293
313
|
it "should make the change to the foreign_key value inside a _association= method" do
|
|
294
314
|
@c2.many_to_one :parent, :class => @c2
|
|
295
|
-
@c2.private_instance_methods.sort.should(include("_parent="))
|
|
315
|
+
@c2.private_instance_methods.collect{|x| x.to_s}.sort.should(include("_parent="))
|
|
296
316
|
p = @c2.new
|
|
297
317
|
c = @c2.load(:id=>123)
|
|
298
318
|
def p._parent=(x)
|
|
@@ -362,6 +382,11 @@ describe Sequel::Model, "many_to_one" do
|
|
|
362
382
|
proc{p.parent = nil}.should raise_error(Sequel::Error)
|
|
363
383
|
end
|
|
364
384
|
|
|
385
|
+
it "should raise an error if a callback is not a proc or symbol" do
|
|
386
|
+
@c2.many_to_one :parent, :class => @c2, :before_add=>Object.new
|
|
387
|
+
proc{@c2.new.parent = @c2.load(:id=>1)}.should raise_error(Sequel::Error)
|
|
388
|
+
end
|
|
389
|
+
|
|
365
390
|
it "should call the remove callbacks for the previous object and the add callbacks for the new object" do
|
|
366
391
|
c = @c2.load(:id=>123)
|
|
367
392
|
d = @c2.load(:id=>321)
|
|
@@ -398,10 +423,12 @@ describe Sequel::Model, "one_to_many" do
|
|
|
398
423
|
MODEL_DB.reset
|
|
399
424
|
|
|
400
425
|
@c1 = Class.new(Sequel::Model(:attributes)) do
|
|
426
|
+
unrestrict_primary_key
|
|
401
427
|
columns :id, :node_id
|
|
402
428
|
end
|
|
403
429
|
|
|
404
430
|
@c2 = Class.new(Sequel::Model(:nodes)) do
|
|
431
|
+
unrestrict_primary_key
|
|
405
432
|
attr_accessor :xxx
|
|
406
433
|
|
|
407
434
|
def self.name; 'Node'; end
|
|
@@ -435,7 +462,7 @@ describe Sequel::Model, "one_to_many" do
|
|
|
435
462
|
end
|
|
436
463
|
|
|
437
464
|
it "should use implicit class if omitted" do
|
|
438
|
-
class HistoricalValue < Sequel::Model
|
|
465
|
+
class ::HistoricalValue < Sequel::Model
|
|
439
466
|
end
|
|
440
467
|
|
|
441
468
|
@c2.one_to_many :historical_values
|
|
@@ -448,7 +475,7 @@ describe Sequel::Model, "one_to_many" do
|
|
|
448
475
|
end
|
|
449
476
|
|
|
450
477
|
it "should use class inside a module if given as a string" do
|
|
451
|
-
module Historical
|
|
478
|
+
module ::Historical
|
|
452
479
|
class Value < Sequel::Model
|
|
453
480
|
end
|
|
454
481
|
end
|
|
@@ -692,7 +719,7 @@ describe Sequel::Model, "one_to_many" do
|
|
|
692
719
|
|
|
693
720
|
it "should not create the add_, remove_, or remove_all_ methods if :read_only option is used" do
|
|
694
721
|
@c2.one_to_many :attributes, :class => @c1, :read_only=>true
|
|
695
|
-
im = @c2.instance_methods
|
|
722
|
+
im = @c2.instance_methods.collect{|x| x.to_s}
|
|
696
723
|
im.should(include('attributes'))
|
|
697
724
|
im.should(include('attributes_dataset'))
|
|
698
725
|
im.should_not(include('add_attribute'))
|
|
@@ -803,7 +830,7 @@ describe Sequel::Model, "one_to_many" do
|
|
|
803
830
|
|
|
804
831
|
it "should not add a getter method if the :one_to_one option is true and :read_only option is true" do
|
|
805
832
|
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true, :read_only=>true
|
|
806
|
-
im = @c2.instance_methods
|
|
833
|
+
im = @c2.instance_methods.collect{|x| x.to_s}
|
|
807
834
|
im.should(include('attribute'))
|
|
808
835
|
im.should_not(include('attribute='))
|
|
809
836
|
end
|
|
@@ -846,7 +873,7 @@ describe Sequel::Model, "one_to_many" do
|
|
|
846
873
|
|
|
847
874
|
it "should make non getter and setter methods private if :one_to_one option is used" do
|
|
848
875
|
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true do |ds| end
|
|
849
|
-
meths = @c2.private_instance_methods(false)
|
|
876
|
+
meths = @c2.private_instance_methods(false).collect{|x| x.to_s}
|
|
850
877
|
meths.should(include("attributes"))
|
|
851
878
|
meths.should(include("add_attribute"))
|
|
852
879
|
meths.should(include("attributes_dataset"))
|
|
@@ -854,7 +881,7 @@ describe Sequel::Model, "one_to_many" do
|
|
|
854
881
|
|
|
855
882
|
it "should call an _add_ method internally to add attributes" do
|
|
856
883
|
@c2.one_to_many :attributes, :class => @c1
|
|
857
|
-
@c2.private_instance_methods.sort.should(include("_add_attribute"))
|
|
884
|
+
@c2.private_instance_methods.collect{|x| x.to_s}.sort.should(include("_add_attribute"))
|
|
858
885
|
p = @c2.load(:id=>10)
|
|
859
886
|
c = @c1.load(:id=>123)
|
|
860
887
|
def p._add_attribute(x)
|
|
@@ -867,7 +894,7 @@ describe Sequel::Model, "one_to_many" do
|
|
|
867
894
|
|
|
868
895
|
it "should call a _remove_ method internally to remove attributes" do
|
|
869
896
|
@c2.one_to_many :attributes, :class => @c1
|
|
870
|
-
@c2.private_instance_methods.sort.should(include("_remove_attribute"))
|
|
897
|
+
@c2.private_instance_methods.collect{|x| x.to_s}.sort.should(include("_remove_attribute"))
|
|
871
898
|
p = @c2.load(:id=>10)
|
|
872
899
|
c = @c1.load(:id=>123)
|
|
873
900
|
def p._remove_attribute(x)
|
|
@@ -966,12 +993,14 @@ describe Sequel::Model, "many_to_many" do
|
|
|
966
993
|
MODEL_DB.reset
|
|
967
994
|
|
|
968
995
|
@c1 = Class.new(Sequel::Model(:attributes)) do
|
|
996
|
+
unrestrict_primary_key
|
|
969
997
|
def self.name; 'Attribute'; end
|
|
970
998
|
def self.to_s; 'Attribute'; end
|
|
971
999
|
columns :id
|
|
972
1000
|
end
|
|
973
1001
|
|
|
974
1002
|
@c2 = Class.new(Sequel::Model(:nodes)) do
|
|
1003
|
+
unrestrict_primary_key
|
|
975
1004
|
attr_accessor :xxx
|
|
976
1005
|
|
|
977
1006
|
def self.name; 'Node'; end
|
|
@@ -1000,7 +1029,7 @@ describe Sequel::Model, "many_to_many" do
|
|
|
1000
1029
|
end
|
|
1001
1030
|
|
|
1002
1031
|
it "should use implicit class if omitted" do
|
|
1003
|
-
class Tag < Sequel::Model
|
|
1032
|
+
class ::Tag < Sequel::Model
|
|
1004
1033
|
end
|
|
1005
1034
|
|
|
1006
1035
|
@c2.many_to_many :tags
|
|
@@ -1012,7 +1041,7 @@ describe Sequel::Model, "many_to_many" do
|
|
|
1012
1041
|
end
|
|
1013
1042
|
|
|
1014
1043
|
it "should use class inside module if given as a string" do
|
|
1015
|
-
module Historical
|
|
1044
|
+
module ::Historical
|
|
1016
1045
|
class Tag < Sequel::Model
|
|
1017
1046
|
end
|
|
1018
1047
|
end
|
|
@@ -1263,7 +1292,7 @@ describe Sequel::Model, "many_to_many" do
|
|
|
1263
1292
|
|
|
1264
1293
|
it "should not create the add_, remove_, or remove_all_ methods if :read_only option is used" do
|
|
1265
1294
|
@c2.many_to_many :attributes, :class => @c1, :read_only=>true
|
|
1266
|
-
im = @c2.instance_methods
|
|
1295
|
+
im = @c2.instance_methods.collect{|x| x.to_s}
|
|
1267
1296
|
im.should(include('attributes'))
|
|
1268
1297
|
im.should(include('attributes_dataset'))
|
|
1269
1298
|
im.should_not(include('add_attribute'))
|
|
@@ -1329,7 +1358,7 @@ describe Sequel::Model, "many_to_many" do
|
|
|
1329
1358
|
|
|
1330
1359
|
it "should call an _add_ method internally to add attributes" do
|
|
1331
1360
|
@c2.many_to_many :attributes, :class => @c1
|
|
1332
|
-
@c2.private_instance_methods.sort.should(include("_add_attribute"))
|
|
1361
|
+
@c2.private_instance_methods.collect{|x| x.to_s}.sort.should(include("_add_attribute"))
|
|
1333
1362
|
p = @c2.load(:id=>10)
|
|
1334
1363
|
c = @c1.load(:id=>123)
|
|
1335
1364
|
def p._add_attribute(x)
|
|
@@ -1342,7 +1371,7 @@ describe Sequel::Model, "many_to_many" do
|
|
|
1342
1371
|
|
|
1343
1372
|
it "should call a _remove_ method internally to remove attributes" do
|
|
1344
1373
|
@c2.many_to_many :attributes, :class => @c1
|
|
1345
|
-
@c2.private_instance_methods.sort.should(include("_remove_attribute"))
|
|
1374
|
+
@c2.private_instance_methods.collect{|x| x.to_s}.sort.should(include("_remove_attribute"))
|
|
1346
1375
|
p = @c2.load(:id=>10)
|
|
1347
1376
|
c = @c1.load(:id=>123)
|
|
1348
1377
|
def p._remove_attribute(x)
|
|
@@ -79,10 +79,11 @@ describe "Model#serialize" do
|
|
|
79
79
|
|
|
80
80
|
@c.create(:abc => 1)
|
|
81
81
|
@c.create(:abc => "hello")
|
|
82
|
+
x = [Marshal.dump("hello")].pack('m')
|
|
82
83
|
|
|
83
84
|
MODEL_DB.sqls.should == [ \
|
|
84
85
|
"INSERT INTO items (abc) VALUES ('BAhpBg==\n')", \
|
|
85
|
-
"INSERT INTO items (abc) VALUES ('
|
|
86
|
+
"INSERT INTO items (abc) VALUES ('#{x}')", \
|
|
86
87
|
]
|
|
87
88
|
end
|
|
88
89
|
|
|
File without changes
|
|
@@ -56,7 +56,19 @@ describe Sequel::Model::DatasetMethods, "#to_hash" do
|
|
|
56
56
|
h.should be_a_kind_of(Hash)
|
|
57
57
|
a = h.to_a
|
|
58
58
|
a.collect{|x| x[1].class}.should == [@c, @c]
|
|
59
|
-
[[[
|
|
59
|
+
a.sort_by{|x| x[0]}.collect{|x| [x[0], x[1].values]}.should == [[1, {:name=>1}], [2, {:name=>2}]]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should result in a hash with given value keys and model object values" do
|
|
63
|
+
def @d.fetch_rows(sql)
|
|
64
|
+
yield({:name=>1, :number=>3})
|
|
65
|
+
yield({:name=>2, :number=>4})
|
|
66
|
+
end
|
|
67
|
+
h = @d.to_hash(:number)
|
|
68
|
+
h.should be_a_kind_of(Hash)
|
|
69
|
+
a = h.to_a
|
|
70
|
+
a.collect{|x| x[1].class}.should == [@c, @c]
|
|
71
|
+
a.sort_by{|x| x[0]}.collect{|x| [x[0], x[1].values]}.should == [[3, {:name=>1, :number=>3}], [4, {:name=>2, :number=>4}]]
|
|
60
72
|
end
|
|
61
73
|
|
|
62
74
|
it "should raise an error if the class doesn't have a primary key" do
|
|
@@ -4,7 +4,7 @@ describe Sequel::Model, "#eager" do
|
|
|
4
4
|
before(:each) do
|
|
5
5
|
MODEL_DB.reset
|
|
6
6
|
|
|
7
|
-
class EagerAlbum < Sequel::Model(:albums)
|
|
7
|
+
class ::EagerAlbum < Sequel::Model(:albums)
|
|
8
8
|
columns :id, :band_id
|
|
9
9
|
many_to_one :band, :class=>'EagerBand', :key=>:band_id
|
|
10
10
|
one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id
|
|
@@ -17,7 +17,7 @@ describe Sequel::Model, "#eager" do
|
|
|
17
17
|
many_to_many :genre_names, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :select=>[:id]
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
class EagerBand < Sequel::Model(:bands)
|
|
20
|
+
class ::EagerBand < Sequel::Model(:bands)
|
|
21
21
|
columns :id
|
|
22
22
|
one_to_many :albums, :class=>'EagerAlbum', :key=>:band_id, :eager=>:tracks
|
|
23
23
|
one_to_many :graph_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_graph=>:tracks
|
|
@@ -32,17 +32,17 @@ describe Sequel::Model, "#eager" do
|
|
|
32
32
|
one_to_many :top_10_albums, :class=>'EagerAlbum', :key=>:band_id, :limit=>10
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
class EagerTrack < Sequel::Model(:tracks)
|
|
35
|
+
class ::EagerTrack < Sequel::Model(:tracks)
|
|
36
36
|
columns :id, :album_id
|
|
37
37
|
many_to_one :album, :class=>'EagerAlbum', :key=>:album_id
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
class EagerGenre < Sequel::Model(:genres)
|
|
40
|
+
class ::EagerGenre < Sequel::Model(:genres)
|
|
41
41
|
columns :id
|
|
42
42
|
many_to_many :albums, :class=>'EagerAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
class EagerBandMember < Sequel::Model(:members)
|
|
45
|
+
class ::EagerBandMember < Sequel::Model(:members)
|
|
46
46
|
columns :id
|
|
47
47
|
many_to_many :bands, :class=>'EagerBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm, :order =>:id
|
|
48
48
|
end
|
|
@@ -106,6 +106,10 @@ describe Sequel::Model, "#eager" do
|
|
|
106
106
|
})
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
+
it "should raise an error if called without a symbol or hash" do
|
|
110
|
+
proc{EagerAlbum.eager(Object.new)}.should raise_error(Sequel::Error)
|
|
111
|
+
end
|
|
112
|
+
|
|
109
113
|
it "should eagerly load a single many_to_one association" do
|
|
110
114
|
a = EagerAlbum.eager(:band).all
|
|
111
115
|
a.should be_a_kind_of(Array)
|
|
@@ -149,7 +153,7 @@ describe Sequel::Model, "#eager" do
|
|
|
149
153
|
MODEL_DB.sqls.length.should == 2
|
|
150
154
|
end
|
|
151
155
|
|
|
152
|
-
it "should eagerly load multiple associations" do
|
|
156
|
+
it "should eagerly load multiple associations in a single call" do
|
|
153
157
|
a = EagerAlbum.eager(:genres, :tracks, :band).all
|
|
154
158
|
a.should be_a_kind_of(Array)
|
|
155
159
|
a.size.should == 1
|
|
@@ -174,6 +178,31 @@ describe Sequel::Model, "#eager" do
|
|
|
174
178
|
MODEL_DB.sqls.length.should == 4
|
|
175
179
|
end
|
|
176
180
|
|
|
181
|
+
it "should eagerly load multiple associations in separate calls" do
|
|
182
|
+
a = EagerAlbum.eager(:genres).eager(:tracks).eager(:band).all
|
|
183
|
+
a.should be_a_kind_of(Array)
|
|
184
|
+
a.size.should == 1
|
|
185
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
|
186
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
|
187
|
+
MODEL_DB.sqls.length.should == 4
|
|
188
|
+
MODEL_DB.sqls[0].should == 'SELECT * FROM albums'
|
|
189
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM bands WHERE (bands.id IN (2))'))
|
|
190
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM tracks WHERE (tracks.album_id IN (1))'))
|
|
191
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))'))
|
|
192
|
+
a = a.first
|
|
193
|
+
a.band.should be_a_kind_of(EagerBand)
|
|
194
|
+
a.band.values.should == {:id => 2}
|
|
195
|
+
a.tracks.should be_a_kind_of(Array)
|
|
196
|
+
a.tracks.size.should == 1
|
|
197
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
|
198
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
|
199
|
+
a.genres.should be_a_kind_of(Array)
|
|
200
|
+
a.genres.size.should == 1
|
|
201
|
+
a.genres.first.should be_a_kind_of(EagerGenre)
|
|
202
|
+
a.genres.first.values.should == {:id => 4}
|
|
203
|
+
MODEL_DB.sqls.length.should == 4
|
|
204
|
+
end
|
|
205
|
+
|
|
177
206
|
it "should allow cascading of eager loading for associations of associated models" do
|
|
178
207
|
a = EagerTrack.eager(:album=>{:band=>:members}).all
|
|
179
208
|
a.should be_a_kind_of(Array)
|
|
@@ -430,13 +459,13 @@ end
|
|
|
430
459
|
|
|
431
460
|
describe Sequel::Model, "#eager_graph" do
|
|
432
461
|
after(:all) do
|
|
433
|
-
class MockDataset
|
|
462
|
+
class ::MockDataset
|
|
434
463
|
alias clone orig_clone
|
|
435
464
|
end
|
|
436
465
|
end
|
|
437
466
|
|
|
438
467
|
before(:all) do
|
|
439
|
-
class MockDataset
|
|
468
|
+
class ::MockDataset
|
|
440
469
|
alias orig_clone clone
|
|
441
470
|
def clone(opts = {})
|
|
442
471
|
c = super()
|
|
@@ -446,15 +475,16 @@ describe Sequel::Model, "#eager_graph" do
|
|
|
446
475
|
end
|
|
447
476
|
end
|
|
448
477
|
|
|
449
|
-
class GraphAlbum < Sequel::Model(:albums)
|
|
478
|
+
class ::GraphAlbum < Sequel::Model(:albums)
|
|
450
479
|
dataset.opts[:from] = [:albums]
|
|
451
480
|
columns :id, :band_id
|
|
452
481
|
many_to_one :band, :class=>'GraphBand', :key=>:band_id
|
|
453
482
|
one_to_many :tracks, :class=>'GraphTrack', :key=>:album_id
|
|
454
483
|
many_to_many :genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
|
|
484
|
+
many_to_one :previous_album, :class=>'GraphAlbum'
|
|
455
485
|
end
|
|
456
486
|
|
|
457
|
-
class GraphBand < Sequel::Model(:bands)
|
|
487
|
+
class ::GraphBand < Sequel::Model(:bands)
|
|
458
488
|
dataset.opts[:from] = [:bands]
|
|
459
489
|
columns :id, :vocalist_id
|
|
460
490
|
many_to_one :vocalist, :class=>'GraphBandMember', :key=>:vocalist_id
|
|
@@ -463,25 +493,29 @@ describe Sequel::Model, "#eager_graph" do
|
|
|
463
493
|
many_to_many :genres, :class=>'GraphGenre', :left_key=>:band_id, :right_key=>:genre_id, :join_table=>:bg
|
|
464
494
|
end
|
|
465
495
|
|
|
466
|
-
class GraphTrack < Sequel::Model(:tracks)
|
|
496
|
+
class ::GraphTrack < Sequel::Model(:tracks)
|
|
467
497
|
dataset.opts[:from] = [:tracks]
|
|
468
498
|
columns :id, :album_id
|
|
469
499
|
many_to_one :album, :class=>'GraphAlbum', :key=>:album_id
|
|
470
500
|
end
|
|
471
501
|
|
|
472
|
-
class GraphGenre < Sequel::Model(:genres)
|
|
502
|
+
class ::GraphGenre < Sequel::Model(:genres)
|
|
473
503
|
dataset.opts[:from] = [:genres]
|
|
474
504
|
columns :id
|
|
475
505
|
many_to_many :albums, :class=>'GraphAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
|
|
476
506
|
end
|
|
477
507
|
|
|
478
|
-
class GraphBandMember < Sequel::Model(:members)
|
|
508
|
+
class ::GraphBandMember < Sequel::Model(:members)
|
|
479
509
|
dataset.opts[:from] = [:members]
|
|
480
510
|
columns :id
|
|
481
511
|
many_to_many :bands, :class=>'GraphBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm
|
|
482
512
|
end
|
|
483
513
|
end
|
|
484
514
|
|
|
515
|
+
it "should raise an error if called without a symbol or hash" do
|
|
516
|
+
proc{GraphAlbum.eager_graph(Object.new)}.should raise_error(Sequel::Error)
|
|
517
|
+
end
|
|
518
|
+
|
|
485
519
|
it "should eagerly load a single many_to_one association" do
|
|
486
520
|
ds = GraphAlbum.eager_graph(:band)
|
|
487
521
|
ds.sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
|
@@ -534,7 +568,7 @@ describe Sequel::Model, "#eager_graph" do
|
|
|
534
568
|
a.genres.first.values.should == {:id => 4}
|
|
535
569
|
end
|
|
536
570
|
|
|
537
|
-
it "should eagerly load multiple associations" do
|
|
571
|
+
it "should eagerly load multiple associations in a single call" do
|
|
538
572
|
ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
|
|
539
573
|
ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id, tracks.id AS tracks_id, tracks.album_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
|
540
574
|
def ds.fetch_rows(sql, &block)
|
|
@@ -558,6 +592,30 @@ describe Sequel::Model, "#eager_graph" do
|
|
|
558
592
|
a.genres.first.values.should == {:id => 4}
|
|
559
593
|
end
|
|
560
594
|
|
|
595
|
+
it "should eagerly load multiple associations in separate calls" do
|
|
596
|
+
ds = GraphAlbum.eager_graph(:genres).eager_graph(:tracks).eager_graph(:band)
|
|
597
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id, tracks.id AS tracks_id, tracks.album_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
|
598
|
+
def ds.fetch_rows(sql, &block)
|
|
599
|
+
yield({:id=>1, :band_id=>2, :genres_id=>4, :tracks_id=>3, :album_id=>1, :band_id_0=>2, :vocalist_id=>6})
|
|
600
|
+
end
|
|
601
|
+
a = ds.all
|
|
602
|
+
a.should be_a_kind_of(Array)
|
|
603
|
+
a.size.should == 1
|
|
604
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
|
605
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
|
606
|
+
a = a.first
|
|
607
|
+
a.band.should be_a_kind_of(GraphBand)
|
|
608
|
+
a.band.values.should == {:id => 2, :vocalist_id=>6}
|
|
609
|
+
a.tracks.should be_a_kind_of(Array)
|
|
610
|
+
a.tracks.size.should == 1
|
|
611
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
|
612
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
|
613
|
+
a.genres.should be_a_kind_of(Array)
|
|
614
|
+
a.genres.size.should == 1
|
|
615
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
|
616
|
+
a.genres.first.values.should == {:id => 4}
|
|
617
|
+
end
|
|
618
|
+
|
|
561
619
|
it "should allow cascading of eager loading for associations of associated models" do
|
|
562
620
|
ds = GraphTrack.eager_graph(:album=>{:band=>:members})
|
|
563
621
|
ds.sql.should == 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, members.id AS members_id FROM tracks LEFT OUTER JOIN albums AS album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands AS band ON (band.id = album.band_id) LEFT OUTER JOIN bm ON (bm.band_id = band.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
|
|
@@ -900,4 +958,7 @@ describe Sequel::Model, "#eager_graph" do
|
|
|
900
958
|
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (active) LEFT OUTER JOIN genres AS active_genres ON ((price + 2) > 100)"
|
|
901
959
|
end
|
|
902
960
|
|
|
961
|
+
it "should create unique table aliases for all associations" do
|
|
962
|
+
GraphAlbum.eager_graph(:previous_album=>{:previous_album=>:previous_album}).sql.should == "SELECT albums.id, albums.band_id, previous_album.id AS previous_album_id, previous_album.band_id AS previous_album_band_id, previous_album_0.id AS previous_album_0_id, previous_album_0.band_id AS previous_album_0_band_id, previous_album_1.id AS previous_album_1_id, previous_album_1.band_id AS previous_album_1_band_id FROM albums LEFT OUTER JOIN albums AS previous_album ON (previous_album.id = albums.previous_album_id) LEFT OUTER JOIN albums AS previous_album_0 ON (previous_album_0.id = previous_album.previous_album_id) LEFT OUTER JOIN albums AS previous_album_1 ON (previous_album_1.id = previous_album_0.previous_album_id)"
|
|
963
|
+
end
|
|
903
964
|
end
|