sequel 3.46.0 → 3.47.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 (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +96 -0
  3. data/Rakefile +7 -1
  4. data/bin/sequel +6 -4
  5. data/doc/active_record.rdoc +1 -1
  6. data/doc/advanced_associations.rdoc +14 -35
  7. data/doc/association_basics.rdoc +66 -4
  8. data/doc/migration.rdoc +4 -0
  9. data/doc/opening_databases.rdoc +6 -0
  10. data/doc/postgresql.rdoc +302 -0
  11. data/doc/release_notes/3.47.0.txt +270 -0
  12. data/doc/security.rdoc +6 -0
  13. data/lib/sequel/adapters/ibmdb.rb +9 -9
  14. data/lib/sequel/adapters/jdbc.rb +22 -7
  15. data/lib/sequel/adapters/jdbc/postgresql.rb +7 -2
  16. data/lib/sequel/adapters/mock.rb +2 -0
  17. data/lib/sequel/adapters/postgres.rb +44 -13
  18. data/lib/sequel/adapters/shared/mssql.rb +1 -1
  19. data/lib/sequel/adapters/shared/mysql.rb +2 -2
  20. data/lib/sequel/adapters/shared/postgres.rb +94 -55
  21. data/lib/sequel/adapters/shared/sqlite.rb +3 -1
  22. data/lib/sequel/adapters/sqlite.rb +2 -2
  23. data/lib/sequel/adapters/utils/pg_types.rb +1 -14
  24. data/lib/sequel/adapters/utils/split_alter_table.rb +3 -3
  25. data/lib/sequel/connection_pool/threaded.rb +1 -1
  26. data/lib/sequel/core.rb +1 -1
  27. data/lib/sequel/database/connecting.rb +2 -2
  28. data/lib/sequel/database/features.rb +5 -0
  29. data/lib/sequel/database/misc.rb +47 -5
  30. data/lib/sequel/database/query.rb +2 -2
  31. data/lib/sequel/dataset/actions.rb +4 -2
  32. data/lib/sequel/dataset/misc.rb +1 -1
  33. data/lib/sequel/dataset/prepared_statements.rb +1 -1
  34. data/lib/sequel/dataset/query.rb +8 -6
  35. data/lib/sequel/dataset/sql.rb +8 -6
  36. data/lib/sequel/extensions/constraint_validations.rb +5 -2
  37. data/lib/sequel/extensions/migration.rb +10 -8
  38. data/lib/sequel/extensions/pagination.rb +3 -0
  39. data/lib/sequel/extensions/pg_array.rb +85 -25
  40. data/lib/sequel/extensions/pg_hstore.rb +8 -1
  41. data/lib/sequel/extensions/pg_hstore_ops.rb +4 -1
  42. data/lib/sequel/extensions/pg_inet.rb +16 -13
  43. data/lib/sequel/extensions/pg_interval.rb +6 -2
  44. data/lib/sequel/extensions/pg_json.rb +18 -11
  45. data/lib/sequel/extensions/pg_range.rb +17 -2
  46. data/lib/sequel/extensions/pg_range_ops.rb +7 -5
  47. data/lib/sequel/extensions/pg_row.rb +29 -12
  48. data/lib/sequel/extensions/pretty_table.rb +3 -0
  49. data/lib/sequel/extensions/query.rb +3 -0
  50. data/lib/sequel/extensions/schema_caching.rb +2 -0
  51. data/lib/sequel/extensions/schema_dumper.rb +3 -1
  52. data/lib/sequel/extensions/select_remove.rb +3 -0
  53. data/lib/sequel/model.rb +8 -2
  54. data/lib/sequel/model/associations.rb +39 -27
  55. data/lib/sequel/model/base.rb +99 -38
  56. data/lib/sequel/model/plugins.rb +25 -0
  57. data/lib/sequel/plugins/association_autoreloading.rb +27 -22
  58. data/lib/sequel/plugins/association_dependencies.rb +1 -7
  59. data/lib/sequel/plugins/auto_validations.rb +110 -0
  60. data/lib/sequel/plugins/boolean_readers.rb +1 -6
  61. data/lib/sequel/plugins/caching.rb +6 -13
  62. data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
  63. data/lib/sequel/plugins/composition.rb +14 -7
  64. data/lib/sequel/plugins/constraint_validations.rb +2 -13
  65. data/lib/sequel/plugins/defaults_setter.rb +1 -6
  66. data/lib/sequel/plugins/dirty.rb +8 -0
  67. data/lib/sequel/plugins/error_splitter.rb +54 -0
  68. data/lib/sequel/plugins/force_encoding.rb +1 -5
  69. data/lib/sequel/plugins/hook_class_methods.rb +1 -6
  70. data/lib/sequel/plugins/input_transformer.rb +79 -0
  71. data/lib/sequel/plugins/instance_filters.rb +7 -1
  72. data/lib/sequel/plugins/instance_hooks.rb +7 -1
  73. data/lib/sequel/plugins/json_serializer.rb +5 -10
  74. data/lib/sequel/plugins/lazy_attributes.rb +20 -7
  75. data/lib/sequel/plugins/list.rb +1 -6
  76. data/lib/sequel/plugins/many_through_many.rb +1 -2
  77. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +23 -39
  78. data/lib/sequel/plugins/optimistic_locking.rb +1 -5
  79. data/lib/sequel/plugins/pg_row.rb +4 -2
  80. data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -7
  81. data/lib/sequel/plugins/prepared_statements.rb +1 -5
  82. data/lib/sequel/plugins/prepared_statements_safe.rb +2 -11
  83. data/lib/sequel/plugins/rcte_tree.rb +2 -2
  84. data/lib/sequel/plugins/serialization.rb +11 -13
  85. data/lib/sequel/plugins/serialization_modification_detection.rb +13 -1
  86. data/lib/sequel/plugins/single_table_inheritance.rb +4 -4
  87. data/lib/sequel/plugins/static_cache.rb +67 -19
  88. data/lib/sequel/plugins/string_stripper.rb +7 -27
  89. data/lib/sequel/plugins/subclasses.rb +3 -5
  90. data/lib/sequel/plugins/tactical_eager_loading.rb +2 -2
  91. data/lib/sequel/plugins/timestamps.rb +2 -7
  92. data/lib/sequel/plugins/touch.rb +5 -8
  93. data/lib/sequel/plugins/tree.rb +1 -6
  94. data/lib/sequel/plugins/typecast_on_load.rb +1 -5
  95. data/lib/sequel/plugins/update_primary_key.rb +26 -14
  96. data/lib/sequel/plugins/validation_class_methods.rb +31 -16
  97. data/lib/sequel/plugins/validation_helpers.rb +50 -26
  98. data/lib/sequel/plugins/xml_serializer.rb +3 -6
  99. data/lib/sequel/sql.rb +1 -1
  100. data/lib/sequel/version.rb +1 -1
  101. data/spec/adapters/postgres_spec.rb +131 -15
  102. data/spec/adapters/sqlite_spec.rb +1 -1
  103. data/spec/core/connection_pool_spec.rb +16 -17
  104. data/spec/core/database_spec.rb +111 -40
  105. data/spec/core/dataset_spec.rb +65 -74
  106. data/spec/core/expression_filters_spec.rb +6 -5
  107. data/spec/core/object_graph_spec.rb +0 -1
  108. data/spec/core/schema_spec.rb +23 -23
  109. data/spec/core/spec_helper.rb +5 -1
  110. data/spec/extensions/association_dependencies_spec.rb +1 -1
  111. data/spec/extensions/association_proxies_spec.rb +1 -1
  112. data/spec/extensions/auto_validations_spec.rb +90 -0
  113. data/spec/extensions/caching_spec.rb +6 -0
  114. data/spec/extensions/class_table_inheritance_spec.rb +8 -1
  115. data/spec/extensions/composition_spec.rb +12 -5
  116. data/spec/extensions/constraint_validations_spec.rb +4 -4
  117. data/spec/extensions/core_refinements_spec.rb +29 -79
  118. data/spec/extensions/dirty_spec.rb +14 -0
  119. data/spec/extensions/error_splitter_spec.rb +18 -0
  120. data/spec/extensions/identity_map_spec.rb +0 -1
  121. data/spec/extensions/input_transformer_spec.rb +54 -0
  122. data/spec/extensions/instance_filters_spec.rb +6 -0
  123. data/spec/extensions/instance_hooks_spec.rb +12 -1
  124. data/spec/extensions/json_serializer_spec.rb +0 -1
  125. data/spec/extensions/lazy_attributes_spec.rb +64 -55
  126. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  127. data/spec/extensions/many_through_many_spec.rb +3 -4
  128. data/spec/extensions/many_to_one_pk_lookup_spec.rb +53 -15
  129. data/spec/extensions/migration_spec.rb +16 -0
  130. data/spec/extensions/null_dataset_spec.rb +1 -1
  131. data/spec/extensions/pg_array_spec.rb +48 -1
  132. data/spec/extensions/pg_hstore_ops_spec.rb +10 -2
  133. data/spec/extensions/pg_hstore_spec.rb +5 -0
  134. data/spec/extensions/pg_inet_spec.rb +5 -0
  135. data/spec/extensions/pg_interval_spec.rb +7 -3
  136. data/spec/extensions/pg_json_spec.rb +6 -1
  137. data/spec/extensions/pg_range_ops_spec.rb +4 -1
  138. data/spec/extensions/pg_range_spec.rb +5 -0
  139. data/spec/extensions/pg_row_plugin_spec.rb +13 -0
  140. data/spec/extensions/pg_row_spec.rb +28 -19
  141. data/spec/extensions/pg_typecast_on_load_spec.rb +6 -1
  142. data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
  143. data/spec/extensions/query_literals_spec.rb +1 -1
  144. data/spec/extensions/rcte_tree_spec.rb +2 -2
  145. data/spec/extensions/schema_spec.rb +2 -2
  146. data/spec/extensions/serialization_modification_detection_spec.rb +8 -0
  147. data/spec/extensions/serialization_spec.rb +15 -1
  148. data/spec/extensions/sharding_spec.rb +1 -1
  149. data/spec/extensions/single_table_inheritance_spec.rb +1 -1
  150. data/spec/extensions/static_cache_spec.rb +59 -9
  151. data/spec/extensions/tactical_eager_loading_spec.rb +19 -4
  152. data/spec/extensions/update_primary_key_spec.rb +17 -1
  153. data/spec/extensions/validation_class_methods_spec.rb +25 -0
  154. data/spec/extensions/validation_helpers_spec.rb +59 -3
  155. data/spec/integration/associations_test.rb +5 -5
  156. data/spec/integration/eager_loader_test.rb +32 -63
  157. data/spec/integration/model_test.rb +2 -2
  158. data/spec/integration/plugin_test.rb +88 -56
  159. data/spec/integration/prepared_statement_test.rb +1 -1
  160. data/spec/integration/schema_test.rb +1 -1
  161. data/spec/integration/timezone_test.rb +0 -1
  162. data/spec/integration/transaction_test.rb +0 -1
  163. data/spec/model/association_reflection_spec.rb +1 -1
  164. data/spec/model/associations_spec.rb +106 -84
  165. data/spec/model/base_spec.rb +4 -4
  166. data/spec/model/eager_loading_spec.rb +8 -8
  167. data/spec/model/model_spec.rb +27 -9
  168. data/spec/model/plugins_spec.rb +71 -0
  169. data/spec/model/record_spec.rb +99 -13
  170. metadata +12 -2
@@ -18,12 +18,17 @@ describe Sequel::Model, "PgTypecastOnLoad plugin" do
18
18
  @c.first.refresh.values.should == {:id=>1, :b=>true, :y=>0}
19
19
  end
20
20
 
21
+ specify "should not fail if schema oid does not have a related conversion proc" do
22
+ @c.db_schema[:b][:oid] = 0
23
+ @c.first.refresh.values.should == {:id=>1, :b=>"t", :y=>0}
24
+ end
25
+
21
26
  specify "should call the database conversion proc with value when automatically reloading the object on creation via insert_select" do
22
27
  @c.dataset.meta_def(:insert_select){|h| insert(h); first}
23
28
  @c.create.values.should == {:id=>1, :b=>true, :y=>0}
24
29
  end
25
30
 
26
- specify "should allowing setting columns separately via add_typecast_on_load_columns" do
31
+ specify "should allowing setting columns separately via add_pg_typecast_on_load_columns" do
27
32
  @c = Class.new(Sequel::Model(@db[:items]))
28
33
  @c.plugin :pg_typecast_on_load
29
34
  @c.first.values.should == {:id=>1, :b=>"t", :y=>"0"}
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
- describe "Sequel::Plugins::AssociationPks" do
3
+ describe "Sequel::Plugins::PreparedStatementsAssociations" do
4
4
  before do
5
5
  @db = Sequel.mock
6
6
  @db.extend_datasets do
@@ -34,7 +34,7 @@ describe "query_literals extension" do
34
34
  @ds.select_more('a, b, c').sql.should == 'SELECT d, a, b, c FROM t'
35
35
  end
36
36
 
37
- it "should have #select_ use placeholder literal string if given a string and additional arguments" do
37
+ it "should have #select_more use placeholder literal string if given a string and additional arguments" do
38
38
  @ds.select_more('a, b, ?', 1).sql.should == 'SELECT d, a, b, 1 FROM t'
39
39
  end
40
40
 
@@ -144,7 +144,7 @@ describe Sequel::Model, "rcte_tree" do
144
144
  [{:id=>2, :name=>'AA', :parent_id=>1, :x_root_x=>2},
145
145
  {:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>1}, {:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>2},
146
146
  {:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>2}, {:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>1}]]
147
- os = @ds.eager(:ancestors).all
147
+ @ds.eager(:ancestors).all
148
148
  sqls = MODEL_DB.sqls
149
149
  sqls.first.should == "SELECT * FROM nodes"
150
150
  sqls.last.should =~ /WITH t AS \(SELECT id AS x_root_x, nodes\.\* FROM nodes WHERE \(\(id IN \([12], [12]\)\) AND \(i = 1\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.parent_id = nodes\.id\) WHERE \(i = 1\)\) SELECT \* FROM t AS nodes WHERE \(i = 1\)/
@@ -236,7 +236,7 @@ describe Sequel::Model, "rcte_tree" do
236
236
  [{:id=>6, :parent_id=>2, :name=>'C', :x_root_x=>2}, {:id=>9, :parent_id=>2, :name=>'E', :x_root_x=>2},
237
237
  {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>6}, {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>2},
238
238
  {:id=>4, :name=>'?', :parent_id=>7, :x_root_x=>7}, {:id=>5, :name=>'?', :parent_id=>4, :x_root_x=>7}]]
239
- os = @ds.eager(:descendants).all
239
+ @ds.eager(:descendants).all
240
240
  sqls = MODEL_DB.sqls
241
241
  sqls.first.should == "SELECT * FROM nodes"
242
242
  sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x, nodes\.\* FROM nodes WHERE \(\(parent_id IN \([267], [267], [267]\)\) AND \(i = 1\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.id = nodes\.parent_id\) WHERE \(i = 1\)\) SELECT \* FROM t AS nodes WHERE \(i = 1\)/
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
- describe Sequel::Model, "dataset & schema" do
3
+ describe Sequel::Model, "set_schema" do
4
4
  before do
5
5
  @model = Class.new(Sequel::Model(:items))
6
6
  @model.plugin :schema
@@ -8,7 +8,7 @@ describe Sequel::Model, "dataset & schema" do
8
8
 
9
9
  specify "sets schema with implicit table name" do
10
10
  @model.set_schema do
11
- primary_key :ssn, :string
11
+ primary_key :ssn, :type=>:string
12
12
  end
13
13
  @model.primary_key.should == :ssn
14
14
  @model.table_name.should == :items
@@ -69,4 +69,12 @@ describe "serialization_modification_detection plugin" do
69
69
  @o4.save
70
70
  @o4.changed_columns.should == []
71
71
  end
72
+
73
+ it "should work with frozen objects" do
74
+ @o1.changed_columns.should == []
75
+ @o1.h.should == {}
76
+ @o1.freeze
77
+ @o1.h[1] = 2
78
+ @o1.changed_columns.should == [:h]
79
+ end
72
80
  end
@@ -76,7 +76,6 @@ describe "Serialization plugin" do
76
76
  it "should translate values to and from yaml serialization format using accessor methods" do
77
77
  @c.set_primary_key :id
78
78
  @c.plugin :serialization, :yaml, :abc, :def
79
- vals = nil
80
79
  @c.dataset._fetch = {:id => 1, :abc => "--- 1\n", :def => "--- hello\n"}
81
80
 
82
81
  o = @c.first
@@ -290,4 +289,19 @@ describe "Serialization plugin" do
290
289
  o = @c.load(:abc => 3)
291
290
  o.abc.should == 9
292
291
  end
292
+
293
+ it "should work correctly with frozen instances" do
294
+ @c.set_primary_key :id
295
+ @c.plugin :serialization, :yaml, :abc, :def
296
+ @c.dataset._fetch = {:id => 1, :abc => "--- 1\n", :def => "--- hello\n"}
297
+
298
+ o = @c.first
299
+ o.freeze
300
+ o.abc.should == 1
301
+ o.abc.should == 1
302
+ o.def.should == "hello"
303
+ o.def.should == "hello"
304
+ proc{o.abc = 2}.should raise_error
305
+ proc{o.def = 'h'}.should raise_error
306
+ end
293
307
  end
@@ -161,7 +161,7 @@ describe "sharding plugin" do
161
161
  end
162
162
 
163
163
  specify "should not override a server already set on an associated object" do
164
- album = @Album.server(:s1).first
164
+ @Album.server(:s1).first
165
165
  artist = @Artist.server(:s2).first
166
166
  @db.sqls.should == ["SELECT * FROM albums LIMIT 1 -- s1", "SELECT * FROM artists LIMIT 1 -- s2"]
167
167
 
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
- describe Sequel::Model, "#sti_key" do
3
+ describe Sequel::Model, "single table inheritance plugin" do
4
4
  before do
5
5
  class ::StiTest < Sequel::Model
6
6
  columns :id, :kind, :blah
@@ -67,13 +67,27 @@ describe "Sequel::Plugins::StaticCache" do
67
67
  @db.sqls.should == []
68
68
  end
69
69
 
70
- it "should have map send a query if given an argument" do
70
+ it "should have count with no argument or block not issue a query" do
71
+ @c.count.should == 2
72
+ @db.sqls.should == []
73
+ end
74
+
75
+ it "should have count with argument or block not issue a query" do
76
+ @db.fetch = [[{:count=>1}], [{:count=>2}]]
77
+ @c.count(:a).should == 1
78
+ @c.count{b}.should == 2
79
+ @db.sqls.should == ["SELECT COUNT(a) AS count FROM t LIMIT 1", "SELECT COUNT(b) AS count FROM t LIMIT 1"]
80
+ end
81
+
82
+ it "should have map not send a query if given an argument" do
71
83
  @c.map(:id).sort.should == [1, 2]
72
- @db.sqls.should == ["SELECT * FROM t"]
84
+ @db.sqls.should == []
85
+ @c.map([:id,:id]).sort.should == [[1,1], [2,2]]
86
+ @db.sqls.should == []
73
87
  end
74
88
 
75
89
  it "should have map without a block or argument not raise an exception or issue a query" do
76
- @c.map
90
+ @c.map.to_a.should == @c.all
77
91
  @db.sqls.should == []
78
92
  end
79
93
 
@@ -81,6 +95,10 @@ describe "Sequel::Plugins::StaticCache" do
81
95
  @c.map.frozen?.should be_false
82
96
  end
83
97
 
98
+ it "should have map with a block and argument raise" do
99
+ proc{@c.map(:id){}}.should raise_error(Sequel::Error)
100
+ end
101
+
84
102
  it "should have other enumerable methods work without sending a query" do
85
103
  a = @c.sort_by{|o| o.id}
86
104
  a.first.should equal(@c1)
@@ -88,7 +106,7 @@ describe "Sequel::Plugins::StaticCache" do
88
106
  @db.sqls.should == []
89
107
  end
90
108
 
91
- it "should have all just return the hashes' values" do
109
+ it "should have all just return the cached values" do
92
110
  a = @c.all.sort_by{|o| o.id}
93
111
  a.first.should equal(@c1)
94
112
  a.last.should equal(@c2)
@@ -105,22 +123,54 @@ describe "Sequel::Plugins::StaticCache" do
105
123
 
106
124
  it "should have to_hash without arguments return the cached objects without a query" do
107
125
  a = @c.to_hash
126
+ a.should == {1=>@c1, 2=>@c2}
108
127
  a[1].should equal(@c1)
109
128
  a[2].should equal(@c2)
110
129
  @db.sqls.should == []
111
130
  end
112
131
 
113
- it "should have to_hash with any arguments use a query" do
114
- @c.to_hash(:id).should == {1=>@c1, 2=>@c2}
115
- @db.sqls.should == ['SELECT * FROM t']
132
+ it "should have to_hash with arguments return the cached objects without a query" do
133
+ a = @c.to_hash(:id)
134
+ a.should == {1=>@c1, 2=>@c2}
135
+ a[1].should equal(@c1)
136
+ a[2].should equal(@c2)
137
+
138
+ a = @c.to_hash([:id])
139
+ a.should == {[1]=>@c1, [2]=>@c2}
140
+ a[[1]].should equal(@c1)
141
+ a[[2]].should equal(@c2)
142
+
116
143
  @c.to_hash(:id, :id).should == {1=>1, 2=>2}
117
- @db.sqls.should == ['SELECT * FROM t']
144
+ @c.to_hash([:id], :id).should == {[1]=>1, [2]=>2}
145
+ @c.to_hash(:id, [:id]).should == {1=>[1], 2=>[2]}
146
+ @c.to_hash([:id], [:id]).should == {[1]=>[1], [2]=>[2]}
147
+
148
+ @db.sqls.should == []
118
149
  end
119
150
 
120
- it "should have all not return a frozen object" do
151
+ it "should have to_hash not return a frozen object" do
121
152
  @c.to_hash.frozen?.should be_false
122
153
  end
123
154
 
155
+ it "should have to_hash_groups without arguments return the cached objects without a query" do
156
+ a = @c.to_hash_groups(:id)
157
+ a.should == {1=>[@c1], 2=>[@c2]}
158
+ a[1].first.should equal(@c1)
159
+ a[2].first.should equal(@c2)
160
+
161
+ a = @c.to_hash_groups([:id])
162
+ a.should == {[1]=>[@c1], [2]=>[@c2]}
163
+ a[[1]].first.should equal(@c1)
164
+ a[[2]].first.should equal(@c2)
165
+
166
+ @c.to_hash_groups(:id, :id).should == {1=>[1], 2=>[2]}
167
+ @c.to_hash_groups([:id], :id).should == {[1]=>[1], [2]=>[2]}
168
+ @c.to_hash_groups(:id, [:id]).should == {1=>[[1]], 2=>[[2]]}
169
+ @c.to_hash_groups([:id], [:id]).should == {[1]=>[[1]], [2]=>[[2]]}
170
+
171
+ @db.sqls.should == []
172
+ end
173
+
124
174
  it "all of the static cache values (model instances) should be frozen" do
125
175
  @c.all.all?{|o| o.frozen?}.should be_true
126
176
  end
@@ -2,7 +2,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "Sequel::Plugins::TacticalEagerLoading" do
4
4
  before do
5
- class ::TaticalEagerLoadingModel < Sequel::Model
5
+ class ::TacticalEagerLoadingModel < Sequel::Model
6
6
  plugin :tactical_eager_loading
7
7
  columns :id, :parent_id
8
8
  many_to_one :parent, :class=>self
@@ -10,6 +10,8 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
10
10
  dataset._fetch = proc do |sql|
11
11
  if sql !~ /WHERE/
12
12
  [{:id=>1, :parent_id=>101}, {:id=>2, :parent_id=>102}, {:id=>101, :parent_id=>nil}, {:id=>102, :parent_id=>nil}]
13
+ elsif sql =~ /WHERE.*\bid = (\d+)/
14
+ [{:id=>$1.to_i, :parent_id=>nil}]
13
15
  elsif sql =~ /WHERE.*\bid IN \(([\d, ]*)\)/
14
16
  $1.split(', ').map{|x| {:id=>x.to_i, :parent_id=>nil}}
15
17
  elsif sql =~ /WHERE.*\bparent_id IN \(([\d, ]*)\)/
@@ -17,12 +19,12 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
17
19
  end
18
20
  end
19
21
  end
20
- @c = ::TaticalEagerLoadingModel
21
- @ds = TaticalEagerLoadingModel.dataset
22
+ @c = ::TacticalEagerLoadingModel
23
+ @ds = TacticalEagerLoadingModel.dataset
22
24
  MODEL_DB.reset
23
25
  end
24
26
  after do
25
- Object.send(:remove_const, :TaticalEagerLoadingModel)
27
+ Object.send(:remove_const, :TacticalEagerLoadingModel)
26
28
  end
27
29
 
28
30
  it "Dataset#all should set the retrieved_by and retrieved_with attributes" do
@@ -60,4 +62,17 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
60
62
  @c.all{|x| x.parent2 if x.is_a?(c)}
61
63
  end
62
64
 
65
+ it "association getter methods should not eagerly load the association if an instance is frozen" do
66
+ ts = @c.all
67
+ ts.first.freeze
68
+ MODEL_DB.sqls.length.should == 1
69
+ ts.map{|x| x.parent}.should == [ts[2], ts[3], nil, nil]
70
+ MODEL_DB.sqls.length.should == 2
71
+ ts.map{|x| x.children}.should == [[], [], [ts[0]], [ts[1]]]
72
+ MODEL_DB.sqls.length.should == 2
73
+ ts.map{|x| x.parent}.should == [ts[2], ts[3], nil, nil]
74
+ MODEL_DB.sqls.length.should == 1
75
+ ts.map{|x| x.children}.should == [[], [], [ts[0]], [ts[1]]]
76
+ MODEL_DB.sqls.length.should == 1
77
+ end
63
78
  end
@@ -7,7 +7,6 @@ describe "Sequel::Plugins::UpdatePrimaryKey" do
7
7
  @c.columns :a, :b
8
8
  @c.set_primary_key :a
9
9
  @c.unrestrict_primary_key
10
- @o = @c.new
11
10
  @ds = @c.dataset
12
11
  MODEL_DB.reset
13
12
  end
@@ -68,4 +67,21 @@ describe "Sequel::Plugins::UpdatePrimaryKey" do
68
67
  @c.all.should == [@c.load(:a=>2, :b=>5)]
69
68
  MODEL_DB.sqls.should == ["SELECT * FROM a LIMIT 1", "UPDATE a SET a = 2 WHERE (a = 1)", "UPDATE a SET b = 4 WHERE (a = 2)", "UPDATE a SET b = 5 WHERE (a = 2)", "SELECT * FROM a"]
70
69
  end
70
+
71
+ specify "should clear the associations cache of non-many_to_one associations when changing the primary key" do
72
+ @c.one_to_many :cs, :class=>@c
73
+ @c.many_to_one :c, :class=>@c
74
+ o = @c.new(:a=>1)
75
+ o.associations[:cs] = @c.new
76
+ o.associations[:c] = o2 = @c.new
77
+ o.a = 2
78
+ o.associations.should == {:c=>o2}
79
+ end
80
+
81
+ specify "should handle frozen instances" do
82
+ o = @c.new
83
+ o.a = 1
84
+ o.freeze
85
+ o.pk_hash.should == {:a=>1}
86
+ end
71
87
  end
@@ -799,6 +799,31 @@ describe Sequel::Model, "Validations" do
799
799
  @person.should be_valid
800
800
  end
801
801
 
802
+ it "should validate that a column has the correct type for the schema column" do
803
+ p = model_class.call Sequel::Model do
804
+ columns :age, :d
805
+ self.raise_on_typecast_failure = false
806
+ validates_schema_type :age
807
+ validates_schema_type :d, :message=>'is a bad choice'
808
+ @db_schema = {:age=>{:type=>:integer}, :d=>{:type=>:date}}
809
+ end
810
+
811
+ @person = p.new
812
+ @person.should be_valid
813
+
814
+ @person.age = 'a'
815
+ @person.should_not be_valid
816
+ @person.errors.full_messages.should == ['age is not a valid integer']
817
+ @person.age = 1
818
+ @person.should be_valid
819
+
820
+ @person.d = 'a'
821
+ @person.should_not be_valid
822
+ @person.errors.full_messages.should == ['d is a bad choice']
823
+ @person.d = Date.today
824
+ @person.should be_valid
825
+ end
826
+
802
827
  it "should validate numericality of column" do
803
828
  class ::Person < Sequel::Model
804
829
  validations.clear
@@ -247,6 +247,22 @@ describe "Sequel::Plugins::ValidationHelpers" do
247
247
  @m.errors.full_messages.should == ['value is not a valid integer']
248
248
  end
249
249
 
250
+ specify "should support validates_schema_types" do
251
+ @c.set_validations{validates_schema_types}
252
+ @m.value = 123
253
+ @m.should be_valid
254
+ @m.value = '123'
255
+ @m.should be_valid
256
+ @m.meta_def(:db_schema){{:value=>{:type=>:integer}}}
257
+ @m.should_not be_valid
258
+ @m.errors.full_messages.should == ['value is not a valid integer']
259
+
260
+ @c.set_validations{validates_schema_types(:value)}
261
+ @m.meta_def(:db_schema){{:value=>{:type=>:integer}}}
262
+ @m.should_not be_valid
263
+ @m.errors.full_messages.should == ['value is not a valid integer']
264
+ end
265
+
250
266
  specify "should support validates_numeric" do
251
267
  @c.set_validations{validates_numeric(:value)}
252
268
  @m.value = 'blah'
@@ -279,29 +295,57 @@ describe "Sequel::Plugins::ValidationHelpers" do
279
295
  @m.should be_valid
280
296
  @m.value = '123'
281
297
  @m.should_not be_valid
282
- @m.errors.full_messages.should == ['value is not a Integer']
298
+ @m.errors.full_messages.should == ['value is not a valid integer']
283
299
 
284
300
  @c.set_validations{validates_type(:String, :value)}
285
301
  @m.value = '123'
286
302
  @m.should be_valid
287
303
  @m.value = 123
288
304
  @m.should_not be_valid
289
- @m.errors.full_messages.should == ['value is not a String']
305
+ @m.errors.full_messages.should == ['value is not a valid string']
290
306
 
291
307
  @c.set_validations{validates_type('Integer', :value)}
292
308
  @m.value = 123
293
309
  @m.should be_valid
294
310
  @m.value = 123.05
295
311
  @m.should_not be_valid
296
- @m.errors.full_messages.should == ['value is not a Integer']
312
+ @m.errors.full_messages.should == ['value is not a valid integer']
297
313
 
298
314
  @c.set_validations{validates_type(Integer, :value)}
299
315
  @m.value = nil
300
316
  @m.should be_valid
301
317
  @m.value = false
302
318
  @m.should_not be_valid
319
+
320
+ @c.set_validations{validates_type([Integer, Float], :value)}
321
+ @m.value = nil
322
+ @m.should be_valid
323
+ @m.value = 1
324
+ @m.should be_valid
325
+ @m.value = 1.0
326
+ @m.should be_valid
327
+ @m.value = BigDecimal.new('1.0')
328
+ @m.should_not be_valid
329
+ @m.errors.full_messages.should == ['value is not a valid integer or float']
303
330
  end
304
331
 
332
+ specify "should support validates_not_null" do
333
+ @c.set_validations{validates_not_null(:value)}
334
+ @m.should_not be_valid
335
+ @m.value = ''
336
+ @m.should be_valid
337
+ @m.value = 1234
338
+ @m.should be_valid
339
+ @m.value = nil
340
+ @m.should_not be_valid
341
+ @m.value = true
342
+ @m.should be_valid
343
+ @m.value = false
344
+ @m.should be_valid
345
+ @m.value = Time.now
346
+ @m.should be_valid
347
+ end
348
+
305
349
  specify "should support validates_presence" do
306
350
  @c.set_validations{validates_presence(:value)}
307
351
  @m.should_not be_valid
@@ -466,4 +510,16 @@ describe "Sequel::Plugins::ValidationHelpers" do
466
510
  m.should be_valid
467
511
  MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '2') AND (password = '1') AND (id != 3)) LIMIT 1"]
468
512
  end
513
+
514
+ it "should not attempt a database query if the underlying columns have validation errors" do
515
+ @c.columns(:id, :username, :password)
516
+ @c.set_dataset MODEL_DB[:items]
517
+ @c.set_validations{validates_not_string(:username); validates_unique([:username, :password])}
518
+ @c.dataset._fetch = {:v=>0}
519
+
520
+ MODEL_DB.reset
521
+ m = @c.new(:username => "1", :password => "anothertest")
522
+ m.should_not be_valid
523
+ MODEL_DB.sqls.should == []
524
+ end
469
525
  end