sequel 4.44.0 → 4.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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