sequel 3.37.0 → 3.38.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.
Files changed (129) hide show
  1. data/CHANGELOG +56 -0
  2. data/README.rdoc +82 -58
  3. data/Rakefile +6 -5
  4. data/bin/sequel +1 -1
  5. data/doc/active_record.rdoc +67 -52
  6. data/doc/advanced_associations.rdoc +33 -48
  7. data/doc/association_basics.rdoc +41 -51
  8. data/doc/cheat_sheet.rdoc +21 -21
  9. data/doc/core_extensions.rdoc +374 -0
  10. data/doc/dataset_basics.rdoc +5 -5
  11. data/doc/dataset_filtering.rdoc +47 -43
  12. data/doc/mass_assignment.rdoc +1 -1
  13. data/doc/migration.rdoc +4 -5
  14. data/doc/model_hooks.rdoc +3 -3
  15. data/doc/object_model.rdoc +31 -25
  16. data/doc/opening_databases.rdoc +19 -5
  17. data/doc/prepared_statements.rdoc +2 -2
  18. data/doc/querying.rdoc +109 -52
  19. data/doc/reflection.rdoc +6 -6
  20. data/doc/release_notes/3.38.0.txt +234 -0
  21. data/doc/schema_modification.rdoc +22 -13
  22. data/doc/sharding.rdoc +8 -9
  23. data/doc/sql.rdoc +154 -112
  24. data/doc/testing.rdoc +47 -7
  25. data/doc/thread_safety.rdoc +1 -1
  26. data/doc/transactions.rdoc +1 -1
  27. data/doc/validations.rdoc +1 -1
  28. data/doc/virtual_rows.rdoc +29 -43
  29. data/lib/sequel/adapters/do/postgres.rb +1 -4
  30. data/lib/sequel/adapters/jdbc.rb +14 -3
  31. data/lib/sequel/adapters/jdbc/db2.rb +9 -0
  32. data/lib/sequel/adapters/jdbc/derby.rb +41 -4
  33. data/lib/sequel/adapters/jdbc/jtds.rb +11 -0
  34. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -6
  35. data/lib/sequel/adapters/mock.rb +10 -4
  36. data/lib/sequel/adapters/postgres.rb +1 -28
  37. data/lib/sequel/adapters/shared/mssql.rb +23 -13
  38. data/lib/sequel/adapters/shared/postgres.rb +46 -0
  39. data/lib/sequel/adapters/swift.rb +21 -13
  40. data/lib/sequel/adapters/swift/mysql.rb +1 -0
  41. data/lib/sequel/adapters/swift/postgres.rb +4 -5
  42. data/lib/sequel/adapters/swift/sqlite.rb +2 -1
  43. data/lib/sequel/adapters/tinytds.rb +14 -2
  44. data/lib/sequel/adapters/utils/pg_types.rb +5 -0
  45. data/lib/sequel/core.rb +29 -17
  46. data/lib/sequel/database/query.rb +1 -1
  47. data/lib/sequel/database/schema_generator.rb +3 -0
  48. data/lib/sequel/dataset/actions.rb +5 -6
  49. data/lib/sequel/dataset/query.rb +7 -7
  50. data/lib/sequel/dataset/sql.rb +5 -18
  51. data/lib/sequel/extensions/core_extensions.rb +8 -12
  52. data/lib/sequel/extensions/pg_array.rb +59 -33
  53. data/lib/sequel/extensions/pg_array_ops.rb +32 -4
  54. data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
  55. data/lib/sequel/extensions/pg_hstore.rb +32 -17
  56. data/lib/sequel/extensions/pg_hstore_ops.rb +32 -3
  57. data/lib/sequel/extensions/pg_inet.rb +1 -2
  58. data/lib/sequel/extensions/pg_interval.rb +0 -1
  59. data/lib/sequel/extensions/pg_json.rb +41 -23
  60. data/lib/sequel/extensions/pg_range.rb +36 -11
  61. data/lib/sequel/extensions/pg_range_ops.rb +32 -4
  62. data/lib/sequel/extensions/pg_row.rb +572 -0
  63. data/lib/sequel/extensions/pg_row_ops.rb +164 -0
  64. data/lib/sequel/extensions/query.rb +3 -3
  65. data/lib/sequel/extensions/schema_dumper.rb +7 -8
  66. data/lib/sequel/extensions/select_remove.rb +1 -1
  67. data/lib/sequel/model/base.rb +1 -0
  68. data/lib/sequel/no_core_ext.rb +1 -1
  69. data/lib/sequel/plugins/pg_row.rb +121 -0
  70. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  71. data/lib/sequel/plugins/validation_helpers.rb +31 -0
  72. data/lib/sequel/sql.rb +64 -44
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/mssql_spec.rb +37 -12
  75. data/spec/adapters/mysql_spec.rb +39 -75
  76. data/spec/adapters/oracle_spec.rb +11 -11
  77. data/spec/adapters/postgres_spec.rb +414 -237
  78. data/spec/adapters/spec_helper.rb +1 -1
  79. data/spec/adapters/sqlite_spec.rb +14 -14
  80. data/spec/core/database_spec.rb +6 -6
  81. data/spec/core/dataset_spec.rb +169 -205
  82. data/spec/core/expression_filters_spec.rb +182 -295
  83. data/spec/core/object_graph_spec.rb +6 -6
  84. data/spec/core/schema_spec.rb +14 -14
  85. data/spec/core/spec_helper.rb +1 -0
  86. data/spec/{extensions/core_extensions_spec.rb → core_extensions_spec.rb} +208 -14
  87. data/spec/extensions/columns_introspection_spec.rb +5 -5
  88. data/spec/extensions/hook_class_methods_spec.rb +28 -36
  89. data/spec/extensions/many_through_many_spec.rb +4 -4
  90. data/spec/extensions/pg_array_ops_spec.rb +15 -7
  91. data/spec/extensions/pg_array_spec.rb +81 -48
  92. data/spec/extensions/pg_auto_parameterize_spec.rb +2 -2
  93. data/spec/extensions/pg_hstore_ops_spec.rb +13 -9
  94. data/spec/extensions/pg_hstore_spec.rb +66 -65
  95. data/spec/extensions/pg_inet_spec.rb +2 -4
  96. data/spec/extensions/pg_interval_spec.rb +2 -3
  97. data/spec/extensions/pg_json_spec.rb +20 -18
  98. data/spec/extensions/pg_range_ops_spec.rb +11 -4
  99. data/spec/extensions/pg_range_spec.rb +30 -7
  100. data/spec/extensions/pg_row_ops_spec.rb +48 -0
  101. data/spec/extensions/pg_row_plugin_spec.rb +45 -0
  102. data/spec/extensions/pg_row_spec.rb +323 -0
  103. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  104. data/spec/extensions/query_literals_spec.rb +11 -11
  105. data/spec/extensions/query_spec.rb +3 -3
  106. data/spec/extensions/schema_dumper_spec.rb +20 -4
  107. data/spec/extensions/schema_spec.rb +18 -41
  108. data/spec/extensions/select_remove_spec.rb +4 -4
  109. data/spec/extensions/spec_helper.rb +4 -8
  110. data/spec/extensions/to_dot_spec.rb +5 -5
  111. data/spec/extensions/validation_class_methods_spec.rb +28 -16
  112. data/spec/integration/associations_test.rb +20 -20
  113. data/spec/integration/dataset_test.rb +98 -98
  114. data/spec/integration/eager_loader_test.rb +13 -27
  115. data/spec/integration/plugin_test.rb +5 -5
  116. data/spec/integration/prepared_statement_test.rb +22 -13
  117. data/spec/integration/schema_test.rb +28 -18
  118. data/spec/integration/spec_helper.rb +1 -1
  119. data/spec/integration/timezone_test.rb +2 -2
  120. data/spec/integration/type_test.rb +15 -6
  121. data/spec/model/association_reflection_spec.rb +1 -1
  122. data/spec/model/associations_spec.rb +4 -4
  123. data/spec/model/base_spec.rb +5 -5
  124. data/spec/model/eager_loading_spec.rb +15 -15
  125. data/spec/model/model_spec.rb +32 -32
  126. data/spec/model/record_spec.rb +16 -0
  127. data/spec/model/spec_helper.rb +2 -6
  128. data/spec/model/validations_spec.rb +1 -1
  129. metadata +16 -4
@@ -0,0 +1,58 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe Sequel::Model, "PgTypecastOnLoad plugin" do
4
+ before do
5
+ @db = Sequel.mock(:host=>'postgres', :fetch=>{:id=>1, :b=>"t", :y=>"0"}, :columns=>[:id, :b, :y], :numrows=>1)
6
+ def @db.schema(*args)
7
+ [[:id, {}], [:b, {:type=>:boolean, :oid=>16}], [:y, {:type=>:integer, :oid=>20}]]
8
+ end
9
+ @c = Class.new(Sequel::Model(@db[:items]))
10
+ @c.plugin :pg_typecast_on_load, :b, :y
11
+ end
12
+
13
+ specify "should call the database conversion proc for all given columns" do
14
+ @c.first.values.should == {:id=>1, :b=>true, :y=>0}
15
+ end
16
+
17
+ specify "should call the database conversion proc with value when reloading the object, for all given columns" do
18
+ @c.first.refresh.values.should == {:id=>1, :b=>true, :y=>0}
19
+ end
20
+
21
+ specify "should call the database conversion proc with value when automatically reloading the object on creation via insert_select" do
22
+ @c.dataset.meta_def(:insert_select){|h| insert(h); first}
23
+ @c.create.values.should == {:id=>1, :b=>true, :y=>0}
24
+ end
25
+
26
+ specify "should allowing setting columns separately via add_typecast_on_load_columns" do
27
+ @c = Class.new(Sequel::Model(@db[:items]))
28
+ @c.plugin :pg_typecast_on_load
29
+ @c.first.values.should == {:id=>1, :b=>"t", :y=>"0"}
30
+ @c.add_pg_typecast_on_load_columns :b
31
+ @c.first.values.should == {:id=>1, :b=>true, :y=>"0"}
32
+ @c.add_pg_typecast_on_load_columns :y
33
+ @c.first.values.should == {:id=>1, :b=>true, :y=>0}
34
+ end
35
+
36
+ specify "should work with subclasses" do
37
+ @c = Class.new(Sequel::Model(@db[:items]))
38
+ @c.plugin :pg_typecast_on_load
39
+ @c.first.values.should == {:id=>1, :b=>"t", :y=>"0"}
40
+
41
+ c1 = Class.new(@c)
42
+ @c.add_pg_typecast_on_load_columns :b
43
+ @c.first.values.should == {:id=>1, :b=>true, :y=>"0"}
44
+ c1.first.values.should == {:id=>1, :b=>"t", :y=>"0"}
45
+
46
+ c2 = Class.new(@c)
47
+ @c.add_pg_typecast_on_load_columns :y
48
+ @c.first.values.should == {:id=>1, :b=>true, :y=>0}
49
+ c2.first.values.should == {:id=>1, :b=>true, :y=>"0"}
50
+
51
+ c1.add_pg_typecast_on_load_columns :y
52
+ c1.first.values.should == {:id=>1, :b=>"t", :y=>0}
53
+ end
54
+
55
+ specify "should not mark the object as modified" do
56
+ @c.first.modified?.should == false
57
+ end
58
+ end
@@ -18,7 +18,7 @@ describe "query_literals extension" do
18
18
  end
19
19
 
20
20
  it "should have #select work the standard way if initial string is a literal string already" do
21
- @ds.select('a, b, ?'.lit, 1).sql.should == 'SELECT a, b, ?, 1 FROM t'
21
+ @ds.select(Sequel.lit('a, b, ?'), 1).sql.should == 'SELECT a, b, ?, 1 FROM t'
22
22
  end
23
23
 
24
24
  it "should have #select work regularly if not given a string as the first argument" do
@@ -39,7 +39,7 @@ describe "query_literals extension" do
39
39
  end
40
40
 
41
41
  it "should have #select_more work the standard way if initial string is a literal string already" do
42
- @ds.select_more('a, b, ?'.lit, 1).sql.should == 'SELECT d, a, b, ?, 1 FROM t'
42
+ @ds.select_more(Sequel.lit('a, b, ?'), 1).sql.should == 'SELECT d, a, b, ?, 1 FROM t'
43
43
  end
44
44
 
45
45
  it "should have #select_more work regularly if not given a string as the first argument" do
@@ -56,7 +56,7 @@ describe "query_literals extension" do
56
56
  end
57
57
 
58
58
  it "should have #select_append work the standard way if initial string is a literal string already" do
59
- @ds.select_append('a, b, ?'.lit, 1).sql.should == 'SELECT *, a, b, ?, 1 FROM t'
59
+ @ds.select_append(Sequel.lit('a, b, ?'), 1).sql.should == 'SELECT *, a, b, ?, 1 FROM t'
60
60
  end
61
61
 
62
62
  it "should have #select_append work regularly if not given a string as the first argument" do
@@ -72,7 +72,7 @@ describe "query_literals extension" do
72
72
  end
73
73
 
74
74
  it "should have #select_group work the standard way if initial string is a literal string already" do
75
- @ds.select_group('a, b, ?'.lit, 1).sql.should == 'SELECT a, b, ?, 1 FROM t GROUP BY a, b, ?, 1'
75
+ @ds.select_group(Sequel.lit('a, b, ?'), 1).sql.should == 'SELECT a, b, ?, 1 FROM t GROUP BY a, b, ?, 1'
76
76
  end
77
77
 
78
78
  it "should have #select_group work regularly if not given a string as the first argument" do
@@ -87,11 +87,11 @@ describe "query_literals extension" do
87
87
  @ds.group('a, b, ?', 1).sql.should == 'SELECT * FROM t GROUP BY a, b, 1'
88
88
  end
89
89
 
90
- it "should have #select_group work the standard way if initial string is a literal string already" do
91
- @ds.group('a, b, ?'.lit, 1).sql.should == 'SELECT * FROM t GROUP BY a, b, ?, 1'
90
+ it "should have #group work the standard way if initial string is a literal string already" do
91
+ @ds.group(Sequel.lit('a, b, ?'), 1).sql.should == 'SELECT * FROM t GROUP BY a, b, ?, 1'
92
92
  end
93
93
 
94
- it "should have #select_group work regularly if not given a string as the first argument" do
94
+ it "should have #group work regularly if not given a string as the first argument" do
95
95
  @ds.group(:a, 1).sql.should == 'SELECT * FROM t GROUP BY a, 1'
96
96
  end
97
97
 
@@ -104,7 +104,7 @@ describe "query_literals extension" do
104
104
  end
105
105
 
106
106
  it "should have #group_and_count work the standard way if initial string is a literal string already" do
107
- @ds.group_and_count('a, b, ?'.lit, 1).sql.should == 'SELECT a, b, ?, 1, count(*) AS count FROM t GROUP BY a, b, ?, 1'
107
+ @ds.group_and_count(Sequel.lit('a, b, ?'), 1).sql.should == 'SELECT a, b, ?, 1, count(*) AS count FROM t GROUP BY a, b, ?, 1'
108
108
  end
109
109
 
110
110
  it "should have #group_and_count work regularly if not given a string as the first argument" do
@@ -120,7 +120,7 @@ describe "query_literals extension" do
120
120
  end
121
121
 
122
122
  it "should have #order work the standard way if initial string is a literal string already" do
123
- @ds.order('a, b, ?'.lit, 1).sql.should == 'SELECT * FROM t ORDER BY a, b, ?, 1'
123
+ @ds.order(Sequel.lit('a, b, ?'), 1).sql.should == 'SELECT * FROM t ORDER BY a, b, ?, 1'
124
124
  end
125
125
 
126
126
  it "should have #order work regularly if not given a string as the first argument" do
@@ -141,7 +141,7 @@ describe "query_literals extension" do
141
141
  end
142
142
 
143
143
  it "should have #order_more work the standard way if initial string is a literal string already" do
144
- @ds.order_more('a, b, ?'.lit, 1).sql.should == 'SELECT * FROM t ORDER BY d, a, b, ?, 1'
144
+ @ds.order_more(Sequel.lit('a, b, ?'), 1).sql.should == 'SELECT * FROM t ORDER BY d, a, b, ?, 1'
145
145
  end
146
146
 
147
147
  it "should have #order_more work regularly if not given a string as the first argument" do
@@ -157,7 +157,7 @@ describe "query_literals extension" do
157
157
  end
158
158
 
159
159
  it "should have #order_append work the standard way if initial string is a literal string already" do
160
- @ds.order_prepend('a, b, ?'.lit, 1).sql.should == 'SELECT * FROM t ORDER BY a, b, ?, 1, d'
160
+ @ds.order_prepend(Sequel.lit('a, b, ?'), 1).sql.should == 'SELECT * FROM t ORDER BY a, b, ?, 1, d'
161
161
  end
162
162
 
163
163
  it "should have #order_append work regularly if not given a string as the first argument" do
@@ -41,13 +41,13 @@ describe "Dataset#query" do
41
41
  specify "should support #where" do
42
42
  q = @d.query do
43
43
  from :zzz
44
- where(:x + 2 > :y + 3)
44
+ where{x + 2 > Sequel.expr(:y) + 3}
45
45
  end
46
46
  q.class.should == @d.class
47
47
  q.sql.should == "SELECT * FROM zzz WHERE ((x + 2) > (y + 3))"
48
48
 
49
49
  q = @d.from(:zzz).query do
50
- where((:x.sql_number > 1) & (:y.sql_number > 2))
50
+ where{(x > 1) & (Sequel.expr(:y) > 2)}
51
51
  end
52
52
  q.class.should == @d.class
53
53
  q.sql.should == "SELECT * FROM zzz WHERE ((x > 1) AND (y > 2))"
@@ -63,7 +63,7 @@ describe "Dataset#query" do
63
63
  q = @d.query do
64
64
  from :abc
65
65
  group_by :id
66
- having(:x.sql_number >= 2)
66
+ having{x >= 2}
67
67
  end
68
68
  q.class.should == @d.class
69
69
  q.sql.should == "SELECT * FROM abc GROUP BY id HAVING (x >= 2)"
@@ -67,7 +67,7 @@ describe "Sequel::Database dump methods" do
67
67
  @d.meta_def(:tables){|o| [:t1, :t2]}
68
68
  @d.meta_def(:schema) do |t, *o|
69
69
  case t
70
- when :t1, 't__t1', :t__t1.identifier
70
+ when :t1, 't__t1', Sequel.identifier(:t__t1)
71
71
  [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>false}],
72
72
  [:c2, {:db_type=>'varchar(20)', :allow_null=>true}]]
73
73
  when :t2
@@ -88,7 +88,7 @@ describe "Sequel::Database dump methods" do
88
88
  end
89
89
 
90
90
  it "should support dumping table schemas when given an identifier" do
91
- @d.dump_table_schema(:t__t1.identifier).should == "create_table(\"t__t1\") do\n primary_key :c1\n String :c2, :size=>20\nend"
91
+ @d.dump_table_schema(Sequel.identifier(:t__t1)).should == "create_table(\"t__t1\") do\n primary_key :c1\n String :c2, :size=>20\nend"
92
92
  end
93
93
 
94
94
  it "should dump non-Integer primary key columns with explicit :type" do
@@ -593,10 +593,10 @@ END_MIG
593
593
  s
594
594
  end
595
595
  @d.dump_table_schema(:t4).gsub(/[+-]\d\d:\d\d"\)/, '")').should == "create_table(:t4) do\n TrueClass :c1, :default=>false\n String :c2, :default=>\"blah\"\n Integer :c3, :default=>-1\n Float :c4, :default=>1.0\n BigDecimal :c5, :default=>BigDecimal.new(\"0.1005E3\")\n File :c6, :default=>Sequel::SQL::Blob.new(\"blah\")\n Date :c7, :default=>Date.parse(\"2008-10-29\")\n DateTime :c8, :default=>DateTime.parse(\"2008-10-29T10:20:30\")\n Time :c9, :default=>Sequel::SQLTime.parse(\"10:20:30\"), :only_time=>true\n String :c10\nend"
596
- @d.dump_table_schema(:t4, :same_db=>true).gsub(/[+-]\d\d:\d\d"\)/, '")').should == "create_table(:t4) do\n column :c1, \"boolean\", :default=>false\n column :c2, \"varchar\", :default=>\"blah\"\n column :c3, \"integer\", :default=>-1\n column :c4, \"float\", :default=>1.0\n column :c5, \"decimal\", :default=>BigDecimal.new(\"0.1005E3\")\n column :c6, \"blob\", :default=>Sequel::SQL::Blob.new(\"blah\")\n column :c7, \"date\", :default=>Date.parse(\"2008-10-29\")\n column :c8, \"datetime\", :default=>DateTime.parse(\"2008-10-29T10:20:30\")\n column :c9, \"time\", :default=>Sequel::SQLTime.parse(\"10:20:30\")\n column :c10, \"interval\", :default=>\"'6 weeks'\".lit\nend"
596
+ @d.dump_table_schema(:t4, :same_db=>true).gsub(/[+-]\d\d:\d\d"\)/, '")').should == "create_table(:t4) do\n column :c1, \"boolean\", :default=>false\n column :c2, \"varchar\", :default=>\"blah\"\n column :c3, \"integer\", :default=>-1\n column :c4, \"float\", :default=>1.0\n column :c5, \"decimal\", :default=>BigDecimal.new(\"0.1005E3\")\n column :c6, \"blob\", :default=>Sequel::SQL::Blob.new(\"blah\")\n column :c7, \"date\", :default=>Date.parse(\"2008-10-29\")\n column :c8, \"datetime\", :default=>DateTime.parse(\"2008-10-29T10:20:30\")\n column :c9, \"time\", :default=>Sequel::SQLTime.parse(\"10:20:30\")\n column :c10, \"interval\", :default=>Sequel::LiteralString.new(\"'6 weeks'\")\nend"
597
597
  end
598
598
 
599
- it "should not use a '...'.lit as a fallback if using MySQL with the :same_db option" do
599
+ it "should not use a literal string as a fallback if using MySQL with the :same_db option" do
600
600
  @d.meta_def(:database_type){:mysql}
601
601
  @d.meta_def(:schema) do |t, *os|
602
602
  s = [[:c10, {:db_type=>'interval', :default=>"'6 weeks'", :type=>:interval, :allow_null=>true}]]
@@ -712,6 +712,22 @@ end
712
712
  END_MIG
713
713
  end
714
714
 
715
+ it "should convert mysql types to ruby types" do
716
+ types = ['double(15,2)', 'double(7,1) unsigned']
717
+ @d.meta_def(:schema) do |t, *o|
718
+ i = 0
719
+ types.map{|x| [:"c#{i+=1}", {:db_type=>x, :allow_null=>true}]}
720
+ end
721
+ @d.dump_table_schema(:x).should == (<<END_MIG).chomp
722
+ create_table(:x) do
723
+ Float :c1
724
+ Float :c2
725
+
726
+ check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:c2), 0)
727
+ end
728
+ END_MIG
729
+ end
730
+
715
731
  it "should use separate primary_key call with non autoincrementable types" do
716
732
  @d.meta_def(:schema){|*s| [[:c1, {:db_type=>'varchar(8)', :primary_key=>true}]]}
717
733
  @d.dump_table_schema(:t3).should == "create_table(:t3) do\n String :c1, :size=>8\n \n primary_key [:c1]\nend"
@@ -3,6 +3,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
3
3
  describe Sequel::Model, "dataset & schema" do
4
4
  before do
5
5
  @model = Class.new(Sequel::Model(:items))
6
+ @model.plugin :schema
6
7
  end
7
8
 
8
9
  specify "sets schema with implicit table name" do
@@ -22,27 +23,17 @@ describe Sequel::Model, "dataset & schema" do
22
23
  end
23
24
  end
24
25
 
25
- describe Sequel::Model, "table_exists?" do
26
- before do
27
- MODEL_DB.reset
28
- @model = Class.new(Sequel::Model(:items))
29
- end
30
-
31
- it "should get the table name and question the model's db if table_exists?" do
32
- @model.db.should_receive(:table_exists?).and_return(false)
33
- @model.table_exists?.should == false
34
- end
35
- end
36
-
37
26
  describe Sequel::Model, "create_table and schema" do
38
27
  before do
39
- MODEL_DB.reset
40
- @model = Class.new(Sequel::Model) do
28
+ @model = Class.new(Sequel::Model)
29
+ @model.class_eval do
30
+ plugin :schema
41
31
  set_schema(:items) do
42
32
  text :name
43
33
  float :price, :null => false
44
34
  end
45
35
  end
36
+ MODEL_DB.reset
46
37
  end
47
38
 
48
39
  it "should get the create table SQL list from the db and execute it line by line" do
@@ -74,61 +65,47 @@ describe Sequel::Model, "create_table and schema" do
74
65
 
75
66
  it "should return nil if no schema is present" do
76
67
  @model = Class.new(Sequel::Model)
68
+ @model.plugin :schema
77
69
  @model.schema.should == nil
78
70
  @submodel = Class.new(@model)
79
71
  @submodel.schema.should == nil
80
72
  end
81
73
  end
82
74
 
83
- describe Sequel::Model, "drop_table" do
75
+ describe Sequel::Model, "schema methods" do
84
76
  before do
85
77
  @model = Class.new(Sequel::Model(:items))
78
+ @model.plugin :schema
86
79
  MODEL_DB.reset
87
80
  end
88
81
 
89
- it "should drop the related table" do
90
- @model.drop_table
91
- MODEL_DB.sqls.should == ['DROP TABLE items']
82
+ it "table_exists? should get the table name and question the model's db if table_exists?" do
83
+ @model.db.should_receive(:table_exists?).and_return(false)
84
+ @model.table_exists?.should == false
92
85
  end
93
- end
94
86
 
95
- describe Sequel::Model, "drop_table?" do
96
- before do
97
- @model = Class.new(Sequel::Model(:items))
98
- MODEL_DB.reset
87
+ it "drop_table should drop the related table" do
88
+ @model.drop_table
89
+ MODEL_DB.sqls.should == ['DROP TABLE items']
99
90
  end
100
91
 
101
- it "should drop the table if it exists" do
92
+ it "drop_table? should drop the table if it exists" do
102
93
  @model.drop_table?
103
94
  MODEL_DB.sqls.should == ["SELECT NULL FROM items LIMIT 1", 'DROP TABLE items']
104
95
  end
105
- end
106
-
107
- describe Sequel::Model, "create_table!" do
108
- before do
109
- MODEL_DB.reset
110
- @model = Class.new(Sequel::Model(:items))
111
- end
112
96
 
113
- it "should drop table if it exists and then create the table" do
97
+ it "create_table! should drop table if it exists and then create the table" do
114
98
  @model.create_table!
115
99
  MODEL_DB.sqls.should == ["SELECT NULL FROM items LIMIT 1", 'DROP TABLE items', 'CREATE TABLE items ()']
116
100
  end
117
- end
118
-
119
- describe Sequel::Model, "create_table?" do
120
- before do
121
- MODEL_DB.reset
122
- @model = Class.new(Sequel::Model(:items))
123
- end
124
101
 
125
- it "should not create the table if it already exists" do
102
+ it "create_table? should not create the table if it already exists" do
126
103
  @model.should_receive(:table_exists?).and_return(true)
127
104
  @model.create_table?
128
105
  MODEL_DB.sqls.should == []
129
106
  end
130
107
 
131
- it "should create the table if it doesn't exist" do
108
+ it "create_table? should create the table if it doesn't exist" do
132
109
  @model.should_receive(:table_exists?).and_return(false)
133
110
  @model.create_table?
134
111
  MODEL_DB.sqls.should == ['CREATE TABLE items ()']
@@ -24,15 +24,15 @@ describe "Dataset#select_remove" do
24
24
  end
25
25
 
26
26
  specify "should handle expressions where Sequel can't determine the alias by itself" do
27
- d = @d.select(:a, :b.sql_function, :c.as(:b))
27
+ d = @d.select(:a, Sequel.function(:b), Sequel.as(:c, :b))
28
28
  d.columns :a, :"b()", :b
29
29
  d.select_remove(:"b()").sql.should == 'SELECT a, c AS b FROM test'
30
30
  end
31
31
 
32
32
  specify "should remove expressions if given exact expressions" do
33
- d = @d.select(:a, :b.sql_function, :c.as(:b))
33
+ d = @d.select(:a, Sequel.function(:b), Sequel.as(:c, :b))
34
34
  d.columns :a, :"b()", :b
35
- d.select_remove(:b.sql_function).sql.should == 'SELECT a, c AS b FROM test'
36
- d.select_remove(:c.as(:b)).sql.should == 'SELECT a, b() FROM test'
35
+ d.select_remove(Sequel.function(:b)).sql.should == 'SELECT a, c AS b FROM test'
36
+ d.select_remove(Sequel.as(:c, :b)).sql.should == 'SELECT a, b() FROM test'
37
37
  end
38
38
  end
@@ -8,13 +8,9 @@ if defined?(RSpec)
8
8
  end
9
9
  end
10
10
 
11
- unless Object.const_defined?('Sequel')
11
+ unless Object.const_defined?('Sequel') && Sequel.const_defined?('Model')
12
12
  $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
13
- require 'sequel/core'
14
- end
15
- unless Sequel.const_defined?('Model')
16
- $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
17
- require 'sequel/model'
13
+ require 'sequel/no_core_ext'
18
14
  end
19
15
 
20
16
  begin
@@ -26,8 +22,8 @@ rescue LoadError
26
22
  nil
27
23
  end
28
24
 
29
- Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones to_dot columns_introspection server_block arbitrary_servers pg_auto_parameterize pg_statement_cache pg_array pg_array_ops pg_hstore pg_hstore_ops pg_range pg_range_ops pg_json pg_inet schema_caching null_dataset select_remove query_literals eval_inspect')
30
- {:hook_class_methods=>[], :schema=>[], :validation_class_methods=>[]}.each{|p, opts| Sequel::Model.plugin(p, *opts)}
25
+ # Load most extensions by default, so that any conflicts are easily detectable.
26
+ Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones to_dot columns_introspection server_block arbitrary_servers pg_auto_parameterize pg_statement_cache pg_array pg_array_ops pg_hstore pg_hstore_ops pg_range pg_range_ops pg_json pg_inet pg_row pg_row_ops schema_caching null_dataset select_remove query_literals eval_inspect')
31
27
 
32
28
  Sequel::Dataset.introspect_all_columns if ENV['SEQUEL_COLUMNS_INTROSPECTION']
33
29
 
@@ -100,19 +100,19 @@ END
100
100
  end
101
101
 
102
102
  it "should handle SQL::OrderedExpressions" do
103
- dot(@ds.order(:a.desc(:nulls=>:last))).should == ["1 -> 2 [label=\"order\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"OrderedExpression: DESC NULLS LAST\"];", "3 -> 4 [label=\"expression\"];", "4 [label=\":a\"];"]
103
+ dot(@ds.order(Sequel.desc(:a, :nulls=>:last))).should == ["1 -> 2 [label=\"order\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"OrderedExpression: DESC NULLS LAST\"];", "3 -> 4 [label=\"expression\"];", "4 [label=\":a\"];"]
104
104
  end
105
105
 
106
106
  it "should handle SQL::AliasedExpressions" do
107
- dot(@ds.from(:a.as(:b))).should == ["1 -> 2 [label=\"from\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"AliasedExpression\"];", "3 -> 4 [label=\"expression\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"alias\"];", "5 [label=\":b\"];"]
107
+ dot(@ds.from(Sequel.as(:a, :b))).should == ["1 -> 2 [label=\"from\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"AliasedExpression\"];", "3 -> 4 [label=\"expression\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"alias\"];", "5 [label=\":b\"];"]
108
108
  end
109
109
 
110
110
  it "should handle SQL::CaseExpressions" do
111
- dot(@ds.select({:a=>:b}.case(:c, :d))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"CaseExpression\"];", "3 -> 4 [label=\"expression\"];", "4 [label=\":d\"];", "3 -> 5 [label=\"conditions\"];", "5 [label=\"Array\"];", "5 -> 6 [label=\"0\"];", "6 [label=\"Array\"];", "6 -> 7 [label=\"0\"];", "7 [label=\":a\"];", "6 -> 8 [label=\"1\"];", "8 [label=\":b\"];", "3 -> 9 [label=\"default\"];", "9 [label=\":c\"];"]
111
+ dot(@ds.select(Sequel.case({:a=>:b}, :c, :d))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"CaseExpression\"];", "3 -> 4 [label=\"expression\"];", "4 [label=\":d\"];", "3 -> 5 [label=\"conditions\"];", "5 [label=\"Array\"];", "5 -> 6 [label=\"0\"];", "6 [label=\"Array\"];", "6 -> 7 [label=\"0\"];", "7 [label=\":a\"];", "6 -> 8 [label=\"1\"];", "8 [label=\":b\"];", "3 -> 9 [label=\"default\"];", "9 [label=\":c\"];"]
112
112
  end
113
113
 
114
114
  it "should handle SQL::Cast" do
115
- dot(@ds.select(:a.cast(Integer))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"Cast\"];", "3 -> 4 [label=\"expr\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"type\"];", "5 [label=\"Integer\"];"]
115
+ dot(@ds.select(Sequel.cast(:a, Integer))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"Cast\"];", "3 -> 4 [label=\"expr\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"type\"];", "5 [label=\"Integer\"];"]
116
116
  end
117
117
 
118
118
  it "should handle SQL::Function" do
@@ -120,7 +120,7 @@ END
120
120
  end
121
121
 
122
122
  it "should handle SQL::Subscript" do
123
- dot(@ds.select(:a.sql_subscript(1))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"Subscript\"];", "3 -> 4 [label=\"f\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"sub\"];", "5 [label=\"Array\"];", "5 -> 6 [label=\"0\"];", "6 [label=\"1\"];"]
123
+ dot(@ds.select(Sequel.subscript(:a, 1))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"Subscript\"];", "3 -> 4 [label=\"f\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"sub\"];", "5 [label=\"Array\"];", "5 -> 6 [label=\"0\"];", "6 [label=\"1\"];"]
124
124
  end
125
125
 
126
126
  it "should handle SQL::WindowFunction" do
@@ -1,8 +1,15 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
+ model_class = proc do |klass, &block|
4
+ c = Class.new(klass)
5
+ c.plugin :validation_class_methods
6
+ c.class_eval(&block) if block
7
+ c
8
+ end
9
+
3
10
  describe Sequel::Model do
4
11
  before do
5
- @c = Class.new(Sequel::Model) do
12
+ @c = model_class.call Sequel::Model do
6
13
  def self.validates_coolness_of(attr)
7
14
  validates_each(attr) {|o, a, v| o.errors[a] << 'is not cool' if v != :cool}
8
15
  end
@@ -135,8 +142,7 @@ end
135
142
 
136
143
  describe Sequel::Model do
137
144
  before do
138
- @c = Class.new(Sequel::Model)
139
- @c.class_eval do
145
+ @c = model_class.call Sequel::Model do
140
146
  columns :score
141
147
  validates_each :score do |o, a, v|
142
148
  o.errors[a] << 'too low' if v < 87
@@ -165,11 +171,11 @@ describe Sequel::Model do
165
171
  end
166
172
  end
167
173
 
168
- describe Sequel::Plugins::ValidationClassMethods::ClassMethods::Generator do
174
+ describe "Sequel::Plugins::ValidationClassMethods::ClassMethods::Generator" do
169
175
  before do
170
176
  $testit = nil
171
177
 
172
- @c = Class.new(Sequel::Model) do
178
+ @c = model_class.call Sequel::Model do
173
179
  def self.validates_blah
174
180
  $testit = 1324
175
181
  end
@@ -186,7 +192,7 @@ end
186
192
 
187
193
  describe Sequel::Model do
188
194
  before do
189
- @c = Class.new(Sequel::Model) do
195
+ @c = model_class.call Sequel::Model do
190
196
  columns :value
191
197
 
192
198
  def self.filter(*args)
@@ -579,8 +585,7 @@ end
579
585
 
580
586
  describe "Superclass validations" do
581
587
  before do
582
- @c1 = Class.new(Sequel::Model)
583
- @c1.class_eval do
588
+ @c1 = model_class.call Sequel::Model do
584
589
  columns :value
585
590
  validates_length_of :value, :minimum => 5
586
591
  end
@@ -624,8 +629,7 @@ end
624
629
 
625
630
  describe ".validates with block" do
626
631
  specify "should support calling .each" do
627
- @c = Class.new(Sequel::Model)
628
- @c.class_eval do
632
+ @c = model_class.call Sequel::Model do
629
633
  columns :vvv
630
634
  validates do
631
635
  each :vvv do |o, a, v|
@@ -646,24 +650,36 @@ describe Sequel::Model, "Validations" do
646
650
 
647
651
  before(:all) do
648
652
  class ::Person < Sequel::Model
653
+ plugin :validation_class_methods
649
654
  columns :id,:name,:first_name,:last_name,:middle_name,:initials,:age, :terms
650
655
  end
651
656
 
652
657
  class ::Smurf < Person
653
658
  end
659
+
660
+ class ::Can < Sequel::Model
661
+ plugin :validation_class_methods
662
+ columns :id, :name
663
+ end
654
664
 
655
665
  class ::Cow < Sequel::Model
666
+ plugin :validation_class_methods
656
667
  columns :id, :name, :got_milk
657
668
  end
658
669
 
659
670
  class ::User < Sequel::Model
671
+ plugin :validation_class_methods
660
672
  columns :id, :username, :password
661
673
  end
662
674
 
663
675
  class ::Address < Sequel::Model
676
+ plugin :validation_class_methods
664
677
  columns :id, :zip_code
665
678
  end
666
679
  end
680
+ after(:all) do
681
+ [:Person, :Smurf, :Cow, :User, :Address].each{|c| Object.send(:remove_const, c)}
682
+ end
667
683
 
668
684
  it "should validate the acceptance of a column" do
669
685
  class ::Cow < Sequel::Model
@@ -741,8 +757,7 @@ describe Sequel::Model, "Validations" do
741
757
  end
742
758
 
743
759
  it "should validate that a column doesn't have a string value" do
744
- p = Class.new(Sequel::Model)
745
- p.class_eval do
760
+ p = model_class.call Sequel::Model do
746
761
  columns :age, :price, :confirmed
747
762
  self.raise_on_typecast_failure = false
748
763
  validates_not_string :age
@@ -941,8 +956,6 @@ describe Sequel::Model, "Validations" do
941
956
 
942
957
  it "should validate correctly instances initialized with string keys" do
943
958
  class ::Can < Sequel::Model
944
- columns :id, :name
945
-
946
959
  validates_length_of :name, :minimum => 4
947
960
  end
948
961
 
@@ -954,8 +967,7 @@ end
954
967
 
955
968
  describe "Model#save" do
956
969
  before do
957
- @c = Class.new(Sequel::Model(:people))
958
- @c.class_eval do
970
+ @c = model_class.call Sequel::Model(:people) do
959
971
  columns :id, :x
960
972
 
961
973
  validates_each :x do |o, a, v|