sequel 4.44.0 → 4.45.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +110 -0
  3. data/README.rdoc +8 -9
  4. data/doc/active_record.rdoc +2 -3
  5. data/doc/model_plugins.rdoc +1 -1
  6. data/doc/opening_databases.rdoc +0 -46
  7. data/doc/release_notes/4.45.0.txt +370 -0
  8. data/lib/sequel/adapters/cubrid.rb +2 -0
  9. data/lib/sequel/adapters/do.rb +2 -0
  10. data/lib/sequel/adapters/jdbc/as400.rb +2 -0
  11. data/lib/sequel/adapters/jdbc/cubrid.rb +2 -0
  12. data/lib/sequel/adapters/jdbc/firebirdsql.rb +2 -0
  13. data/lib/sequel/adapters/jdbc/informix-sqli.rb +2 -0
  14. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +2 -0
  15. data/lib/sequel/adapters/jdbc/mysql.rb +1 -0
  16. data/lib/sequel/adapters/jdbc/postgresql.rb +5 -0
  17. data/lib/sequel/adapters/mysql.rb +1 -0
  18. data/lib/sequel/adapters/mysql2.rb +1 -0
  19. data/lib/sequel/adapters/odbc/oracle.rb +11 -0
  20. data/lib/sequel/adapters/odbc/progress.rb +2 -0
  21. data/lib/sequel/adapters/postgres.rb +0 -2
  22. data/lib/sequel/adapters/shared/cubrid.rb +2 -0
  23. data/lib/sequel/adapters/shared/firebird.rb +2 -0
  24. data/lib/sequel/adapters/shared/informix.rb +2 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +47 -7
  26. data/lib/sequel/adapters/shared/mysql.rb +16 -1
  27. data/lib/sequel/adapters/shared/postgres.rb +9 -1
  28. data/lib/sequel/adapters/shared/progress.rb +2 -0
  29. data/lib/sequel/adapters/shared/sqlanywhere.rb +1 -1
  30. data/lib/sequel/adapters/swift.rb +2 -0
  31. data/lib/sequel/ast_transformer.rb +13 -6
  32. data/lib/sequel/core.rb +13 -16
  33. data/lib/sequel/database/connecting.rb +25 -10
  34. data/lib/sequel/database/dataset.rb +6 -1
  35. data/lib/sequel/database/dataset_defaults.rb +9 -2
  36. data/lib/sequel/database/misc.rb +10 -3
  37. data/lib/sequel/database/schema_methods.rb +4 -0
  38. data/lib/sequel/dataset/mutation.rb +8 -20
  39. data/lib/sequel/dataset/prepared_statements.rb +2 -0
  40. data/lib/sequel/dataset/query.rb +32 -7
  41. data/lib/sequel/dataset/sql.rb +13 -3
  42. data/lib/sequel/deprecated.rb +9 -1
  43. data/lib/sequel/exceptions.rb +37 -8
  44. data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +117 -0
  45. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  46. data/lib/sequel/extensions/identifier_mangling.rb +3 -2
  47. data/lib/sequel/extensions/pg_hstore.rb +1 -5
  48. data/lib/sequel/extensions/schema_dumper.rb +3 -1
  49. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +2 -2
  50. data/lib/sequel/extensions/string_agg.rb +1 -0
  51. data/lib/sequel/model.rb +23 -10
  52. data/lib/sequel/model/associations.rb +17 -5
  53. data/lib/sequel/model/base.rb +115 -62
  54. data/lib/sequel/model/dataset_module.rb +10 -3
  55. data/lib/sequel/model/exceptions.rb +7 -5
  56. data/lib/sequel/plugins/association_pks.rb +13 -1
  57. data/lib/sequel/plugins/association_proxies.rb +8 -1
  58. data/lib/sequel/plugins/before_after_save.rb +1 -0
  59. data/lib/sequel/plugins/class_table_inheritance.rb +7 -3
  60. data/lib/sequel/plugins/columns_updated.rb +42 -0
  61. data/lib/sequel/plugins/composition.rb +10 -5
  62. data/lib/sequel/plugins/error_splitter.rb +1 -1
  63. data/lib/sequel/plugins/hook_class_methods.rb +39 -5
  64. data/lib/sequel/plugins/instance_hooks.rb +58 -5
  65. data/lib/sequel/plugins/lazy_attributes.rb +10 -5
  66. data/lib/sequel/plugins/nested_attributes.rb +10 -5
  67. data/lib/sequel/plugins/prepared_statements.rb +7 -0
  68. data/lib/sequel/plugins/prepared_statements_associations.rb +2 -0
  69. data/lib/sequel/plugins/prepared_statements_with_pk.rb +2 -0
  70. data/lib/sequel/plugins/schema.rb +2 -0
  71. data/lib/sequel/plugins/scissors.rb +2 -0
  72. data/lib/sequel/plugins/serialization.rb +10 -5
  73. data/lib/sequel/plugins/split_values.rb +5 -1
  74. data/lib/sequel/plugins/static_cache.rb +2 -2
  75. data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
  76. data/lib/sequel/plugins/validation_contexts.rb +49 -0
  77. data/lib/sequel/plugins/validation_helpers.rb +1 -0
  78. data/lib/sequel/sql.rb +1 -1
  79. data/lib/sequel/version.rb +1 -1
  80. data/spec/adapters/mssql_spec.rb +31 -0
  81. data/spec/adapters/mysql_spec.rb +20 -2
  82. data/spec/adapters/postgres_spec.rb +43 -12
  83. data/spec/adapters/spec_helper.rb +5 -8
  84. data/spec/core/database_spec.rb +47 -12
  85. data/spec/core/dataset_mutation_spec.rb +22 -22
  86. data/spec/core/dataset_spec.rb +88 -20
  87. data/spec/core/deprecated_spec.rb +1 -1
  88. data/spec/core/expression_filters_spec.rb +1 -1
  89. data/spec/core/mock_adapter_spec.rb +0 -3
  90. data/spec/core/placeholder_literalizer_spec.rb +1 -1
  91. data/spec/core/schema_spec.rb +8 -1
  92. data/spec/core/spec_helper.rb +6 -1
  93. data/spec/core_extensions_spec.rb +4 -0
  94. data/spec/deprecation_helper.rb +17 -0
  95. data/spec/extensions/_deprecated_identifier_mangling_spec.rb +314 -0
  96. data/spec/extensions/association_pks_spec.rb +61 -13
  97. data/spec/extensions/association_proxies_spec.rb +3 -3
  98. data/spec/extensions/class_table_inheritance_spec.rb +39 -0
  99. data/spec/extensions/columns_updated_spec.rb +35 -0
  100. data/spec/extensions/composition_spec.rb +6 -1
  101. data/spec/extensions/hook_class_methods_spec.rb +114 -26
  102. data/spec/extensions/identifier_mangling_spec.rb +107 -73
  103. data/spec/extensions/instance_hooks_spec.rb +78 -14
  104. data/spec/extensions/lazy_attributes_spec.rb +8 -2
  105. data/spec/extensions/many_through_many_spec.rb +2 -2
  106. data/spec/extensions/mssql_optimistic_locking_spec.rb +1 -1
  107. data/spec/extensions/nested_attributes_spec.rb +8 -2
  108. data/spec/extensions/pg_array_spec.rb +18 -4
  109. data/spec/extensions/prepared_statements_associations_spec.rb +48 -39
  110. data/spec/extensions/prepared_statements_with_pk_spec.rb +13 -11
  111. data/spec/extensions/query_spec.rb +1 -1
  112. data/spec/extensions/schema_dumper_spec.rb +34 -6
  113. data/spec/extensions/schema_spec.rb +13 -7
  114. data/spec/extensions/scissors_spec.rb +3 -1
  115. data/spec/extensions/sequel_3_dataset_methods_spec.rb +4 -4
  116. data/spec/extensions/serialization_spec.rb +7 -1
  117. data/spec/extensions/set_overrides_spec.rb +2 -2
  118. data/spec/extensions/shared_caching_spec.rb +19 -15
  119. data/spec/extensions/spec_helper.rb +7 -3
  120. data/spec/extensions/split_values_spec.rb +45 -10
  121. data/spec/extensions/string_agg_spec.rb +2 -2
  122. data/spec/extensions/subset_conditions_spec.rb +3 -3
  123. data/spec/extensions/tactical_eager_loading_spec.rb +1 -1
  124. data/spec/extensions/validation_contexts_spec.rb +31 -0
  125. data/spec/guards_helper.rb +2 -0
  126. data/spec/integration/associations_test.rb +22 -20
  127. data/spec/integration/dataset_test.rb +25 -2
  128. data/spec/integration/model_test.rb +1 -1
  129. data/spec/integration/plugin_test.rb +11 -16
  130. data/spec/integration/prepared_statement_test.rb +40 -32
  131. data/spec/integration/spec_helper.rb +5 -8
  132. data/spec/model/association_reflection_spec.rb +4 -0
  133. data/spec/model/associations_spec.rb +37 -10
  134. data/spec/model/base_spec.rb +6 -0
  135. data/spec/model/hooks_spec.rb +56 -35
  136. data/spec/model/model_spec.rb +21 -5
  137. data/spec/model/record_spec.rb +14 -11
  138. data/spec/model/spec_helper.rb +7 -1
  139. data/spec/sequel_warning.rb +11 -0
  140. metadata +13 -3
@@ -11,9 +11,13 @@ unless Object.const_defined?('Sequel') && Sequel.const_defined?('Model')
11
11
  Sequel::Deprecation.backtrace_filter = true
12
12
  end
13
13
 
14
+ # SEQUEL5: Remove
15
+ output = Sequel::Deprecation.output
16
+ Sequel::Deprecation.output = nil
14
17
  Sequel.quote_identifiers = false
15
18
  Sequel.identifier_input_method = nil
16
19
  Sequel.identifier_output_method = nil
20
+ Sequel::Deprecation.output = output
17
21
 
18
22
  Regexp.send(:include, Sequel::SQL::StringMethods)
19
23
  String.send(:include, Sequel::SQL::StringMethods)
@@ -0,0 +1,17 @@
1
+ Sequel::Deprecation.backtrace_filter = lambda{|line, lineno| lineno < 4 || line =~ /_spec\.rb/}
2
+
3
+ class Minitest::HooksSpec
4
+ def self.deprecated(*a, &block)
5
+ it(*a) do
6
+ deprecated{instance_exec(&block)}
7
+ end
8
+ end
9
+
10
+ def deprecated
11
+ output = Sequel::Deprecation.output
12
+ Sequel::Deprecation.output = nil
13
+ yield
14
+ ensure
15
+ Sequel::Deprecation.output = output
16
+ end
17
+ end
@@ -0,0 +1,314 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "identifier_mangling extension" do
4
+ after do
5
+ deprecated do
6
+ Sequel.quote_identifiers = false
7
+ Sequel.identifier_input_method = nil
8
+ Sequel.identifier_output_method = nil
9
+ end
10
+ end
11
+
12
+ deprecated "should respect the :quote_identifiers option" do
13
+ db = Sequel::Database.new(:quote_identifiers=>false, :identifier_mangling=>true)
14
+ db.quote_identifiers?.must_equal false
15
+ db = Sequel::Database.new(:quote_identifiers=>true, :identifier_mangling=>true)
16
+ db.quote_identifiers?.must_equal true
17
+ end
18
+
19
+ deprecated "should respect the :quote_identifiers setting" do
20
+ db = Sequel::Database.new(:identifier_mangling=>true)
21
+ db.quote_identifiers?.must_equal false
22
+ db.quote_identifiers = true
23
+ db.quote_identifiers?.must_equal true
24
+ end
25
+
26
+ deprecated "should upcase on input and downcase on output by default" do
27
+ db = Sequel::Database.new(:identifier_mangling=>true)
28
+ db.send(:identifier_input_method_default).must_equal :upcase
29
+ db.send(:identifier_output_method_default).must_equal :downcase
30
+ end
31
+
32
+ deprecated "should respect the :identifier_input_method option" do
33
+ Sequel.identifier_input_method = nil
34
+ Sequel::Database.identifier_input_method.must_equal false
35
+ db = Sequel::Database.new(:identifier_input_method=>nil, :identifier_mangling=>true)
36
+ db.identifier_input_method.must_be_nil
37
+ db.identifier_input_method = :downcase
38
+ db.identifier_input_method.must_equal :downcase
39
+ db = Sequel::Database.new(:identifier_input_method=>:upcase, :identifier_mangling=>true)
40
+ db.identifier_input_method.must_equal :upcase
41
+ db.identifier_input_method = nil
42
+ db.identifier_input_method.must_be_nil
43
+ Sequel.identifier_input_method = :downcase
44
+ Sequel::Database.identifier_input_method.must_equal :downcase
45
+ db = Sequel::Database.new(:identifier_input_method=>nil, :identifier_mangling=>true)
46
+ db.identifier_input_method.must_be_nil
47
+ db.identifier_input_method = :upcase
48
+ db.identifier_input_method.must_equal :upcase
49
+ db = Sequel::Database.new(:identifier_input_method=>:upcase, :identifier_mangling=>true)
50
+ db.identifier_input_method.must_equal :upcase
51
+ db.identifier_input_method = nil
52
+ db.identifier_input_method.must_be_nil
53
+ end
54
+
55
+ deprecated "should respect the :identifier_output_method option" do
56
+ Sequel.identifier_output_method = nil
57
+ Sequel::Database.identifier_output_method.must_equal false
58
+ db = Sequel::Database.new(:identifier_output_method=>nil, :identifier_mangling=>true)
59
+ db.identifier_output_method.must_be_nil
60
+ db.identifier_output_method = :downcase
61
+ db.identifier_output_method.must_equal :downcase
62
+ db = Sequel::Database.new(:identifier_output_method=>:upcase, :identifier_mangling=>true)
63
+ db.identifier_output_method.must_equal :upcase
64
+ db.identifier_output_method = nil
65
+ db.identifier_output_method.must_be_nil
66
+ Sequel.identifier_output_method = :downcase
67
+ Sequel::Database.identifier_output_method.must_equal :downcase
68
+ db = Sequel::Database.new(:identifier_output_method=>nil, :identifier_mangling=>true)
69
+ db.identifier_output_method.must_be_nil
70
+ db.identifier_output_method = :upcase
71
+ db.identifier_output_method.must_equal :upcase
72
+ db = Sequel::Database.new(:identifier_output_method=>:upcase, :identifier_mangling=>true)
73
+ db.identifier_output_method.must_equal :upcase
74
+ db.identifier_output_method = nil
75
+ db.identifier_output_method.must_be_nil
76
+ end
77
+
78
+ deprecated "should use the default Sequel.quote_identifiers value" do
79
+ Sequel.quote_identifiers = true
80
+ Sequel::Database.new(:identifier_mangling=>true).quote_identifiers?.must_equal true
81
+ Sequel.quote_identifiers = false
82
+ Sequel::Database.new(:identifier_mangling=>true).quote_identifiers?.must_equal false
83
+ Sequel::Database.quote_identifiers = true
84
+ Sequel::Database.new(:identifier_mangling=>true).quote_identifiers?.must_equal true
85
+ Sequel::Database.quote_identifiers = false
86
+ Sequel::Database.new(:identifier_mangling=>true).quote_identifiers?.must_equal false
87
+ end
88
+
89
+ deprecated "should use the default Sequel.identifier_input_method value" do
90
+ Sequel.identifier_input_method = :downcase
91
+ Sequel::Database.new(:identifier_mangling=>true).identifier_input_method.must_equal :downcase
92
+ Sequel.identifier_input_method = :upcase
93
+ Sequel::Database.new(:identifier_mangling=>true).identifier_input_method.must_equal :upcase
94
+ Sequel::Database.identifier_input_method = :downcase
95
+ Sequel::Database.new(:identifier_mangling=>true).identifier_input_method.must_equal :downcase
96
+ Sequel::Database.identifier_input_method = :upcase
97
+ Sequel::Database.new(:identifier_mangling=>true).identifier_input_method.must_equal :upcase
98
+ end
99
+
100
+ deprecated "should use the default Sequel.identifier_output_method value" do
101
+ Sequel.identifier_output_method = :downcase
102
+ Sequel::Database.new(:identifier_mangling=>true).identifier_output_method.must_equal :downcase
103
+ Sequel.identifier_output_method = :upcase
104
+ Sequel::Database.new(:identifier_mangling=>true).identifier_output_method.must_equal :upcase
105
+ Sequel::Database.identifier_output_method = :downcase
106
+ Sequel::Database.new(:identifier_mangling=>true).identifier_output_method.must_equal :downcase
107
+ Sequel::Database.identifier_output_method = :upcase
108
+ Sequel::Database.new(:identifier_mangling=>true).identifier_output_method.must_equal :upcase
109
+ end
110
+
111
+ deprecated "should respect the quote_indentifiers_default method if Sequel.quote_identifiers = nil" do
112
+ Sequel.quote_identifiers = nil
113
+ Sequel::Database.new(:identifier_mangling=>true).quote_identifiers?.must_equal true
114
+ x = Class.new(Sequel::Database){def quote_identifiers_default; false end}
115
+ x.new(:identifier_mangling=>true).quote_identifiers?.must_equal false
116
+ y = Class.new(Sequel::Database){def quote_identifiers_default; true end}
117
+ y.new(:identifier_mangling=>true).quote_identifiers?.must_equal true
118
+ end
119
+
120
+ deprecated "should respect the identifier_input_method_default method if Sequel.identifier_input_method is not called" do
121
+ class Sequel::Database
122
+ @identifier_input_method = nil
123
+ end
124
+ x = Class.new(Sequel::Database){def identifier_input_method_default; :downcase end}
125
+ x.new(:identifier_mangling=>true).identifier_input_method.must_equal :downcase
126
+ y = Class.new(Sequel::Database){def identifier_input_method_default; :camelize end}
127
+ y.new(:identifier_mangling=>true).identifier_input_method.must_equal :camelize
128
+ end
129
+
130
+ deprecated "should respect the identifier_output_method_default method if Sequel.identifier_output_method is not called" do
131
+ class Sequel::Database
132
+ @identifier_output_method = nil
133
+ end
134
+ x = Class.new(Sequel::Database){def identifier_output_method_default; :upcase end}
135
+ x.new(:identifier_mangling=>true).identifier_output_method.must_equal :upcase
136
+ y = Class.new(Sequel::Database){def identifier_output_method_default; :underscore end}
137
+ y.new(:identifier_mangling=>true).identifier_output_method.must_equal :underscore
138
+ end
139
+ end
140
+
141
+ describe "Database#input_identifier_meth" do
142
+ deprecated "should be the input_identifer method of a default dataset for this database" do
143
+ db = Sequel::Database.new(:identifier_mangling=>true)
144
+ db.send(:input_identifier_meth).call(:a).must_equal 'a'
145
+ db.identifier_input_method = :upcase
146
+ db.send(:input_identifier_meth).call(:a).must_equal 'A'
147
+ end
148
+ end
149
+
150
+ describe "Database#output_identifier_meth" do
151
+ deprecated "should be the output_identifer method of a default dataset for this database" do
152
+ db = Sequel::Database.new(:identifier_mangling=>true)
153
+ db.send(:output_identifier_meth).call('A').must_equal :A
154
+ db.identifier_output_method = :downcase
155
+ db.send(:output_identifier_meth).call('A').must_equal :a
156
+ end
157
+ end
158
+
159
+ describe "Database#metadata_dataset" do
160
+ deprecated "should be a dataset with the default settings for identifier_mangling" do
161
+ ds = Sequel::Database.new(:identifier_mangling=>true).send(:metadata_dataset)
162
+ ds.literal(:a).must_equal 'A'
163
+ ds.send(:output_identifier, 'A').must_equal :a
164
+ end
165
+ end
166
+
167
+ describe "Dataset" do
168
+ before do
169
+ @dataset = Sequel.mock(:identifier_mangling=>true).dataset
170
+ end
171
+
172
+ deprecated "should get quote_identifiers default from database" do
173
+ db = Sequel::Database.new(:quote_identifiers=>true, :identifier_mangling=>true)
174
+ db[:a].quote_identifiers?.must_equal true
175
+ db = Sequel::Database.new(:quote_identifiers=>false, :identifier_mangling=>true)
176
+ db[:a].quote_identifiers?.must_equal false
177
+ end
178
+
179
+ deprecated "should get identifier_input_method default from database" do
180
+ db = Sequel::Database.new(:identifier_input_method=>:upcase, :identifier_mangling=>true)
181
+ db[:a].identifier_input_method.must_equal :upcase
182
+ db = Sequel::Database.new(:identifier_input_method=>:downcase, :identifier_mangling=>true)
183
+ db[:a].identifier_input_method.must_equal :downcase
184
+ end
185
+
186
+ deprecated "should get identifier_output_method default from database" do
187
+ db = Sequel::Database.new(:identifier_output_method=>:upcase, :identifier_mangling=>true)
188
+ db[:a].identifier_output_method.must_equal :upcase
189
+ db = Sequel::Database.new(:identifier_output_method=>:downcase, :identifier_mangling=>true)
190
+ db[:a].identifier_output_method.must_equal :downcase
191
+ end
192
+
193
+ # SEQUEL5: Remove
194
+ unless Sequel.mock(:identifier_mangling=>true).dataset.frozen?
195
+ deprecated "should have quote_identifiers= method which changes literalization of identifiers" do
196
+ @dataset.quote_identifiers = true
197
+ @dataset.literal(:a).must_equal '"a"'
198
+ @dataset.quote_identifiers = false
199
+ @dataset.literal(:a).must_equal 'a'
200
+ end
201
+
202
+ deprecated "should have identifier_input_method= method which changes literalization of identifiers" do
203
+ @dataset.identifier_input_method = :upcase
204
+ @dataset.literal(:a).must_equal 'A'
205
+ @dataset.identifier_input_method = :downcase
206
+ @dataset.literal(:A).must_equal 'a'
207
+ @dataset.identifier_input_method = :reverse
208
+ @dataset.literal(:at_b).must_equal 'b_ta'
209
+ end
210
+
211
+ deprecated "should have identifier_output_method= method which changes identifiers returned from the database" do
212
+ @dataset.send(:output_identifier, "at_b_C").must_equal :at_b_C
213
+ @dataset.identifier_output_method = :upcase
214
+ @dataset.send(:output_identifier, "at_b_C").must_equal :AT_B_C
215
+ @dataset.identifier_output_method = :downcase
216
+ @dataset.send(:output_identifier, "at_b_C").must_equal :at_b_c
217
+ @dataset.identifier_output_method = :reverse
218
+ @dataset.send(:output_identifier, "at_b_C").must_equal :C_b_ta
219
+ end
220
+ end
221
+
222
+ deprecated "should have with_quote_identifiers method which returns cloned dataset with changed literalization of identifiers" do
223
+ @dataset.with_quote_identifiers(true).literal(:a).must_equal '"a"'
224
+ @dataset.with_quote_identifiers(false).literal(:a).must_equal 'a'
225
+ ds = @dataset.freeze.with_quote_identifiers(false)
226
+ ds.literal(:a).must_equal 'a'
227
+ ds.frozen?.must_equal true
228
+ end
229
+
230
+ deprecated "should have with_identifier_input_method method which returns cloned dataset with changed literalization of identifiers" do
231
+ @dataset.with_identifier_input_method(:upcase).literal(:a).must_equal 'A'
232
+ @dataset.with_identifier_input_method(:downcase).literal(:A).must_equal 'a'
233
+ @dataset.with_identifier_input_method(:reverse).literal(:at_b).must_equal 'b_ta'
234
+ ds = @dataset.freeze.with_identifier_input_method(:reverse)
235
+ ds.frozen?.must_equal true
236
+ ds.literal(:at_b).must_equal 'b_ta'
237
+ end
238
+
239
+ deprecated "should have with_identifier_output_method method which returns cloned dataset with changed identifiers returned from the database" do
240
+ @dataset.send(:output_identifier, "at_b_C").must_equal :at_b_C
241
+ @dataset.with_identifier_output_method(:upcase).send(:output_identifier, "at_b_C").must_equal :AT_B_C
242
+ @dataset.with_identifier_output_method(:downcase).send(:output_identifier, "at_b_C").must_equal :at_b_c
243
+ @dataset.with_identifier_output_method(:reverse).send(:output_identifier, "at_b_C").must_equal :C_b_ta
244
+ ds = @dataset.freeze.with_identifier_output_method(:reverse)
245
+ ds.send(:output_identifier, "at_b_C").must_equal :C_b_ta
246
+ ds.frozen?.must_equal true
247
+ end
248
+
249
+ deprecated "should have output_identifier handle empty identifiers" do
250
+ @dataset.send(:output_identifier, "").must_equal :untitled
251
+ @dataset.with_identifier_output_method(:upcase).send(:output_identifier, "").must_equal :UNTITLED
252
+ @dataset.with_identifier_output_method(:downcase).send(:output_identifier, "").must_equal :untitled
253
+ @dataset.with_identifier_output_method(:reverse).send(:output_identifier, "").must_equal :deltitnu
254
+ end
255
+ end
256
+
257
+ describe "Frozen Datasets" do
258
+ before do
259
+ @ds = Sequel.mock(:identifier_mangling=>true)[:test].freeze
260
+ end
261
+
262
+ deprecated "should raise an error when calling mutation methods" do
263
+ proc{@ds.identifier_input_method = :a}.must_raise RuntimeError
264
+ proc{@ds.identifier_output_method = :a}.must_raise RuntimeError
265
+ proc{@ds.quote_identifiers = false}.must_raise RuntimeError
266
+ end
267
+ end
268
+
269
+ describe "identifier_mangling extension" do
270
+ deprecated "should be able to load dialects based on the database name" do
271
+ begin
272
+ qi = class Sequel::Database; @quote_identifiers; end
273
+ ii = class Sequel::Database; @identifier_input_method; end
274
+ io = class Sequel::Database; @identifier_output_method; end
275
+ Sequel.quote_identifiers = nil
276
+ class Sequel::Database; @identifier_input_method=nil; end
277
+ class Sequel::Database; @identifier_output_method=nil; end
278
+ Sequel.mock(:host=>'access').select(Date.new(2011, 12, 13)).sql.must_equal 'SELECT #2011-12-13#'
279
+ Sequel.mock(:host=>'db2').select(1).sql.must_equal 'SELECT 1 FROM "SYSIBM"."SYSDUMMY1"'
280
+ Sequel.mock(:host=>'mssql')[:a].full_text_search(:b, 'c').sql.must_equal "SELECT * FROM [A] WHERE (CONTAINS ([B], 'c'))"
281
+ Sequel.mock(:host=>'mysql')[:a].full_text_search(:b, 'c').sql.must_equal "SELECT * FROM `a` WHERE (MATCH (`b`) AGAINST ('c'))"
282
+ Sequel.mock(:host=>'oracle')[:a].limit(1).sql.must_equal 'SELECT * FROM (SELECT * FROM "A") "T1" WHERE (ROWNUM <= 1)'
283
+ Sequel.mock(:host=>'postgres')[:a].full_text_search(:b, 'c').sql.must_equal "SELECT * FROM \"a\" WHERE (to_tsvector(CAST('simple' AS regconfig), (COALESCE(\"b\", ''))) @@ to_tsquery(CAST('simple' AS regconfig), 'c'))"
284
+ Sequel.mock(:host=>'sqlanywhere').from(:a).offset(1).sql.must_equal 'SELECT TOP 2147483647 START AT (1 + 1) * FROM "A"'
285
+ Sequel.mock(:host=>'sqlite')[:a___b].sql.must_equal "SELECT * FROM `a` AS 'b'"
286
+ ensure
287
+ Sequel.quote_identifiers = qi
288
+ Sequel::Database.send(:instance_variable_set, :@identifier_input_method, ii)
289
+ Sequel::Database.send(:instance_variable_set, :@identifier_output_method, io)
290
+ end
291
+ end
292
+ end
293
+
294
+ describe Sequel::Model, ".[] optimization" do
295
+ before do
296
+ @db = Sequel.mock(:identifier_mangling=>true, :quote_identifiers=>true)
297
+ def @db.schema(*) [[:id, {:primary_key=>true}]] end
298
+ def @db.supports_schema_parsing?() true end
299
+ @c = Class.new(Sequel::Model(@db))
300
+ @ds = @db.dataset.with_quote_identifiers(true)
301
+ end
302
+
303
+ deprecated "should have simple_pk and simple_table respect dataset's identifier input methods" do
304
+ ds = @db.from(:ab).with_identifier_input_method(:reverse)
305
+ @c.set_dataset ds
306
+ @c.simple_table.must_equal '"ba"'
307
+ @c.set_primary_key :cd
308
+ @c.simple_pk.must_equal '"dc"'
309
+
310
+ @c.set_dataset ds.from(:ef__gh)
311
+ @c.simple_table.must_equal '"fe"."hg"'
312
+ end
313
+ end
314
+
@@ -57,8 +57,8 @@ describe "Sequel::Plugins::AssociationPks" do
57
57
  @Artist.plugin :association_pks
58
58
  @Album.plugin :association_pks
59
59
  @Vocalist.plugin :association_pks
60
- @Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id
61
- @Album.many_to_many :tags, :class=>@Tag, :join_table=>:albums_tags, :left_key=>:album_id
60
+ @Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id, :delay_pks=>false
61
+ @Album.many_to_many :tags, :class=>@Tag, :join_table=>:albums_tags, :left_key=>:album_id, :delay_pks=>false
62
62
  @db.sqls
63
63
  end
64
64
 
@@ -73,6 +73,13 @@ describe "Sequel::Plugins::AssociationPks" do
73
73
  @Album.load(:id=>3).tag_pks.must_equal []
74
74
  end
75
75
 
76
+ deprecated "should set associated pks correctly for a one_to_many association when :delay_pks is not set" do
77
+ @Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id
78
+ @Artist.load(:id=>1).album_pks = [1, 2]
79
+ @db.sqls.must_equal ["UPDATE albums SET artist_id = 1 WHERE (id IN (1, 2))",
80
+ "UPDATE albums SET artist_id = NULL WHERE ((albums.artist_id = 1) AND (id NOT IN (1, 2)))"]
81
+ end
82
+
76
83
  it "should set associated pks correctly for a one_to_many association" do
77
84
  @Artist.load(:id=>1).album_pks = [1, 2]
78
85
  @db.sqls.must_equal ["UPDATE albums SET artist_id = 1 WHERE (id IN (1, 2))",
@@ -111,14 +118,14 @@ describe "Sequel::Plugins::AssociationPks" do
111
118
  end
112
119
 
113
120
  it "should set associated right-side cpks correctly for a one_to_many association" do
114
- @Album.one_to_many :vocalists, :class=>@Vocalist, :key=>:album_id
121
+ @Album.one_to_many :vocalists, :class=>@Vocalist, :key=>:album_id, :delay_pks=>false
115
122
  @Album.load(:id=>1).vocalist_pks = [["F1", "L1"], ["F2", "L2"]]
116
123
  @db.sqls.must_equal ["UPDATE vocalists SET album_id = 1 WHERE ((first, last) IN (('F1', 'L1'), ('F2', 'L2')))",
117
124
  "UPDATE vocalists SET album_id = NULL WHERE ((vocalists.album_id = 1) AND ((first, last) NOT IN (('F1', 'L1'), ('F2', 'L2'))))"]
118
125
  end
119
126
 
120
127
  it "should set associated right-side cpks correctly for a many_to_many association" do
121
- @Album.many_to_many :vocalists, :class=>@Vocalist, :join_table=>:albums_vocalists, :left_key=>:album_id, :right_key=>[:first, :last]
128
+ @Album.many_to_many :vocalists, :class=>@Vocalist, :join_table=>:albums_vocalists, :left_key=>:album_id, :right_key=>[:first, :last], :delay_pks=>false
122
129
  @Album.load(:id=>2).vocalist_pks = [["F1", "L1"], ["F2", "L2"]]
123
130
  sqls = @db.sqls
124
131
  sqls[0].must_equal "DELETE FROM albums_vocalists WHERE ((album_id = 2) AND ((first, last) NOT IN (('F1', 'L1'), ('F2', 'L2'))))"
@@ -142,7 +149,7 @@ describe "Sequel::Plugins::AssociationPks" do
142
149
  end
143
150
 
144
151
  it "should set associated pks correctly for left-side cpks for a one_to_many association" do
145
- @Vocalist.one_to_many :instruments, :class=>@Instrument, :key=>[:first, :last]
152
+ @Vocalist.one_to_many :instruments, :class=>@Instrument, :key=>[:first, :last], :delay_pks=>false
146
153
  @Vocalist.load(:first=>'F1', :last=>'L1').instrument_pks = [1, 2]
147
154
  sqls = @db.sqls
148
155
  sqls[0].must_match(/UPDATE instruments SET (first = 'F1', last = 'L1'|last = 'L1', first = 'F1') WHERE \(id IN \(1, 2\)\)/)
@@ -151,7 +158,7 @@ describe "Sequel::Plugins::AssociationPks" do
151
158
  end
152
159
 
153
160
  it "should set associated pks correctly for left-side cpks for a many_to_many association" do
154
- @Vocalist.many_to_many :instruments, :class=>@Instrument, :join_table=>:vocalists_instruments, :left_key=>[:first, :last]
161
+ @Vocalist.many_to_many :instruments, :class=>@Instrument, :join_table=>:vocalists_instruments, :left_key=>[:first, :last], :delay_pks=>false
155
162
  @Vocalist.load(:first=>'F2', :last=>'L2').instrument_pks = [1, 2]
156
163
  sqls = @db.sqls
157
164
  sqls[0].must_equal "DELETE FROM vocalists_instruments WHERE ((first = 'F2') AND (last = 'L2') AND (instrument_id NOT IN (1, 2)))"
@@ -175,7 +182,7 @@ describe "Sequel::Plugins::AssociationPks" do
175
182
  end
176
183
 
177
184
  it "should set associated right-side cpks correctly for left-side cpks for a one_to_many association" do
178
- @Vocalist.one_to_many :hits, :class=>@Hit, :key=>[:first, :last], :order=>:week
185
+ @Vocalist.one_to_many :hits, :class=>@Hit, :key=>[:first, :last], :order=>:week, :delay_pks=>false
179
186
  @Vocalist.load(:first=>'F1', :last=>'L1').hit_pks = [[1997, 1], [1997, 2]]
180
187
  sqls = @db.sqls
181
188
  sqls[0].must_match(/UPDATE hits SET (first = 'F1', last = 'L1'|last = 'L1', first = 'F1') WHERE \(\(year, week\) IN \(\(1997, 1\), \(1997, 2\)\)\)/)
@@ -184,7 +191,7 @@ describe "Sequel::Plugins::AssociationPks" do
184
191
  end
185
192
 
186
193
  it "should set associated right-side cpks correctly for left-side cpks for a many_to_many association" do
187
- @Vocalist.many_to_many :hits, :class=>@Hit, :join_table=>:vocalists_hits, :left_key=>[:first, :last], :right_key=>[:year, :week]
194
+ @Vocalist.many_to_many :hits, :class=>@Hit, :join_table=>:vocalists_hits, :left_key=>[:first, :last], :right_key=>[:year, :week], :delay_pks=>false
188
195
  @Vocalist.load(:first=>'F2', :last=>'L2').hit_pks = [[1997, 1], [1997, 2]]
189
196
  sqls = @db.sqls
190
197
  sqls[0].must_equal "DELETE FROM vocalists_hits WHERE ((first = 'F2') AND (last = 'L2') AND ((year, week) NOT IN ((1997, 1), (1997, 2))))"
@@ -253,7 +260,7 @@ describe "Sequel::Plugins::AssociationPks" do
253
260
  it "should automatically convert keys to numbers for appropriate integer primary key for composite key associations" do
254
261
  @Hit.db_schema[:year][:type] = :integer
255
262
  @Hit.db_schema[:week][:type] = :integer
256
- @Vocalist.many_to_many :hits, :class=>@Hit, :join_table=>:vocalists_hits, :left_key=>[:first, :last], :right_key=>[:year, :week]
263
+ @Vocalist.many_to_many :hits, :class=>@Hit, :join_table=>:vocalists_hits, :left_key=>[:first, :last], :right_key=>[:year, :week], :delay_pks=>false
257
264
  @Vocalist.load(:first=>'F2', :last=>'L2').hit_pks = [['1997', '1'], ['1997', '2']]
258
265
  sqls = @db.sqls
259
266
  sqls[0].must_equal "DELETE FROM vocalists_hits WHERE ((first = 'F2') AND (last = 'L2') AND ((year, week) NOT IN ((1997, 1), (1997, 2))))"
@@ -264,12 +271,12 @@ describe "Sequel::Plugins::AssociationPks" do
264
271
 
265
272
  @Vocalist.db_schema[:first][:type] = :integer
266
273
  @Vocalist.db_schema[:last][:type] = :integer
267
- @Album.one_to_many :vocalists, :class=>@Vocalist, :key=>:album_id
274
+ @Album.one_to_many :vocalists, :class=>@Vocalist, :key=>:album_id, :delay_pks=>false
268
275
  @Album.load(:id=>1).vocalist_pks = [["11", "11"], ["12", "12"]]
269
276
  @db.sqls.must_equal ["UPDATE vocalists SET album_id = 1 WHERE ((first, last) IN ((11, 11), (12, 12)))",
270
277
  "UPDATE vocalists SET album_id = NULL WHERE ((vocalists.album_id = 1) AND ((first, last) NOT IN ((11, 11), (12, 12))))"]
271
278
 
272
- @Album.many_to_many :vocalists, :class=>@Vocalist, :join_table=>:albums_vocalists, :left_key=>:album_id, :right_key=>[:first, :last]
279
+ @Album.many_to_many :vocalists, :class=>@Vocalist, :join_table=>:albums_vocalists, :left_key=>:album_id, :right_key=>[:first, :last], :delay_pks=>false
273
280
  @Album.load(:id=>2).vocalist_pks = [["11", "11"], ["12", "12"]]
274
281
  sqls = @db.sqls
275
282
  sqls[0].must_equal "DELETE FROM albums_vocalists WHERE ((album_id = 2) AND ((first, last) NOT IN ((11, 11), (12, 12))))"
@@ -281,7 +288,7 @@ describe "Sequel::Plugins::AssociationPks" do
281
288
  sqls.length.must_equal 6
282
289
  end
283
290
 
284
- it "should handle delaying setting of association pks until after saving for new objects, if :delay plugin option is used" do
291
+ deprecated "should handle delaying setting of association pks until after saving for new objects, if :delay_pks=>true association option is used" do
285
292
  @Artist.one_to_many :albums, :clone=>:albums, :delay_pks=>true
286
293
  @Album.many_to_many :tags, :clone=>:tags, :delay_pks=>true
287
294
  @Album.db_schema[:id][:type] = :integer
@@ -316,13 +323,54 @@ describe "Sequel::Plugins::AssociationPks" do
316
323
  "COMMIT",
317
324
  "SELECT * FROM albums WHERE (id = 2) LIMIT 1"
318
325
  ]
326
+
327
+ al = @Album.load(:id=>1)
328
+ al.tag_pks = [2,3]
329
+ @db.sqls.must_equal [
330
+ "DELETE FROM albums_tags WHERE ((album_id = 1) AND (tag_id NOT IN (2, 3)))",
331
+ "SELECT tag_id FROM albums_tags WHERE (album_id = 1)",
332
+ "BEGIN",
333
+ "INSERT INTO albums_tags (album_id, tag_id) VALUES (1, 3)",
334
+ "COMMIT"
335
+ ]
336
+ al.tag_pks.must_equal [1, 2]
319
337
  end
320
338
 
321
- it "should handle delaying setting of association pks until after saving for existing objects, if :delay=>:all plugin option is used" do
339
+ it "should handle delaying setting of association pks until after saving for existing objects, if :delay_pks=>:always association option is used" do
322
340
  @Artist.one_to_many :albums, :clone=>:albums, :delay_pks=>:always
323
341
  @Album.many_to_many :tags, :clone=>:tags, :delay_pks=>:always
324
342
  @Album.db_schema[:id][:type] = :integer
325
343
 
344
+ ar = @Artist.new
345
+ ar.album_pks.must_equal []
346
+ ar.album_pks = ["1","2","3"]
347
+ ar.album_pks.must_equal [1,2,3]
348
+ @db.sqls.must_equal []
349
+
350
+ ar.save
351
+ @db.sqls.must_equal [
352
+ "INSERT INTO artists DEFAULT VALUES",
353
+ "UPDATE albums SET artist_id = 1 WHERE (id IN (1, 2, 3))",
354
+ "UPDATE albums SET artist_id = NULL WHERE ((albums.artist_id = 1) AND (id NOT IN (1, 2, 3)))",
355
+ "SELECT * FROM artists WHERE (id = 1) LIMIT 1",
356
+ ]
357
+
358
+ al = @Album.new
359
+ al.tag_pks.must_equal []
360
+ al.tag_pks = [1,2]
361
+ al.tag_pks.must_equal [1, 2]
362
+ @db.sqls.must_equal []
363
+
364
+ al.save
365
+ @db.sqls.must_equal [
366
+ "INSERT INTO albums DEFAULT VALUES",
367
+ "DELETE FROM albums_tags WHERE ((album_id = 2) AND (tag_id NOT IN (1, 2)))",
368
+ "SELECT tag_id FROM albums_tags WHERE (album_id = 2)",
369
+ "BEGIN",
370
+ "INSERT INTO albums_tags (album_id, tag_id) VALUES (2, 1)",
371
+ "COMMIT",
372
+ "SELECT * FROM albums WHERE (id = 2) LIMIT 1"
373
+ ]
326
374
  ar = @Artist.load(:id=>1)
327
375
  ar.album_pks.must_equal [1,2,3]
328
376
  @db.sqls