sequel 4.43.0 → 4.44.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +40 -0
- data/doc/active_record.rdoc +2 -2
- data/doc/code_order.rdoc +15 -0
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/model_dataset_method_design.rdoc +132 -0
- data/doc/opening_databases.rdoc +2 -2
- data/doc/release_notes/4.44.0.txt +125 -0
- data/lib/sequel/adapters/jdbc.rb +5 -1
- data/lib/sequel/adapters/jdbc/as400.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +23 -14
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +27 -0
- data/lib/sequel/dataset/actions.rb +1 -1
- data/lib/sequel/dataset/query.rb +5 -1
- data/lib/sequel/extensions/eval_inspect.rb +4 -4
- data/lib/sequel/extensions/implicit_subquery.rb +48 -0
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model.rb +3 -5
- data/lib/sequel/model/associations.rb +107 -4
- data/lib/sequel/model/base.rb +98 -12
- data/lib/sequel/model/dataset_module.rb +1 -1
- data/lib/sequel/plugins/active_model.rb +11 -3
- data/lib/sequel/plugins/association_dependencies.rb +7 -0
- data/lib/sequel/plugins/auto_validations.rb +10 -0
- data/lib/sequel/plugins/blacklist_security.rb +13 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +11 -0
- data/lib/sequel/plugins/column_conflicts.rb +8 -0
- data/lib/sequel/plugins/composition.rb +12 -2
- data/lib/sequel/plugins/constraint_validations.rb +12 -0
- data/lib/sequel/plugins/csv_serializer.rb +9 -0
- data/lib/sequel/plugins/defaults_setter.rb +6 -0
- data/lib/sequel/plugins/force_encoding.rb +4 -3
- data/lib/sequel/plugins/hook_class_methods.rb +6 -0
- data/lib/sequel/plugins/input_transformer.rb +9 -0
- data/lib/sequel/plugins/insert_returning_select.rb +8 -0
- data/lib/sequel/plugins/instance_hooks.rb +4 -3
- data/lib/sequel/plugins/json_serializer.rb +9 -0
- data/lib/sequel/plugins/lazy_attributes.rb +7 -0
- data/lib/sequel/plugins/many_through_many.rb +13 -2
- data/lib/sequel/plugins/nested_attributes.rb +7 -0
- data/lib/sequel/plugins/pg_array_associations.rb +18 -2
- data/lib/sequel/plugins/pg_row.rb +3 -3
- data/lib/sequel/plugins/pg_typecast_on_load.rb +7 -0
- data/lib/sequel/plugins/prepared_statements.rb +2 -2
- data/lib/sequel/plugins/prepared_statements_safe.rb +7 -0
- data/lib/sequel/plugins/serialization.rb +9 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +13 -1
- data/lib/sequel/plugins/subclasses.rb +15 -1
- data/lib/sequel/plugins/touch.rb +7 -0
- data/lib/sequel/plugins/tree.rb +7 -0
- data/lib/sequel/plugins/typecast_on_load.rb +7 -0
- data/lib/sequel/plugins/update_refresh.rb +24 -13
- data/lib/sequel/plugins/validation_class_methods.rb +13 -0
- data/lib/sequel/sql.rb +28 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +18 -15
- data/spec/core/dataset_spec.rb +5 -0
- data/spec/core/expression_filters_spec.rb +33 -0
- data/spec/extensions/active_model_spec.rb +15 -1
- data/spec/extensions/association_dependencies_spec.rb +8 -0
- data/spec/extensions/auto_validations_spec.rb +8 -0
- data/spec/extensions/blacklist_security_spec.rb +6 -0
- data/spec/extensions/class_table_inheritance_spec.rb +9 -0
- data/spec/extensions/column_conflicts_spec.rb +6 -0
- data/spec/extensions/composition_spec.rb +8 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +12 -0
- data/spec/extensions/csv_serializer_spec.rb +7 -0
- data/spec/extensions/defaults_setter_spec.rb +7 -0
- data/spec/extensions/force_encoding_spec.rb +14 -0
- data/spec/extensions/hook_class_methods_spec.rb +10 -0
- data/spec/extensions/implicit_subquery_spec.rb +60 -0
- data/spec/extensions/input_transformer_spec.rb +10 -0
- data/spec/extensions/insert_returning_select_spec.rb +6 -0
- data/spec/extensions/json_serializer_spec.rb +7 -0
- data/spec/extensions/lazy_attributes_spec.rb +6 -0
- data/spec/extensions/many_through_many_spec.rb +44 -0
- data/spec/extensions/nested_attributes_spec.rb +5 -0
- data/spec/extensions/pg_array_associations_spec.rb +46 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +5 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +5 -0
- data/spec/extensions/serialization_spec.rb +7 -0
- data/spec/extensions/single_table_inheritance_spec.rb +19 -2
- data/spec/extensions/subclasses_spec.rb +13 -0
- data/spec/extensions/to_dot_spec.rb +1 -1
- data/spec/extensions/touch_spec.rb +6 -0
- data/spec/extensions/tree_spec.rb +6 -0
- data/spec/extensions/typecast_on_load_spec.rb +6 -0
- data/spec/extensions/update_refresh_spec.rb +7 -1
- data/spec/extensions/validation_class_methods_spec.rb +13 -0
- data/spec/model/association_reflection_spec.rb +177 -0
- data/spec/model/associations_spec.rb +16 -0
- data/spec/model/dataset_methods_spec.rb +59 -0
- data/spec/model/model_spec.rb +59 -0
- metadata +8 -2
data/spec/core/dataset_spec.rb
CHANGED
@@ -2057,6 +2057,11 @@ describe "Dataset#from_self" do
|
|
2057
2057
|
@ds.from_self.sql.must_equal 'SELECT * FROM (SELECT name FROM test LIMIT 1) AS t1'
|
2058
2058
|
end
|
2059
2059
|
|
2060
|
+
it "should keep any existing columns" do
|
2061
|
+
@ds.columns(:id, :a)
|
2062
|
+
@ds.from_self.columns.must_equal [:id, :a]
|
2063
|
+
end
|
2064
|
+
|
2060
2065
|
it "should modify only the new dataset" do
|
2061
2066
|
@ds.from_self.select(:bogus).sql.must_equal 'SELECT bogus FROM (SELECT name FROM test LIMIT 1) AS t1'
|
2062
2067
|
end
|
@@ -248,6 +248,10 @@ describe "Blockless Ruby Filters" do
|
|
248
248
|
@d.l(~((((Sequel.lit('x') - :y)/(Sequel.expr(:x) + :y))*:z) <= 100)).must_equal '((((x - y) / (x + y)) * z) > 100)'
|
249
249
|
end
|
250
250
|
|
251
|
+
it "should have LiteralString#inspect show it is a literal string" do
|
252
|
+
Sequel.lit('x').inspect.must_equal "#<Sequel::LiteralString \"x\">"
|
253
|
+
end
|
254
|
+
|
251
255
|
it "should support hashes by ANDing the conditions" do
|
252
256
|
@d.l(:x => 100, :y => 'a')[1...-1].split(' AND ').sort.must_equal ['(x = 100)', '(y = \'a\')']
|
253
257
|
@d.l(:x => true, :y => false)[1...-1].split(' AND ').sort.must_equal ['(x IS TRUE)', '(y IS FALSE)']
|
@@ -270,6 +274,10 @@ describe "Blockless Ruby Filters" do
|
|
270
274
|
@d.l([:x, :y]=>Sequel.value_list([[1,2], [3,4]])).must_equal '(((x = 1) AND (y = 2)) OR ((x = 3) AND (y = 4)))'
|
271
275
|
@d.l([:x, :y, :z]=>[[1,2,5], [3,4,6]]).must_equal '(((x = 1) AND (y = 2) AND (z = 5)) OR ((x = 3) AND (y = 4) AND (z = 6)))'
|
272
276
|
end
|
277
|
+
|
278
|
+
it "should have SQL::ValueList#inspect show it is a value list" do
|
279
|
+
Sequel.value_list([[1,2], [3,4]]).inspect.must_equal "#<Sequel::SQL::ValueList [[1, 2], [3, 4]]>"
|
280
|
+
end
|
273
281
|
|
274
282
|
it "should support StringExpression#+ for concatenation of SQL strings" do
|
275
283
|
@d.lit(Sequel.expr(:x).sql_string + :y).must_equal '(x || y)'
|
@@ -952,6 +960,21 @@ describe "Sequel core extension replacements" do
|
|
952
960
|
Sequel.blob(o).must_be_same_as(o)
|
953
961
|
end
|
954
962
|
|
963
|
+
it "Sequel.blob#inspect output should indicate it is a blob and the size" do
|
964
|
+
o = Sequel.blob('a')
|
965
|
+
o.inspect.must_equal "#<Sequel::SQL::Blob:0x#{'%x' % o.object_id} bytes=1 content=\"a\">"
|
966
|
+
o = Sequel.blob(('a'..'z').to_a.join)
|
967
|
+
o.inspect.must_equal "#<Sequel::SQL::Blob:0x#{'%x' % o.object_id} bytes=26 start=\"abcdefghij\" end=\"qrstuvwxyz\">"
|
968
|
+
o = Sequel.blob(255.chr)
|
969
|
+
o.inspect.must_equal "#<Sequel::SQL::Blob:0x#{'%x' % o.object_id} bytes=1 content=\"#{RUBY_VERSION >= '1.9' ? "\\xFF" : "\\377"}\">"
|
970
|
+
o = Sequel.blob((230..255).map(&:chr).join)
|
971
|
+
if RUBY_VERSION >= '1.9'
|
972
|
+
o.inspect.must_equal "#<Sequel::SQL::Blob:0x#{'%x' % o.object_id} bytes=26 start=\"\\xE6\\xE7\\xE8\\xE9\\xEA\\xEB\\xEC\\xED\\xEE\\xEF\" end=\"\\xF6\\xF7\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\">"
|
973
|
+
else
|
974
|
+
o.inspect.must_equal "#<Sequel::SQL::Blob:0x#{'%x' % o.object_id} bytes=26 start=\"\\346\\347\\350\\351\\352\\353\\354\\355\\356\\357\" end=\"\\366\\367\\370\\371\\372\\373\\374\\375\\376\\377\">"
|
975
|
+
end
|
976
|
+
end
|
977
|
+
|
955
978
|
it "Sequel.deep_qualify should do a deep qualification into nested structors" do
|
956
979
|
l(Sequel.deep_qualify(:t, Sequel.+(:c, 1)), "(t.c + 1)")
|
957
980
|
end
|
@@ -1138,6 +1161,11 @@ describe "Sequel::SQLTime" do
|
|
1138
1161
|
Sequel::SQLTime.create(1, 2, 3).strftime('%Y-%m-%d').must_equal Date.new(2000).strftime('%Y-%m-%d')
|
1139
1162
|
end
|
1140
1163
|
|
1164
|
+
it "#inspect should show class and time by default" do
|
1165
|
+
Sequel::SQLTime.create(1, 2, 3).inspect.must_equal "#<Sequel::SQLTime 01:02:03>"
|
1166
|
+
Sequel::SQLTime.create(13, 24, 35).inspect.must_equal "#<Sequel::SQLTime 13:24:35>"
|
1167
|
+
end
|
1168
|
+
|
1141
1169
|
it "#to_s should include hour, minute, and second by default" do
|
1142
1170
|
Sequel::SQLTime.create(1, 2, 3).to_s.must_equal "01:02:03"
|
1143
1171
|
Sequel::SQLTime.create(1, 2, 3, 500000).to_s.must_equal "01:02:03"
|
@@ -1225,6 +1253,11 @@ describe "Sequel.recursive_map" do
|
|
1225
1253
|
Sequel.recursive_map([nil], proc{|s| s.to_i}).must_equal [nil]
|
1226
1254
|
Sequel.recursive_map([[nil]], proc{|s| s.to_i}).must_equal [[nil]]
|
1227
1255
|
end
|
1256
|
+
|
1257
|
+
it "should call callable for falsey value" do
|
1258
|
+
Sequel.recursive_map([false], proc{|s| s.to_s}).must_equal ['false']
|
1259
|
+
Sequel.recursive_map([[false]], proc{|s| s.to_s}).must_equal [['false']]
|
1260
|
+
end
|
1228
1261
|
end
|
1229
1262
|
|
1230
1263
|
describe "Sequel.delay" do
|
@@ -19,6 +19,7 @@ describe "ActiveModel plugin" do
|
|
19
19
|
end
|
20
20
|
@c = AMLintTest
|
21
21
|
@c.plugin :active_model
|
22
|
+
@c.freeze if @freeze_class
|
22
23
|
@m = @model = @c.new
|
23
24
|
@o = @c.load({})
|
24
25
|
end
|
@@ -26,7 +27,6 @@ describe "ActiveModel plugin" do
|
|
26
27
|
Object.send(:remove_const, :AMLintTest)
|
27
28
|
Object.send(:remove_const, :Blog)
|
28
29
|
end
|
29
|
-
include ActiveModel::Lint::Tests
|
30
30
|
|
31
31
|
it ".to_model should return self, not a proxy object" do
|
32
32
|
@m.object_id.must_equal @m.to_model.object_id
|
@@ -40,6 +40,7 @@ describe "ActiveModel plugin" do
|
|
40
40
|
@o.to_key.must_be_nil
|
41
41
|
|
42
42
|
@c.set_primary_key [:id2, :id]
|
43
|
+
@c.freeze
|
43
44
|
@o.to_key.must_be_nil
|
44
45
|
@o.id = 1
|
45
46
|
@o.id2 = 2
|
@@ -55,6 +56,7 @@ describe "ActiveModel plugin" do
|
|
55
56
|
@o.id = 1
|
56
57
|
@o.to_param.must_equal '1'
|
57
58
|
@c.set_primary_key [:id2, :id]
|
59
|
+
@c.freeze
|
58
60
|
@o.id2 = 2
|
59
61
|
@o.to_param.must_equal '2-1'
|
60
62
|
@o.meta_def(:to_param_joiner){'|'}
|
@@ -81,5 +83,17 @@ describe "ActiveModel plugin" do
|
|
81
83
|
@m.to_partial_path.must_equal 'am_lint_tests/am_lint_test'
|
82
84
|
Blog::Post.new.to_partial_path.must_equal 'blog/posts/post'
|
83
85
|
end
|
86
|
+
|
87
|
+
describe "with unfrozen model class" do
|
88
|
+
include ActiveModel::Lint::Tests
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "with frozen model class" do
|
92
|
+
before do
|
93
|
+
@freeze_class = true
|
94
|
+
end
|
95
|
+
|
96
|
+
include ActiveModel::Lint::Tests
|
97
|
+
end
|
84
98
|
end
|
85
99
|
end
|
@@ -72,6 +72,14 @@ describe "AssociationDependencies plugin" do
|
|
72
72
|
DB.sqls.must_equal ['DELETE FROM aoa WHERE (l = 2)', 'DELETE FROM artists WHERE id = 2']
|
73
73
|
end
|
74
74
|
|
75
|
+
it "should not allow modifications if class is frozen" do
|
76
|
+
@Artist.add_association_dependencies :other_artists=>:nullify
|
77
|
+
@Artist.freeze
|
78
|
+
proc{@Artist.add_association_dependencies :albums=>:nullify}.must_raise RuntimeError, TypeError
|
79
|
+
@Artist.association_dependencies.frozen?.must_equal true
|
80
|
+
@Artist.association_dependencies[:before_nullify].frozen?.must_equal true
|
81
|
+
end
|
82
|
+
|
75
83
|
it "should raise an error if attempting to nullify a many_to_one association" do
|
76
84
|
proc{@Album.add_association_dependencies :artist=>:nullify}.must_raise(Sequel::Error)
|
77
85
|
end
|
@@ -189,4 +189,12 @@ describe "Sequel::Plugins::AutoValidations" do
|
|
189
189
|
@m.valid?.must_equal false
|
190
190
|
@m.errors.must_equal([:name, :num]=>["u_message"])
|
191
191
|
end
|
192
|
+
|
193
|
+
it "should not allow modifying auto validation information for frozen model classes" do
|
194
|
+
@c.freeze
|
195
|
+
@c.auto_validate_not_null_columns.frozen?.must_equal true
|
196
|
+
@c.auto_validate_explicit_not_null_columns.frozen?.must_equal true
|
197
|
+
@c.auto_validate_max_length_columns.frozen?.must_equal true
|
198
|
+
@c.auto_validate_unique_columns.frozen?.must_equal true
|
199
|
+
end
|
192
200
|
end
|
@@ -85,4 +85,10 @@ describe Sequel::Model, ".restricted_columns " do
|
|
85
85
|
i.values.must_equal(:y => 7)
|
86
86
|
DB.sqls.must_equal ["INSERT INTO blahblah (y) VALUES (7)", "SELECT * FROM blahblah WHERE id = 10"]
|
87
87
|
end
|
88
|
+
|
89
|
+
it "should freeze restricted_columns when freezing class" do
|
90
|
+
@c.set_restricted_columns :z
|
91
|
+
@c.freeze
|
92
|
+
@c.restricted_columns.frozen?.must_equal true
|
93
|
+
end
|
88
94
|
end
|
@@ -51,6 +51,15 @@ describe "class_table_inheritance plugin" do
|
|
51
51
|
Object.send(:remove_const, :Employee)
|
52
52
|
end
|
53
53
|
|
54
|
+
it "should freeze CTI information when freezing model class" do
|
55
|
+
Employee.freeze
|
56
|
+
Employee.cti_models.frozen?.must_equal true
|
57
|
+
Employee.cti_tables.frozen?.must_equal true
|
58
|
+
Employee.cti_instance_dataset.frozen?.must_equal true
|
59
|
+
Employee.cti_table_columns.frozen?.must_equal true
|
60
|
+
Employee.cti_table_map.frozen?.must_equal true
|
61
|
+
end
|
62
|
+
|
54
63
|
it "should not attempt to use prepared statements" do
|
55
64
|
Manager.plugin :prepared_statements
|
56
65
|
Manager[1]
|
@@ -55,4 +55,10 @@ describe "column_conflicts plugin" do
|
|
55
55
|
o.get_column_value(:object_id).must_equal 3
|
56
56
|
o.object_id.wont_equal 3
|
57
57
|
end
|
58
|
+
|
59
|
+
it "should freeze column conflict information when freezing model class" do
|
60
|
+
@c.freeze
|
61
|
+
@c.get_column_conflicts.frozen?.must_equal true
|
62
|
+
@c.set_column_conflicts.frozen?.must_equal true
|
63
|
+
end
|
58
64
|
end
|
@@ -241,4 +241,12 @@ describe "Composition plugin" do
|
|
241
241
|
sql.must_include("month = 2")
|
242
242
|
sql.must_include("day = 3")
|
243
243
|
end
|
244
|
+
|
245
|
+
it "should freeze composition metadata when freezing model class" do
|
246
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
247
|
+
@c.freeze
|
248
|
+
@c.compositions.frozen?.must_equal true
|
249
|
+
@c.compositions[:date].frozen?.must_equal true
|
250
|
+
@c.composition_module.frozen?.must_equal true
|
251
|
+
end
|
244
252
|
end
|
@@ -285,4 +285,16 @@ describe "Sequel::Plugins::ConstraintValidations" do
|
|
285
285
|
c.constraint_validations.must_equal [[:validates_presence, :name]]
|
286
286
|
c.constraint_validation_reflections.must_equal(:name=>[[:presence, {}]])
|
287
287
|
end
|
288
|
+
|
289
|
+
it "should freeze constraint validations data when freezing model class" do
|
290
|
+
@c = model_class
|
291
|
+
@c.freeze
|
292
|
+
@c.constraint_validations.frozen?.must_equal true
|
293
|
+
@c.constraint_validations.all?(&:frozen?).must_equal true
|
294
|
+
@c.constraint_validation_reflections.frozen?.must_equal true
|
295
|
+
@c.constraint_validation_reflections.values.all?(&:frozen?).must_equal true
|
296
|
+
@c.constraint_validation_reflections.values.all?{|r| r.all?(&:frozen?)}.must_equal true
|
297
|
+
@c.instance_variable_get(:@constraint_validation_options).frozen?.must_equal true
|
298
|
+
@c.instance_variable_get(:@constraint_validation_options).values.all?(&:frozen?).must_equal true
|
299
|
+
end
|
288
300
|
end
|
@@ -177,5 +177,12 @@ describe "Sequel::Plugins::CsvSerializer" do
|
|
177
177
|
@album.to_csv(:only=>:name).must_equal "RF\n"
|
178
178
|
@album.to_csv(:except=>[:id, :artist_id]).must_equal "RF\n"
|
179
179
|
end
|
180
|
+
|
181
|
+
it "should freeze csv serializier opts when model class is frozen" do
|
182
|
+
@Album.csv_serializer_opts[:only] = [:id]
|
183
|
+
@Album.freeze
|
184
|
+
@Album.csv_serializer_opts.frozen?.must_equal true
|
185
|
+
@Album.csv_serializer_opts[:only].frozen?.must_equal true
|
186
|
+
end
|
180
187
|
end
|
181
188
|
end
|
@@ -99,4 +99,11 @@ describe "Sequel::Plugins::DefaultsSetter" do
|
|
99
99
|
c.plugin :defaults_setter
|
100
100
|
c.default_values.must_equal(:a=>2)
|
101
101
|
end
|
102
|
+
|
103
|
+
it "should freeze default values when freezing model class" do
|
104
|
+
c = Class.new(Sequel::Model(@db[:bar]))
|
105
|
+
c.plugin :defaults_setter
|
106
|
+
c.freeze
|
107
|
+
c.default_values.frozen?.must_equal true
|
108
|
+
end
|
102
109
|
end
|
@@ -24,6 +24,20 @@ describe "force_encoding plugin" do
|
|
24
24
|
o.x.encoding.must_equal @e1
|
25
25
|
end
|
26
26
|
|
27
|
+
it "should not force encoding of blobs to given encoding on load" do
|
28
|
+
s = Sequel.blob('blah'.dup.force_encoding('BINARY'))
|
29
|
+
o = @c.load(:id=>1, :x=>s)
|
30
|
+
o.x.must_equal 'blah'
|
31
|
+
o.x.encoding.must_equal Encoding.find('BINARY')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should not force encoding of blobs to given encoding when setting column values" do
|
35
|
+
s = Sequel.blob('blah'.dup.force_encoding('BINARY'))
|
36
|
+
o = @c.new(:x=>s)
|
37
|
+
o.x.must_equal 'blah'
|
38
|
+
o.x.encoding.must_equal Encoding.find('BINARY')
|
39
|
+
end
|
40
|
+
|
27
41
|
it "should work correctly when given a frozen string" do
|
28
42
|
s = 'blah'.dup
|
29
43
|
s.force_encoding('US-ASCII')
|
@@ -12,6 +12,16 @@ describe Sequel::Model, "hook_class_methods plugin" do
|
|
12
12
|
DB.reset
|
13
13
|
end
|
14
14
|
|
15
|
+
it "should freeze hooks when freezing model class" do
|
16
|
+
c = model_class.call Sequel::Model do
|
17
|
+
before_save{adds << 'hi'}
|
18
|
+
end
|
19
|
+
c.freeze
|
20
|
+
hooks = c.instance_variable_get(:@hooks)
|
21
|
+
hooks.frozen?.must_equal true
|
22
|
+
hooks.values.all?(&:frozen?).must_equal true
|
23
|
+
end
|
24
|
+
|
15
25
|
it "should be definable using a block" do
|
16
26
|
adds = []
|
17
27
|
c = model_class.call Sequel::Model do
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Dataset::ImplicitSubquery" do
|
4
|
+
it "should implicitly use a subquery for most dataset query methods" do
|
5
|
+
db = Sequel.mock
|
6
|
+
db.extend_datasets{def supports_cte?; true end}
|
7
|
+
ds = db["SELECT * FROM table"].extension(:implicit_subquery)
|
8
|
+
ds.columns(:id, :a)
|
9
|
+
ods = db[:c]
|
10
|
+
ods.columns(:id, :b)
|
11
|
+
|
12
|
+
ds.and(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 WHERE c"
|
13
|
+
ds.cross_join(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 CROSS JOIN c"
|
14
|
+
ds.distinct.sql.must_equal "SELECT DISTINCT * FROM (SELECT * FROM table) AS t1"
|
15
|
+
ds.except(ods).sql.must_equal "SELECT * FROM (SELECT * FROM (SELECT * FROM table) AS t1 EXCEPT SELECT * FROM c) AS t1"
|
16
|
+
ds.exclude(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 WHERE NOT c"
|
17
|
+
ds.exclude_having(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 HAVING NOT c"
|
18
|
+
ds.exclude_where(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 WHERE NOT c"
|
19
|
+
ds.filter(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 WHERE c"
|
20
|
+
ds.for_update.sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 FOR UPDATE"
|
21
|
+
ds.full_join(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 FULL JOIN c"
|
22
|
+
ds.full_outer_join(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 FULL OUTER JOIN c"
|
23
|
+
ds.graph(ods).sql.must_equal "SELECT t1.id, t1.a, c.id AS c_id, c.b FROM (SELECT * FROM table) AS t1 LEFT OUTER JOIN c"
|
24
|
+
ds.grep(:c, 'a').sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 WHERE ((c LIKE 'a' ESCAPE '\\'))"
|
25
|
+
ds.group(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 GROUP BY c"
|
26
|
+
ds.group_append(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 GROUP BY c"
|
27
|
+
ds.group_and_count(:c).sql.must_equal "SELECT c, count(*) AS count FROM (SELECT * FROM table) AS t1 GROUP BY c"
|
28
|
+
ds.group_by(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 GROUP BY c"
|
29
|
+
ds.having(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 HAVING c"
|
30
|
+
ds.inner_join(:c, [:d]).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 INNER JOIN c USING (d)"
|
31
|
+
ds.intersect(ods).sql.must_equal "SELECT * FROM (SELECT * FROM (SELECT * FROM table) AS t1 INTERSECT SELECT * FROM c) AS t1"
|
32
|
+
ds.invert.sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 WHERE 'f'"
|
33
|
+
ds.join(:c, [:d]).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 INNER JOIN c USING (d)"
|
34
|
+
ds.join_table(:inner, :c, [:d]).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 INNER JOIN c USING (d)"
|
35
|
+
ds.left_join(:c, [:d]).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 LEFT JOIN c USING (d)"
|
36
|
+
ds.left_outer_join(:c, [:d]).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 LEFT OUTER JOIN c USING (d)"
|
37
|
+
ds.limit(1).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 LIMIT 1"
|
38
|
+
ds.lock_style('FOR UPDATE').sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 FOR UPDATE"
|
39
|
+
ds.natural_full_join(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 NATURAL FULL JOIN c"
|
40
|
+
ds.natural_join(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 NATURAL JOIN c"
|
41
|
+
ds.natural_left_join(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 NATURAL LEFT JOIN c"
|
42
|
+
ds.natural_right_join(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 NATURAL RIGHT JOIN c"
|
43
|
+
ds.offset(1).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 OFFSET 1"
|
44
|
+
ds.order(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 ORDER BY c"
|
45
|
+
ds.order_append(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 ORDER BY c"
|
46
|
+
ds.order_by(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 ORDER BY c"
|
47
|
+
ds.order_more(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 ORDER BY c"
|
48
|
+
ds.order_prepend(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 ORDER BY c"
|
49
|
+
ds.right_join(:c, [:d]).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 RIGHT JOIN c USING (d)"
|
50
|
+
ds.right_outer_join(:c, [:d]).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 RIGHT OUTER JOIN c USING (d)"
|
51
|
+
ds.select(:c).sql.must_equal "SELECT c FROM (SELECT * FROM table) AS t1"
|
52
|
+
ds.select_append(:c).sql.must_equal "SELECT *, c FROM (SELECT * FROM table) AS t1"
|
53
|
+
ds.select_group(:c).sql.must_equal "SELECT c FROM (SELECT * FROM table) AS t1 GROUP BY c"
|
54
|
+
ds.select_more(:c).sql.must_equal "SELECT *, c FROM (SELECT * FROM table) AS t1"
|
55
|
+
ds.union(ods).sql.must_equal "SELECT * FROM (SELECT * FROM (SELECT * FROM table) AS t1 UNION SELECT * FROM c) AS t1"
|
56
|
+
ds.where(:c).sql.must_equal "SELECT * FROM (SELECT * FROM table) AS t1 WHERE c"
|
57
|
+
ds.with(:d, ods).sql.must_equal "WITH d AS (SELECT * FROM c) SELECT * FROM (SELECT * FROM table) AS t1"
|
58
|
+
ds.with_recursive(:d, ods, ods).sql.must_equal "WITH d AS (SELECT * FROM c UNION ALL SELECT * FROM c) SELECT * FROM (SELECT * FROM table) AS t1"
|
59
|
+
end
|
60
|
+
end
|
@@ -51,4 +51,14 @@ describe "Sequel::Plugins::InputTransformer" do
|
|
51
51
|
@o.name = ' name '.dup
|
52
52
|
@o.name.must_equal 'raboof eman '
|
53
53
|
end
|
54
|
+
|
55
|
+
it "should freeze input transformers when freezing model class" do
|
56
|
+
@c.skip_input_transformer :reverser, :name
|
57
|
+
@c.freeze
|
58
|
+
@c.input_transformers.frozen?.must_equal true
|
59
|
+
@c.input_transformer_order.frozen?.must_equal true
|
60
|
+
skip = @c.instance_variable_get(:@skip_input_transformer_columns)
|
61
|
+
skip.frozen?.must_equal true
|
62
|
+
skip.values.all?(&:frozen?).must_equal true
|
63
|
+
end
|
54
64
|
end
|
@@ -63,4 +63,10 @@ describe "Sequel::Plugins::InsertReturningSelect" do
|
|
63
63
|
b.create(:x=>2).must_equal b.load(:id=>1, :x=>2)
|
64
64
|
@db.sqls.must_equal ['INSERT INTO albums (x) VALUES (2) RETURNING id, x']
|
65
65
|
end
|
66
|
+
|
67
|
+
it "should freeze instance_insert_dataset when freezing model class" do
|
68
|
+
@Album.plugin :insert_returning_select
|
69
|
+
@Album.freeze
|
70
|
+
@Album.instance_insert_dataset.frozen?.must_equal true
|
71
|
+
end
|
66
72
|
end
|
@@ -303,4 +303,11 @@ describe "Sequel::Plugins::JsonSerializer" do
|
|
303
303
|
it "should raise an error if using an unsupported :associations option" do
|
304
304
|
proc{Artist.from_json(@artist.to_json, :associations=>'')}.must_raise(Sequel::Error)
|
305
305
|
end
|
306
|
+
|
307
|
+
it "should freeze json serializier opts when model class is frozen" do
|
308
|
+
Album.json_serializer_opts[:only] = [:id]
|
309
|
+
Album.freeze
|
310
|
+
Album.json_serializer_opts.frozen?.must_equal true
|
311
|
+
Album.json_serializer_opts[:only].frozen?.must_equal true
|
312
|
+
end
|
306
313
|
end
|
@@ -167,4 +167,10 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
167
167
|
m.name.must_equal 3
|
168
168
|
@db.sqls.must_equal ["SELECT la.id FROM la LIMIT 1", "SELECT la.name FROM la WHERE (id = 1) LIMIT 1"]
|
169
169
|
end
|
170
|
+
|
171
|
+
it "should freeze lazy_attributes_module when freezing model class" do
|
172
|
+
@c.plugin :lazy_attributes, :blah
|
173
|
+
@c.freeze
|
174
|
+
@c.lazy_attributes_module.frozen?.must_equal true
|
175
|
+
end
|
170
176
|
end
|
@@ -2115,3 +2115,47 @@ describe "one_through_many eager loading methods" do
|
|
2115
2115
|
@c1.order(:artists__blah2, :artists__blah3).eager_graph(:tag).sql.must_equal 'SELECT artists.id, tag.id AS tag_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags AS tag ON (tag.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tag.blah__id, tag.blah__id DESC, blah.id DESC, blah.id, tag.album_id, tag.album_id DESC, 1, RANDOM(), b.a'
|
2116
2116
|
end
|
2117
2117
|
end
|
2118
|
+
|
2119
|
+
describe "Sequel::Model.finalize_associations" do
|
2120
|
+
before do
|
2121
|
+
class ::Item < Sequel::Model
|
2122
|
+
plugin :many_through_many
|
2123
|
+
many_through_many :items, [[:foos, :item1_id, :foo1_id], [:bars, :foo2_id, :item2_id]]
|
2124
|
+
one_through_many :item, [[:foos, :item1_id, :foo1_id], [:bars, :foo2_id, :item2_id]]
|
2125
|
+
finalize_associations
|
2126
|
+
end
|
2127
|
+
end
|
2128
|
+
after do
|
2129
|
+
Object.send(:remove_const, :Item)
|
2130
|
+
end
|
2131
|
+
|
2132
|
+
it "should finalize one_through_many associations" do
|
2133
|
+
r = Item.association_reflection(:item)
|
2134
|
+
r[:class].must_equal Item
|
2135
|
+
r[:_dataset].sql.must_equal "SELECT items.* FROM items INNER JOIN bars ON (bars.item2_id = items.id) INNER JOIN foos ON (foos.foo1_id = bars.foo2_id) LIMIT 1"
|
2136
|
+
r[:associated_eager_dataset].sql.must_equal "SELECT items.* FROM items INNER JOIN bars ON (bars.item2_id = items.id) INNER JOIN foos ON (foos.foo1_id = bars.foo2_id)"
|
2137
|
+
r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT foos.item1_id FROM items INNER JOIN bars ON (bars.item2_id = items.id) INNER JOIN foos ON (foos.foo1_id = bars.foo2_id) WHERE (foos.item1_id IS NOT NULL)"
|
2138
|
+
r[:placeholder_loader].wont_be_nil
|
2139
|
+
r[:predicate_key].must_equal Sequel.qualify(:foos, :item1_id)
|
2140
|
+
r[:associated_key_table].must_equal :foos
|
2141
|
+
r[:edges].must_equal [{:table=>:foos, :left=>:id, :right=>:item1_id, :conditions=>[], :join_type=>:left_outer, :block=>nil}, {:table=>:bars, :left=>:foo1_id, :right=>:foo2_id, :conditions=>[], :join_type=>:left_outer, :block=>nil}]
|
2142
|
+
r[:final_edge].must_equal(:table=>:items, :left=>:item2_id, :right=>:id, :conditions=>nil, :join_type=>nil, :block=>nil)
|
2143
|
+
r[:final_reverse_edge].must_equal(:table=>:foos, :left=>:foo1_id, :right=>:foo2_id, :alias=>:foos)
|
2144
|
+
r[:reverse_edges].must_equal [{:table=>:bars, :left=>:item2_id, :right=>:id, :alias=>:bars}]
|
2145
|
+
end
|
2146
|
+
|
2147
|
+
it "should finalize many_through_many associations" do
|
2148
|
+
r = Item.association_reflection(:items)
|
2149
|
+
r[:class].must_equal Item
|
2150
|
+
r[:_dataset].sql.must_equal "SELECT items.* FROM items INNER JOIN bars ON (bars.item2_id = items.id) INNER JOIN foos ON (foos.foo1_id = bars.foo2_id)"
|
2151
|
+
r[:associated_eager_dataset].sql.must_equal "SELECT items.* FROM items INNER JOIN bars ON (bars.item2_id = items.id) INNER JOIN foos ON (foos.foo1_id = bars.foo2_id)"
|
2152
|
+
r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT foos.item1_id FROM items INNER JOIN bars ON (bars.item2_id = items.id) INNER JOIN foos ON (foos.foo1_id = bars.foo2_id) WHERE (foos.item1_id IS NOT NULL)"
|
2153
|
+
r[:placeholder_loader].wont_be_nil
|
2154
|
+
r[:predicate_key].must_equal Sequel.qualify(:foos, :item1_id)
|
2155
|
+
r[:associated_key_table].must_equal :foos
|
2156
|
+
r[:edges].must_equal [{:table=>:foos, :left=>:id, :right=>:item1_id, :conditions=>[], :join_type=>:left_outer, :block=>nil}, {:table=>:bars, :left=>:foo1_id, :right=>:foo2_id, :conditions=>[], :join_type=>:left_outer, :block=>nil}]
|
2157
|
+
r[:final_edge].must_equal(:table=>:items, :left=>:item2_id, :right=>:id, :conditions=>nil, :join_type=>nil, :block=>nil)
|
2158
|
+
r[:final_reverse_edge].must_equal(:table=>:foos, :left=>:foo1_id, :right=>:foo2_id, :alias=>:foos)
|
2159
|
+
r[:reverse_edges].must_equal [{:table=>:bars, :left=>:item2_id, :right=>:id, :alias=>:bars}]
|
2160
|
+
end
|
2161
|
+
end
|