sequel 3.37.0 → 3.38.0

Sign up to get free protection for your applications and to get access to all the features.
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|