sequel 4.43.0 → 4.44.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +40 -0
  3. data/doc/active_record.rdoc +2 -2
  4. data/doc/code_order.rdoc +15 -0
  5. data/doc/dataset_filtering.rdoc +1 -1
  6. data/doc/model_dataset_method_design.rdoc +132 -0
  7. data/doc/opening_databases.rdoc +2 -2
  8. data/doc/release_notes/4.44.0.txt +125 -0
  9. data/lib/sequel/adapters/jdbc.rb +5 -1
  10. data/lib/sequel/adapters/jdbc/as400.rb +1 -1
  11. data/lib/sequel/adapters/postgres.rb +23 -14
  12. data/lib/sequel/core.rb +1 -1
  13. data/lib/sequel/database/schema_generator.rb +27 -0
  14. data/lib/sequel/dataset/actions.rb +1 -1
  15. data/lib/sequel/dataset/query.rb +5 -1
  16. data/lib/sequel/extensions/eval_inspect.rb +4 -4
  17. data/lib/sequel/extensions/implicit_subquery.rb +48 -0
  18. data/lib/sequel/extensions/to_dot.rb +1 -1
  19. data/lib/sequel/model.rb +3 -5
  20. data/lib/sequel/model/associations.rb +107 -4
  21. data/lib/sequel/model/base.rb +98 -12
  22. data/lib/sequel/model/dataset_module.rb +1 -1
  23. data/lib/sequel/plugins/active_model.rb +11 -3
  24. data/lib/sequel/plugins/association_dependencies.rb +7 -0
  25. data/lib/sequel/plugins/auto_validations.rb +10 -0
  26. data/lib/sequel/plugins/blacklist_security.rb +13 -4
  27. data/lib/sequel/plugins/class_table_inheritance.rb +11 -0
  28. data/lib/sequel/plugins/column_conflicts.rb +8 -0
  29. data/lib/sequel/plugins/composition.rb +12 -2
  30. data/lib/sequel/plugins/constraint_validations.rb +12 -0
  31. data/lib/sequel/plugins/csv_serializer.rb +9 -0
  32. data/lib/sequel/plugins/defaults_setter.rb +6 -0
  33. data/lib/sequel/plugins/force_encoding.rb +4 -3
  34. data/lib/sequel/plugins/hook_class_methods.rb +6 -0
  35. data/lib/sequel/plugins/input_transformer.rb +9 -0
  36. data/lib/sequel/plugins/insert_returning_select.rb +8 -0
  37. data/lib/sequel/plugins/instance_hooks.rb +4 -3
  38. data/lib/sequel/plugins/json_serializer.rb +9 -0
  39. data/lib/sequel/plugins/lazy_attributes.rb +7 -0
  40. data/lib/sequel/plugins/many_through_many.rb +13 -2
  41. data/lib/sequel/plugins/nested_attributes.rb +7 -0
  42. data/lib/sequel/plugins/pg_array_associations.rb +18 -2
  43. data/lib/sequel/plugins/pg_row.rb +3 -3
  44. data/lib/sequel/plugins/pg_typecast_on_load.rb +7 -0
  45. data/lib/sequel/plugins/prepared_statements.rb +2 -2
  46. data/lib/sequel/plugins/prepared_statements_safe.rb +7 -0
  47. data/lib/sequel/plugins/serialization.rb +9 -0
  48. data/lib/sequel/plugins/single_table_inheritance.rb +13 -1
  49. data/lib/sequel/plugins/subclasses.rb +15 -1
  50. data/lib/sequel/plugins/touch.rb +7 -0
  51. data/lib/sequel/plugins/tree.rb +7 -0
  52. data/lib/sequel/plugins/typecast_on_load.rb +7 -0
  53. data/lib/sequel/plugins/update_refresh.rb +24 -13
  54. data/lib/sequel/plugins/validation_class_methods.rb +13 -0
  55. data/lib/sequel/sql.rb +28 -0
  56. data/lib/sequel/version.rb +1 -1
  57. data/spec/adapters/postgres_spec.rb +18 -15
  58. data/spec/core/dataset_spec.rb +5 -0
  59. data/spec/core/expression_filters_spec.rb +33 -0
  60. data/spec/extensions/active_model_spec.rb +15 -1
  61. data/spec/extensions/association_dependencies_spec.rb +8 -0
  62. data/spec/extensions/auto_validations_spec.rb +8 -0
  63. data/spec/extensions/blacklist_security_spec.rb +6 -0
  64. data/spec/extensions/class_table_inheritance_spec.rb +9 -0
  65. data/spec/extensions/column_conflicts_spec.rb +6 -0
  66. data/spec/extensions/composition_spec.rb +8 -0
  67. data/spec/extensions/constraint_validations_plugin_spec.rb +12 -0
  68. data/spec/extensions/csv_serializer_spec.rb +7 -0
  69. data/spec/extensions/defaults_setter_spec.rb +7 -0
  70. data/spec/extensions/force_encoding_spec.rb +14 -0
  71. data/spec/extensions/hook_class_methods_spec.rb +10 -0
  72. data/spec/extensions/implicit_subquery_spec.rb +60 -0
  73. data/spec/extensions/input_transformer_spec.rb +10 -0
  74. data/spec/extensions/insert_returning_select_spec.rb +6 -0
  75. data/spec/extensions/json_serializer_spec.rb +7 -0
  76. data/spec/extensions/lazy_attributes_spec.rb +6 -0
  77. data/spec/extensions/many_through_many_spec.rb +44 -0
  78. data/spec/extensions/nested_attributes_spec.rb +5 -0
  79. data/spec/extensions/pg_array_associations_spec.rb +46 -0
  80. data/spec/extensions/pg_typecast_on_load_spec.rb +5 -0
  81. data/spec/extensions/prepared_statements_safe_spec.rb +5 -0
  82. data/spec/extensions/serialization_spec.rb +7 -0
  83. data/spec/extensions/single_table_inheritance_spec.rb +19 -2
  84. data/spec/extensions/subclasses_spec.rb +13 -0
  85. data/spec/extensions/to_dot_spec.rb +1 -1
  86. data/spec/extensions/touch_spec.rb +6 -0
  87. data/spec/extensions/tree_spec.rb +6 -0
  88. data/spec/extensions/typecast_on_load_spec.rb +6 -0
  89. data/spec/extensions/update_refresh_spec.rb +7 -1
  90. data/spec/extensions/validation_class_methods_spec.rb +13 -0
  91. data/spec/model/association_reflection_spec.rb +177 -0
  92. data/spec/model/associations_spec.rb +16 -0
  93. data/spec/model/dataset_methods_spec.rb +59 -0
  94. data/spec/model/model_spec.rb +59 -0
  95. metadata +8 -2
@@ -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