sequel 3.21.0 → 3.31.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 (225) hide show
  1. data/CHANGELOG +485 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +37 -19
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +249 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/dataset_filtering.rdoc +8 -0
  8. data/doc/mass_assignment.rdoc +54 -0
  9. data/doc/migration.rdoc +15 -538
  10. data/doc/model_hooks.rdoc +72 -27
  11. data/doc/opening_databases.rdoc +89 -50
  12. data/doc/prepared_statements.rdoc +40 -13
  13. data/doc/reflection.rdoc +8 -2
  14. data/doc/release_notes/3.22.0.txt +39 -0
  15. data/doc/release_notes/3.23.0.txt +172 -0
  16. data/doc/release_notes/3.24.0.txt +420 -0
  17. data/doc/release_notes/3.25.0.txt +88 -0
  18. data/doc/release_notes/3.26.0.txt +88 -0
  19. data/doc/release_notes/3.27.0.txt +82 -0
  20. data/doc/release_notes/3.28.0.txt +304 -0
  21. data/doc/release_notes/3.29.0.txt +459 -0
  22. data/doc/release_notes/3.30.0.txt +135 -0
  23. data/doc/release_notes/3.31.0.txt +146 -0
  24. data/doc/schema_modification.rdoc +547 -0
  25. data/doc/sharding.rdoc +7 -1
  26. data/doc/testing.rdoc +129 -0
  27. data/doc/transactions.rdoc +137 -0
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  30. data/lib/sequel/adapters/ado.rb +40 -18
  31. data/lib/sequel/adapters/amalgalite.rb +17 -9
  32. data/lib/sequel/adapters/db2.rb +175 -86
  33. data/lib/sequel/adapters/dbi.rb +15 -15
  34. data/lib/sequel/adapters/do/mysql.rb +5 -7
  35. data/lib/sequel/adapters/do/postgres.rb +0 -5
  36. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/do.rb +17 -36
  38. data/lib/sequel/adapters/firebird.rb +27 -208
  39. data/lib/sequel/adapters/ibmdb.rb +448 -0
  40. data/lib/sequel/adapters/informix.rb +6 -23
  41. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  42. data/lib/sequel/adapters/jdbc/db2.rb +45 -0
  43. data/lib/sequel/adapters/jdbc/derby.rb +247 -0
  44. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  45. data/lib/sequel/adapters/jdbc/h2.rb +56 -29
  46. data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
  47. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  48. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  49. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  50. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  51. data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  53. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  54. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  55. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  56. data/lib/sequel/adapters/jdbc.rb +231 -78
  57. data/lib/sequel/adapters/mock.rb +335 -0
  58. data/lib/sequel/adapters/mysql.rb +82 -184
  59. data/lib/sequel/adapters/mysql2.rb +26 -25
  60. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  61. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  62. data/lib/sequel/adapters/odbc.rb +28 -9
  63. data/lib/sequel/adapters/openbase.rb +3 -5
  64. data/lib/sequel/adapters/oracle.rb +351 -53
  65. data/lib/sequel/adapters/postgres.rb +194 -33
  66. data/lib/sequel/adapters/shared/access.rb +32 -9
  67. data/lib/sequel/adapters/shared/db2.rb +321 -0
  68. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  69. data/lib/sequel/adapters/shared/informix.rb +53 -0
  70. data/lib/sequel/adapters/shared/mssql.rb +231 -106
  71. data/lib/sequel/adapters/shared/mysql.rb +181 -63
  72. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +231 -41
  74. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  75. data/lib/sequel/adapters/shared/progress.rb +4 -7
  76. data/lib/sequel/adapters/shared/sqlite.rb +201 -57
  77. data/lib/sequel/adapters/sqlite.rb +29 -21
  78. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  79. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  80. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  81. data/lib/sequel/adapters/swift.rb +5 -5
  82. data/lib/sequel/adapters/tinytds.rb +160 -19
  83. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  84. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  85. data/lib/sequel/ast_transformer.rb +190 -0
  86. data/lib/sequel/connection_pool/threaded.rb +3 -2
  87. data/lib/sequel/connection_pool.rb +1 -1
  88. data/lib/sequel/core.rb +46 -5
  89. data/lib/sequel/database/connecting.rb +5 -6
  90. data/lib/sequel/database/dataset.rb +4 -4
  91. data/lib/sequel/database/dataset_defaults.rb +59 -1
  92. data/lib/sequel/database/logging.rb +1 -1
  93. data/lib/sequel/database/misc.rb +104 -19
  94. data/lib/sequel/database/query.rb +153 -58
  95. data/lib/sequel/database/schema_generator.rb +17 -7
  96. data/lib/sequel/database/schema_methods.rb +59 -29
  97. data/lib/sequel/dataset/actions.rb +231 -76
  98. data/lib/sequel/dataset/features.rb +91 -8
  99. data/lib/sequel/dataset/graph.rb +38 -11
  100. data/lib/sequel/dataset/misc.rb +50 -23
  101. data/lib/sequel/dataset/mutation.rb +5 -6
  102. data/lib/sequel/dataset/prepared_statements.rb +48 -27
  103. data/lib/sequel/dataset/query.rb +236 -43
  104. data/lib/sequel/dataset/sql.rb +665 -253
  105. data/lib/sequel/dataset.rb +8 -0
  106. data/lib/sequel/exceptions.rb +4 -0
  107. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  108. data/lib/sequel/extensions/migration.rb +6 -4
  109. data/lib/sequel/extensions/named_timezones.rb +5 -0
  110. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  111. data/lib/sequel/extensions/to_dot.rb +95 -83
  112. data/lib/sequel/model/associations.rb +1020 -337
  113. data/lib/sequel/model/base.rb +414 -132
  114. data/lib/sequel/model/errors.rb +1 -1
  115. data/lib/sequel/model/exceptions.rb +5 -1
  116. data/lib/sequel/model.rb +15 -8
  117. data/lib/sequel/plugins/association_pks.rb +22 -4
  118. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  119. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  120. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  121. data/lib/sequel/plugins/force_encoding.rb +6 -6
  122. data/lib/sequel/plugins/identity_map.rb +114 -7
  123. data/lib/sequel/plugins/many_through_many.rb +65 -7
  124. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  125. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  126. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  127. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  128. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  129. data/lib/sequel/plugins/serialization.rb +88 -44
  130. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  131. data/lib/sequel/plugins/sharding.rb +21 -54
  132. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  133. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  134. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  135. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  136. data/lib/sequel/sql.rb +109 -52
  137. data/lib/sequel/timezones.rb +57 -38
  138. data/lib/sequel/version.rb +1 -1
  139. data/spec/adapters/db2_spec.rb +146 -0
  140. data/spec/adapters/mssql_spec.rb +111 -29
  141. data/spec/adapters/mysql_spec.rb +135 -123
  142. data/spec/adapters/oracle_spec.rb +49 -77
  143. data/spec/adapters/postgres_spec.rb +267 -78
  144. data/spec/adapters/spec_helper.rb +6 -5
  145. data/spec/adapters/sqlite_spec.rb +35 -21
  146. data/spec/core/connection_pool_spec.rb +71 -92
  147. data/spec/core/core_sql_spec.rb +21 -30
  148. data/spec/core/database_spec.rb +788 -512
  149. data/spec/core/dataset_spec.rb +1073 -1053
  150. data/spec/core/expression_filters_spec.rb +159 -42
  151. data/spec/core/mock_adapter_spec.rb +419 -0
  152. data/spec/core/object_graph_spec.rb +86 -114
  153. data/spec/core/schema_generator_spec.rb +3 -3
  154. data/spec/core/schema_spec.rb +298 -38
  155. data/spec/core/spec_helper.rb +6 -48
  156. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  157. data/spec/extensions/association_dependencies_spec.rb +2 -12
  158. data/spec/extensions/association_pks_spec.rb +66 -32
  159. data/spec/extensions/caching_spec.rb +23 -50
  160. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  161. data/spec/extensions/columns_introspection_spec.rb +91 -0
  162. data/spec/extensions/composition_spec.rb +18 -13
  163. data/spec/extensions/dataset_associations_spec.rb +199 -0
  164. data/spec/extensions/defaults_setter_spec.rb +64 -0
  165. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  166. data/spec/extensions/identity_map_spec.rb +114 -22
  167. data/spec/extensions/instance_filters_spec.rb +11 -21
  168. data/spec/extensions/instance_hooks_spec.rb +53 -0
  169. data/spec/extensions/json_serializer_spec.rb +4 -5
  170. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  171. data/spec/extensions/list_spec.rb +17 -39
  172. data/spec/extensions/many_through_many_spec.rb +283 -250
  173. data/spec/extensions/migration_spec.rb +35 -32
  174. data/spec/extensions/named_timezones_spec.rb +23 -3
  175. data/spec/extensions/nested_attributes_spec.rb +97 -88
  176. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  177. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  178. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  179. data/spec/extensions/prepared_statements_spec.rb +53 -0
  180. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  181. data/spec/extensions/pretty_table_spec.rb +1 -6
  182. data/spec/extensions/rcte_tree_spec.rb +41 -43
  183. data/spec/extensions/schema_dumper_spec.rb +5 -8
  184. data/spec/extensions/schema_spec.rb +13 -21
  185. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  186. data/spec/extensions/serialization_spec.rb +72 -43
  187. data/spec/extensions/sharding_spec.rb +66 -140
  188. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  189. data/spec/extensions/spec_helper.rb +13 -61
  190. data/spec/extensions/sql_expr_spec.rb +20 -60
  191. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  192. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  193. data/spec/extensions/timestamps_spec.rb +6 -6
  194. data/spec/extensions/to_dot_spec.rb +4 -7
  195. data/spec/extensions/touch_spec.rb +13 -14
  196. data/spec/extensions/tree_spec.rb +11 -26
  197. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  198. data/spec/extensions/update_primary_key_spec.rb +30 -24
  199. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  200. data/spec/extensions/validation_helpers_spec.rb +16 -35
  201. data/spec/extensions/xml_serializer_spec.rb +16 -4
  202. data/spec/integration/associations_test.rb +537 -21
  203. data/spec/integration/database_test.rb +4 -2
  204. data/spec/integration/dataset_test.rb +461 -65
  205. data/spec/integration/eager_loader_test.rb +19 -21
  206. data/spec/integration/model_test.rb +80 -1
  207. data/spec/integration/plugin_test.rb +304 -116
  208. data/spec/integration/prepared_statement_test.rb +212 -122
  209. data/spec/integration/schema_test.rb +161 -30
  210. data/spec/integration/spec_helper.rb +39 -30
  211. data/spec/integration/timezone_test.rb +38 -12
  212. data/spec/integration/transaction_test.rb +172 -5
  213. data/spec/integration/type_test.rb +17 -3
  214. data/spec/model/association_reflection_spec.rb +201 -7
  215. data/spec/model/associations_spec.rb +865 -662
  216. data/spec/model/base_spec.rb +275 -95
  217. data/spec/model/dataset_methods_spec.rb +7 -27
  218. data/spec/model/eager_loading_spec.rb +677 -676
  219. data/spec/model/hooks_spec.rb +309 -67
  220. data/spec/model/model_spec.rb +222 -168
  221. data/spec/model/plugins_spec.rb +24 -13
  222. data/spec/model/record_spec.rb +381 -218
  223. data/spec/model/spec_helper.rb +13 -71
  224. data/spec/model/validations_spec.rb +11 -0
  225. metadata +115 -73
@@ -195,14 +195,14 @@ end
195
195
 
196
196
  describe "Sequel::IntegerMigrator" do
197
197
  before do
198
- dbc = Class.new(MockDatabase) do
198
+ dbc = Class.new(Sequel::Mock::Database) do
199
199
  attr_reader :drops, :tables_created, :columns_created, :versions
200
200
  def initialize(*args)
201
201
  super
202
202
  @drops = []
203
203
  @tables_created = []
204
204
  @columns_created = []
205
- @versions = {}
205
+ @versions = Hash.new{|h,k| h[k.to_sym]}
206
206
  end
207
207
 
208
208
  def version; versions.values.first || 0; end
@@ -211,8 +211,8 @@ describe "Sequel::IntegerMigrator" do
211
211
 
212
212
  def create_table(name, opts={}, &block)
213
213
  super
214
- @columns_created << / \(?(\w+) integer.*\)?\z/.match(sqls.last)[1].to_sym
215
- @tables_created << name
214
+ @columns_created << / \(?(\w+) integer.*\)?\z/.match(@sqls.last)[1].to_sym
215
+ @tables_created << name.to_sym
216
216
  end
217
217
 
218
218
  def dataset(opts={})
@@ -220,15 +220,15 @@ describe "Sequel::IntegerMigrator" do
220
220
  ds.extend(Module.new do
221
221
  def count; 1; end
222
222
  def columns; db.columns_created end
223
- def insert(h); db.versions.merge!(h); db.sqls << insert_sql(h) end
224
- def update(h); db.versions.merge!(h); db.sqls << update_sql(h) end
223
+ def insert(h); db.versions.merge!(h); db.run insert_sql(h) end
224
+ def update(h); db.versions.merge!(h); db.run update_sql(h) end
225
225
  def fetch_rows(sql); db.execute(sql); yield(db.versions) unless db.versions.empty? end
226
226
  end)
227
227
  ds
228
228
  end
229
229
 
230
230
  def table_exists?(name)
231
- @tables_created.include?(name)
231
+ @tables_created.include?(name.to_sym)
232
232
  end
233
233
  end
234
234
  @db = dbc.new
@@ -250,7 +250,7 @@ describe "Sequel::IntegerMigrator" do
250
250
 
251
251
  specify "should add a column name if it doesn't already exist in the schema_info table" do
252
252
  @db.create_table(:schema_info){Integer :v}
253
- @db.should_receive(:alter_table).with(:schema_info)
253
+ @db.should_receive(:alter_table).with('schema_info')
254
254
  Sequel::Migrator.apply(@db, @dirname)
255
255
  end
256
256
 
@@ -315,60 +315,63 @@ end
315
315
 
316
316
  describe "Sequel::TimestampMigrator" do
317
317
  before do
318
- $sequel_migration_version = 0
319
- $sequel_migration_files = []
320
- @dsc = dsc = Class.new(MockDataset) do
318
+ sequel_migration_version = 0
319
+ @dsc = dsc = Class.new(Sequel::Mock::Dataset) do
320
+ self::FILES =[]
321
+ define_method(:sequel_migration_version){sequel_migration_version}
322
+ define_method(:sequel_migration_version=){|v| sequel_migration_version = v}
323
+
321
324
  def columns
322
325
  case opts[:from].first
323
- when :schema_info
326
+ when :schema_info, 'schema_info'
324
327
  [:version]
325
- when :schema_migrations
328
+ when :schema_migrations, 'schema_migrations'
326
329
  [:filename]
327
- when :sm
330
+ when :sm, 'sm'
328
331
  [:fn]
329
332
  end
330
333
  end
331
334
 
332
335
  def fetch_rows(sql)
333
336
  case opts[:from].first
334
- when :schema_info
335
- yield({:version=>$sequel_migration_version})
336
- when :schema_migrations
337
- $sequel_migration_files.sort.each{|f| yield(:filename=>f)}
338
- when :sm
339
- $sequel_migration_files.sort.each{|f| yield(:fn=>f)}
337
+ when :schema_info, 'schema_info'
338
+ yield({:version=>sequel_migration_version})
339
+ when :schema_migrations, 'schema_migrations'
340
+ self.class::FILES.sort.each{|f| yield(:filename=>f)}
341
+ when :sm, 'sm'
342
+ self.class::FILES.sort.each{|f| yield(:fn=>f)}
340
343
  end
341
344
  end
342
345
 
343
346
  def insert(h={})
344
347
  case opts[:from].first
345
- when :schema_info
346
- $sequel_migration_version = h.values.first
347
- when :schema_migrations, :sm
348
- $sequel_migration_files << h.values.first
348
+ when :schema_info, 'schema_info'
349
+ self.sequel_migration_version = h.values.first
350
+ when :schema_migrations, :sm, 'schema_migrations', 'sm'
351
+ self.class::FILES << h.values.first
349
352
  end
350
353
  end
351
354
 
352
355
  def update(h={})
353
356
  case opts[:from].first
354
- when :schema_info
355
- $sequel_migration_version = h.values.first
357
+ when :schema_info, 'schema_info'
358
+ self.sequel_migration_version = h.values.first
356
359
  end
357
360
  end
358
361
 
359
362
  def delete
360
363
  case opts[:from].first
361
- when :schema_migrations, :sm
362
- $sequel_migration_files.delete(opts[:where].args.last)
364
+ when :schema_migrations, :sm, 'schema_migrations', 'sm'
365
+ self.class::FILES.delete(opts[:where].args.last)
363
366
  end
364
367
  end
365
368
  end
366
- dbc = Class.new(MockDatabase) do
369
+ dbc = Class.new(Sequel::Mock::Database) do
367
370
  tables = {}
368
371
  define_method(:dataset){|*a| dsc.new(self, *a)}
369
- define_method(:create_table){|name, *args| tables[name] = true}
370
- define_method(:drop_table){|*names| names.each{|n| tables.delete(n)}}
371
- define_method(:table_exists?){|name| tables.has_key?(name)}
372
+ define_method(:create_table){|name, *args| tables[name.to_sym] = true}
373
+ define_method(:drop_table){|*names| names.each{|n| tables.delete(n.to_sym)}}
374
+ define_method(:table_exists?){|name| tables.has_key?(name.to_sym)}
372
375
  end
373
376
  @db = dbc.new
374
377
  @m = Sequel::Migrator
@@ -12,7 +12,7 @@ describe "Sequel named_timezones extension" do
12
12
  before do
13
13
  @tz_in = TZInfo::Timezone.get('America/Los_Angeles')
14
14
  @tz_out = TZInfo::Timezone.get('America/New_York')
15
- @db = MockDatabase.new
15
+ @db = Sequel.mock
16
16
  @dt = DateTime.civil(2009,6,1,10,20,30,0)
17
17
  Sequel.application_timezone = 'America/Los_Angeles'
18
18
  Sequel.database_timezone = 'America/New_York'
@@ -66,8 +66,28 @@ describe "Sequel named_timezones extension" do
66
66
  end
67
67
 
68
68
  it "should work with the thread_local_timezones extension" do
69
- [Thread.new{Sequel.thread_application_timezone = 'America/New_York'; sleep 0.03; Sequel.application_timezone.should == @tz_out},
70
- Thread.new{sleep 0.01; Sequel.thread_application_timezone = 'America/Los_Angeles'; sleep 0.01; Sequel.application_timezone.should == @tz_in}].each{|x| x.join}
69
+ q, q1, q2 = Queue.new, Queue.new, Queue.new
70
+ tz1, tz2 = nil, nil
71
+ t1 = Thread.new do
72
+ Sequel.thread_application_timezone = 'America/New_York'
73
+ q2.push nil
74
+ q.pop
75
+ tz1 = Sequel.application_timezone
76
+ end
77
+ t2 = Thread.new do
78
+ Sequel.thread_application_timezone = 'America/Los_Angeles'
79
+ q2.push nil
80
+ q1.pop
81
+ tz2 = Sequel.application_timezone
82
+ end
83
+ q2.pop
84
+ q2.pop
85
+ q.push nil
86
+ q1.push nil
87
+ t1.join
88
+ t2.join
89
+ tz1.should == @tz_out
90
+ tz2.should == @tz_in
71
91
  end
72
92
  end
73
93
  end
@@ -1,46 +1,30 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "NestedAttributes plugin" do
4
- before do
5
- mods = @mods = []
6
- i = 0
7
- gi = lambda{i}
8
- ii = lambda{i+=1}
9
- ds_mod = Module.new do
10
- def empty?; false; end
11
- define_method(:insert) do |h|
12
- x = ii.call
13
- mods << [:i, first_source, h, x]
14
- x
15
- end
16
- define_method(:insert_select) do |h|
17
- x = ii.call
18
- mods << [:is, first_source, h, x]
19
- h.merge(:id=>x)
20
- end
21
- define_method(:update) do |h|
22
- mods << [:u, first_source, h, literal(opts[:where])]
23
- 1
24
- end
25
- define_method(:delete) do
26
- mods << [:d, first_source, literal(opts[:where])]
27
- 1
28
- end
29
- end
30
- db = Sequel::Database.new({})
31
- db.meta_def(:dataset) do |*a|
32
- x = super(*a)
33
- x.extend(ds_mod)
34
- x
4
+ def check_sqls(should, is)
5
+ if should.is_a?(Array)
6
+ should.should include(is)
7
+ else
8
+ should.should == is
35
9
  end
36
- @c = Class.new(Sequel::Model(db))
10
+ end
11
+
12
+ def check_sql_array(*shoulds)
13
+ sqls = @db.sqls
14
+ shoulds.length.should == sqls.length
15
+ shoulds.zip(sqls){|s, i| check_sqls(s, i)}
16
+ end
17
+
18
+ before do
19
+ @db = Sequel.mock(:autoid=>1, :numrows=>1)
20
+ @c = Class.new(Sequel::Model(@db))
37
21
  @c.plugin :nested_attributes
38
22
  @Artist = Class.new(@c).set_dataset(:artists)
39
23
  @Album = Class.new(@c).set_dataset(:albums)
40
24
  @Tag = Class.new(@c).set_dataset(:tags)
41
- [@Artist, @Album, @Tag].each do |m|
42
- m.dataset.extend(ds_mod)
43
- end
25
+ @Artist.plugin :skip_create_refresh
26
+ @Album.plugin :skip_create_refresh
27
+ @Tag.plugin :skip_create_refresh
44
28
  @Artist.columns :id, :name
45
29
  @Album.columns :id, :name, :artist_id
46
30
  @Tag.columns :id, :name
@@ -50,36 +34,44 @@ describe "NestedAttributes plugin" do
50
34
  @Album.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:at
51
35
  @Artist.nested_attributes :albums, :first_album, :destroy=>true, :remove=>true
52
36
  @Album.nested_attributes :artist, :tags, :destroy=>true, :remove=>true
37
+ @db.sqls
53
38
  end
54
39
 
55
40
  it "should support creating new many_to_one objects" do
56
41
  a = @Album.new({:name=>'Al', :artist_attributes=>{:name=>'Ar'}})
57
- @mods.should == []
42
+ @db.sqls.should == []
58
43
  a.save
59
- @mods.should == [[:is, :artists, {:name=>"Ar"}, 1], [:is, :albums, {:name=>"Al", :artist_id=>1}, 2]]
44
+ check_sql_array("INSERT INTO artists (name) VALUES ('Ar')",
45
+ ["INSERT INTO albums (name, artist_id) VALUES ('Al', 1)", "INSERT INTO albums (artist_id, name) VALUES (1, 'Al')"])
60
46
  end
61
47
 
62
48
  it "should support creating new one_to_one objects" do
63
49
  a = @Artist.new(:name=>'Ar')
64
50
  a.id = 1
65
51
  a.first_album_attributes = {:name=>'Al'}
66
- @mods.should == []
52
+ @db.sqls.should == []
67
53
  a.save
68
- @mods.should == [[:is, :artists, {:name=>"Ar", :id=>1}, 1], [:is, :albums, {:name=>"Al"}, 2], [:u, :albums, {:artist_id=>nil}, "((artist_id = 1) AND (id != 2))"], [:u, :albums, {:name=>"Al", :artist_id=>1}, "(id = 2)"]]
54
+ check_sql_array(["INSERT INTO artists (name, id) VALUES ('Ar', 1)", "INSERT INTO artists (id, name) VALUES (1, 'Ar')"],
55
+ "INSERT INTO albums (name) VALUES ('Al')",
56
+ "UPDATE albums SET artist_id = NULL WHERE ((artist_id = 1) AND (id != 2))",
57
+ ["UPDATE albums SET artist_id = 1, name = 'Al' WHERE (id = 2)", "UPDATE albums SET name = 'Al', artist_id = 1 WHERE (id = 2)"])
69
58
  end
70
59
 
71
60
  it "should support creating new one_to_many objects" do
72
61
  a = @Artist.new({:name=>'Ar', :albums_attributes=>[{:name=>'Al'}]})
73
- @mods.should == []
62
+ @db.sqls.should == []
74
63
  a.save
75
- @mods.should == [[:is, :artists, {:name=>"Ar"}, 1], [:is, :albums, {:name=>"Al", :artist_id=>1}, 2]]
64
+ check_sql_array("INSERT INTO artists (name) VALUES ('Ar')",
65
+ ["INSERT INTO albums (artist_id, name) VALUES (1, 'Al')", "INSERT INTO albums (name, artist_id) VALUES ('Al', 1)"])
76
66
  end
77
67
 
78
68
  it "should support creating new many_to_many objects" do
79
69
  a = @Album.new({:name=>'Al', :tags_attributes=>[{:name=>'T'}]})
80
- @mods.should == []
70
+ @db.sqls.should == []
81
71
  a.save
82
- @mods.should == [[:is, :albums, {:name=>"Al"}, 1], [:is, :tags, {:name=>"T"}, 2], [:i, :at, {:album_id=>1, :tag_id=>2}, 3]]
72
+ check_sql_array("INSERT INTO albums (name) VALUES ('Al')",
73
+ "INSERT INTO tags (name) VALUES ('T')",
74
+ ["INSERT INTO at (album_id, tag_id) VALUES (1, 2)", "INSERT INTO at (tag_id, album_id) VALUES (2, 1)"])
83
75
  end
84
76
 
85
77
  it "should add new objects to the cached association array as soon as the *_attributes= method is called" do
@@ -93,9 +85,9 @@ describe "NestedAttributes plugin" do
93
85
  ar = @Artist.load(:id=>20, :name=>'Ar')
94
86
  al.associations[:artist] = ar
95
87
  al.set(:artist_attributes=>{:id=>'20', :name=>'Ar2'})
96
- @mods.should == []
88
+ @db.sqls.should == []
97
89
  al.save
98
- @mods.should == [[:u, :albums, {:name=>"Al"}, '(id = 10)'], [:u, :artists, {:name=>"Ar2"}, '(id = 20)']]
90
+ @db.sqls.should == ["UPDATE albums SET name = 'Al' WHERE (id = 10)", "UPDATE artists SET name = 'Ar2' WHERE (id = 20)"]
99
91
  end
100
92
 
101
93
  it "should support updating one_to_one objects" do
@@ -103,9 +95,9 @@ describe "NestedAttributes plugin" do
103
95
  ar = @Artist.load(:id=>20, :name=>'Ar')
104
96
  ar.associations[:first_album] = al
105
97
  ar.set(:first_album_attributes=>{:id=>10, :name=>'Al2'})
106
- @mods.should == []
98
+ @db.sqls.should == []
107
99
  ar.save
108
- @mods.should == [[:u, :artists, {:name=>"Ar"}, '(id = 20)'], [:u, :albums, {:name=>"Al2"}, '(id = 10)']]
100
+ @db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "UPDATE albums SET name = 'Al2' WHERE (id = 10)"]
109
101
  end
110
102
 
111
103
  it "should support updating one_to_many objects" do
@@ -113,9 +105,9 @@ describe "NestedAttributes plugin" do
113
105
  ar = @Artist.load(:id=>20, :name=>'Ar')
114
106
  ar.associations[:albums] = [al]
115
107
  ar.set(:albums_attributes=>[{:id=>10, :name=>'Al2'}])
116
- @mods.should == []
108
+ @db.sqls.should == []
117
109
  ar.save
118
- @mods.should == [[:u, :artists, {:name=>"Ar"}, '(id = 20)'], [:u, :albums, {:name=>"Al2"}, '(id = 10)']]
110
+ @db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "UPDATE albums SET name = 'Al2' WHERE (id = 10)"]
119
111
  end
120
112
 
121
113
  it "should support updating many_to_many objects" do
@@ -123,9 +115,9 @@ describe "NestedAttributes plugin" do
123
115
  t = @Tag.load(:id=>20, :name=>'T')
124
116
  a.associations[:tags] = [t]
125
117
  a.set(:tags_attributes=>[{:id=>20, :name=>'T2'}])
126
- @mods.should == []
118
+ @db.sqls.should == []
127
119
  a.save
128
- @mods.should == [[:u, :albums, {:name=>"Al"}, '(id = 10)'], [:u, :tags, {:name=>"T2"}, '(id = 20)']]
120
+ @db.sqls.should == ["UPDATE albums SET name = 'Al' WHERE (id = 10)", "UPDATE tags SET name = 'T2' WHERE (id = 20)"]
129
121
  end
130
122
 
131
123
  it "should support removing many_to_one objects" do
@@ -133,9 +125,9 @@ describe "NestedAttributes plugin" do
133
125
  ar = @Artist.load(:id=>20, :name=>'Ar')
134
126
  al.associations[:artist] = ar
135
127
  al.set(:artist_attributes=>{:id=>'20', :_remove=>'1'})
136
- @mods.should == []
128
+ @db.sqls.should == []
137
129
  al.save
138
- @mods.should == [[:u, :albums, {:artist_id=>nil, :name=>'Al'}, '(id = 10)']]
130
+ check_sql_array(["UPDATE albums SET artist_id = NULL, name = 'Al' WHERE (id = 10)", "UPDATE albums SET name = 'Al', artist_id = NULL WHERE (id = 10)"])
139
131
  end
140
132
 
141
133
  it "should support removing one_to_one objects" do
@@ -143,10 +135,9 @@ describe "NestedAttributes plugin" do
143
135
  ar = @Artist.load(:id=>20, :name=>'Ar')
144
136
  ar.associations[:first_album] = al
145
137
  ar.set(:first_album_attributes=>{:id=>10, :_remove=>'t'})
146
- @mods.should == []
138
+ @db.sqls.should == []
147
139
  ar.save
148
- @mods.should == [[:u, :albums, {:artist_id=>nil}, "(artist_id = 20)"], [:u, :artists, {:name=>"Ar"}, "(id = 20)"]]
149
-
140
+ @db.sqls.should == ["UPDATE albums SET artist_id = NULL WHERE (artist_id = 20)", "UPDATE artists SET name = 'Ar' WHERE (id = 20)"]
150
141
  end
151
142
 
152
143
  it "should support removing one_to_many objects" do
@@ -154,9 +145,12 @@ describe "NestedAttributes plugin" do
154
145
  ar = @Artist.load(:id=>20, :name=>'Ar')
155
146
  ar.associations[:albums] = [al]
156
147
  ar.set(:albums_attributes=>[{:id=>10, :_remove=>'t'}])
157
- @mods.should == []
148
+ @db.sqls.should == []
149
+ @Album.dataset._fetch = {:id=>1}
158
150
  ar.save
159
- @mods.should == [[:u, :albums, {:name=>"Al", :artist_id=>nil}, '(id = 10)'], [:u, :artists, {:name=>"Ar"}, '(id = 20)']]
151
+ check_sql_array("SELECT 1 AS one FROM albums WHERE ((albums.artist_id = 20) AND (id = 10)) LIMIT 1",
152
+ ["UPDATE albums SET artist_id = NULL, name = 'Al' WHERE (id = 10)", "UPDATE albums SET name = 'Al', artist_id = NULL WHERE (id = 10)"],
153
+ "UPDATE artists SET name = 'Ar' WHERE (id = 20)")
160
154
  end
161
155
 
162
156
  it "should support removing many_to_many objects" do
@@ -164,9 +158,9 @@ describe "NestedAttributes plugin" do
164
158
  t = @Tag.load(:id=>20, :name=>'T')
165
159
  a.associations[:tags] = [t]
166
160
  a.set(:tags_attributes=>[{:id=>20, :_remove=>true}])
167
- @mods.should == []
161
+ @db.sqls.should == []
168
162
  a.save
169
- @mods.should == [[:d, :at, '((album_id = 10) AND (tag_id = 20))'], [:u, :albums, {:name=>"Al"}, '(id = 10)']]
163
+ @db.sqls.should == ["DELETE FROM at WHERE ((album_id = 10) AND (tag_id = 20))", "UPDATE albums SET name = 'Al' WHERE (id = 10)"]
170
164
  end
171
165
 
172
166
  it "should support destroying many_to_one objects" do
@@ -174,9 +168,10 @@ describe "NestedAttributes plugin" do
174
168
  ar = @Artist.load(:id=>20, :name=>'Ar')
175
169
  al.associations[:artist] = ar
176
170
  al.set(:artist_attributes=>{:id=>'20', :_delete=>'1'})
177
- @mods.should == []
171
+ @db.sqls.should == []
178
172
  al.save
179
- @mods.should == [[:u, :albums, {:artist_id=>nil, :name=>'Al'}, '(id = 10)'], [:d, :artists, '(id = 20)']]
173
+ check_sql_array(["UPDATE albums SET artist_id = NULL, name = 'Al' WHERE (id = 10)", "UPDATE albums SET name = 'Al', artist_id = NULL WHERE (id = 10)"],
174
+ "DELETE FROM artists WHERE (id = 20)")
180
175
  end
181
176
 
182
177
  it "should support destroying one_to_one objects" do
@@ -184,9 +179,9 @@ describe "NestedAttributes plugin" do
184
179
  ar = @Artist.load(:id=>20, :name=>'Ar')
185
180
  ar.associations[:first_album] = al
186
181
  ar.set(:first_album_attributes=>{:id=>10, :_delete=>'t'})
187
- @mods.should == []
182
+ @db.sqls.should == []
188
183
  ar.save
189
- @mods.should == [[:u, :artists, {:name=>"Ar"}, "(id = 20)"], [:d, :albums, "(id = 10)"]]
184
+ @db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "DELETE FROM albums WHERE (id = 10)"]
190
185
  end
191
186
 
192
187
  it "should support destroying one_to_many objects" do
@@ -194,9 +189,9 @@ describe "NestedAttributes plugin" do
194
189
  ar = @Artist.load(:id=>20, :name=>'Ar')
195
190
  ar.associations[:albums] = [al]
196
191
  ar.set(:albums_attributes=>[{:id=>10, :_delete=>'t'}])
197
- @mods.should == []
192
+ @db.sqls.should == []
198
193
  ar.save
199
- @mods.should == [[:u, :artists, {:name=>"Ar"}, '(id = 20)'], [:d, :albums, '(id = 10)']]
194
+ @db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "DELETE FROM albums WHERE (id = 10)"]
200
195
  end
201
196
 
202
197
  it "should support destroying many_to_many objects" do
@@ -204,9 +199,9 @@ describe "NestedAttributes plugin" do
204
199
  t = @Tag.load(:id=>20, :name=>'T')
205
200
  a.associations[:tags] = [t]
206
201
  a.set(:tags_attributes=>[{:id=>20, :_delete=>true}])
207
- @mods.should == []
202
+ @db.sqls.should == []
208
203
  a.save
209
- @mods.should == [[:d, :at, '((album_id = 10) AND (tag_id = 20))'], [:u, :albums, {:name=>"Al"}, '(id = 10)'], [:d, :tags, '(id = 20)']]
204
+ @db.sqls.should == ["DELETE FROM at WHERE ((album_id = 10) AND (tag_id = 20))", "UPDATE albums SET name = 'Al' WHERE (id = 10)", "DELETE FROM tags WHERE (id = 20)"]
210
205
  end
211
206
 
212
207
  it "should support both string and symbol keys in nested attribute hashes" do
@@ -214,9 +209,9 @@ describe "NestedAttributes plugin" do
214
209
  t = @Tag.load(:id=>20, :name=>'T')
215
210
  a.associations[:tags] = [t]
216
211
  a.set('tags_attributes'=>[{'id'=>20, '_delete'=>true}])
217
- @mods.should == []
212
+ @db.sqls.should == []
218
213
  a.save
219
- @mods.should == [[:d, :at, '((album_id = 10) AND (tag_id = 20))'], [:u, :albums, {:name=>"Al"}, '(id = 10)'], [:d, :tags, '(id = 20)']]
214
+ @db.sqls.should == ["DELETE FROM at WHERE ((album_id = 10) AND (tag_id = 20))", "UPDATE albums SET name = 'Al' WHERE (id = 10)", "DELETE FROM tags WHERE (id = 20)"]
220
215
  end
221
216
 
222
217
  it "should support using a hash instead of an array for to_many nested attributes" do
@@ -224,9 +219,9 @@ describe "NestedAttributes plugin" do
224
219
  t = @Tag.load(:id=>20, :name=>'T')
225
220
  a.associations[:tags] = [t]
226
221
  a.set('tags_attributes'=>{'1'=>{'id'=>20, '_delete'=>true}})
227
- @mods.should == []
222
+ @db.sqls.should == []
228
223
  a.save
229
- @mods.should == [[:d, :at, '((album_id = 10) AND (tag_id = 20))'], [:u, :albums, {:name=>"Al"}, '(id = 10)'], [:d, :tags, '(id = 20)']]
224
+ @db.sqls.should == ["DELETE FROM at WHERE ((album_id = 10) AND (tag_id = 20))", "UPDATE albums SET name = 'Al' WHERE (id = 10)", "DELETE FROM tags WHERE (id = 20)"]
230
225
  end
231
226
 
232
227
  it "should only allow destroying associated objects if :destroy option is used in the nested_attributes call" do
@@ -263,9 +258,9 @@ describe "NestedAttributes plugin" do
263
258
  ar = @Artist.load(:id=>20, :name=>'Ar')
264
259
  ar.associations[:albums] = [al]
265
260
  ar.set(:albums_attributes=>[{:id=>30, :_delete=>'t'}])
266
- @mods.should == []
261
+ @db.sqls.should == []
267
262
  ar.save
268
- @mods.should == [[:u, :artists, {:name=>"Ar"}, '(id = 20)']]
263
+ @db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)"]
269
264
  end
270
265
 
271
266
  it "should not save if nested attribute is not valid and should include nested attribute validation errors in the main object's validation errors" do
@@ -276,10 +271,10 @@ describe "NestedAttributes plugin" do
276
271
  end
277
272
  end
278
273
  a = @Album.new(:name=>'Al', :artist_attributes=>{:name=>'Ar'})
279
- @mods.should == []
274
+ @db.sqls.should == []
280
275
  proc{a.save}.should raise_error(Sequel::ValidationFailed)
281
276
  a.errors.full_messages.should == ['artist name cannot be Ar']
282
- @mods.should == []
277
+ @db.sqls.should == []
283
278
  # Should preserve attributes
284
279
  a.artist.name.should == 'Ar'
285
280
  end
@@ -294,9 +289,10 @@ describe "NestedAttributes plugin" do
294
289
  end
295
290
  end
296
291
  a = @Album.new(:name=>'Al', :artist_attributes=>{:name=>'Ar'})
297
- @mods.should == []
292
+ @db.sqls.should == []
298
293
  a.save
299
- @mods.should == [[:is, :artists, {:name=>"Ar"}, 1], [:is, :albums, {:name=>"Al", :artist_id=>1}, 2]]
294
+ check_sql_array("INSERT INTO artists (name) VALUES ('Ar')",
295
+ ["INSERT INTO albums (artist_id, name) VALUES (1, 'Al')", "INSERT INTO albums (name, artist_id) VALUES ('Al', 1)"])
300
296
  end
301
297
 
302
298
  it "should not attempt to validate nested attributes if the :validate=>false option is passed to save" do
@@ -307,23 +303,25 @@ describe "NestedAttributes plugin" do
307
303
  end
308
304
  end
309
305
  a = @Album.new(:name=>'Al', :artist_attributes=>{:name=>'Ar'})
310
- @mods.should == []
306
+ @db.sqls.should == []
311
307
  a.save(:validate=>false)
312
- @mods.should == [[:is, :artists, {:name=>"Ar"}, 1], [:is, :albums, {:name=>"Al", :artist_id=>1}, 2]]
308
+ check_sql_array("INSERT INTO artists (name) VALUES ('Ar')",
309
+ ["INSERT INTO albums (artist_id, name) VALUES (1, 'Al')", "INSERT INTO albums (name, artist_id) VALUES ('Al', 1)"])
313
310
  end
314
311
 
315
312
  it "should not accept nested attributes unless explicitly specified" do
316
313
  @Artist.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:at
317
314
  proc{@Artist.create({:name=>'Ar', :tags_attributes=>[{:name=>'T'}]})}.should raise_error(Sequel::Error)
318
- @mods.should == []
315
+ @db.sqls.should == []
319
316
  end
320
317
 
321
318
  it "should save when save_changes or update is called if nested attribute associated objects changed but there are no changes to the main object" do
322
319
  al = @Album.load(:id=>10, :name=>'Al')
323
320
  ar = @Artist.load(:id=>20, :name=>'Ar')
324
321
  al.associations[:artist] = ar
322
+ @db.sqls.should == []
325
323
  al.update(:artist_attributes=>{:id=>'20', :name=>'Ar2'})
326
- @mods.should == [[:u, :artists, {:name=>"Ar2"}, '(id = 20)']]
324
+ @db.sqls.should == ["UPDATE artists SET name = 'Ar2' WHERE (id = 20)"]
327
325
  end
328
326
 
329
327
  it "should have a :limit option limiting the amount of entries" do
@@ -331,17 +329,25 @@ describe "NestedAttributes plugin" do
331
329
  arr = [{:name=>'T'}]
332
330
  proc{@Album.new({:name=>'Al', :tags_attributes=>arr*3})}.should raise_error(Sequel::Error)
333
331
  a = @Album.new({:name=>'Al', :tags_attributes=>arr*2})
334
- @mods.should == []
332
+ @db.sqls.should == []
335
333
  a.save
336
- @mods.should == [[:is, :albums, {:name=>"Al"}, 1], [:is, :tags, {:name=>"T"}, 2], [:i, :at, {:album_id=>1, :tag_id=>2}, 3], [:is, :tags, {:name=>"T"}, 4], [:i, :at, {:album_id=>1, :tag_id=>4}, 5]]
334
+ check_sql_array("INSERT INTO albums (name) VALUES ('Al')",
335
+ "INSERT INTO tags (name) VALUES ('T')",
336
+ ["INSERT INTO at (album_id, tag_id) VALUES (1, 2)", "INSERT INTO at (tag_id, album_id) VALUES (2, 1)"],
337
+ "INSERT INTO tags (name) VALUES ('T')",
338
+ ["INSERT INTO at (album_id, tag_id) VALUES (1, 4)", "INSERT INTO at (tag_id, album_id) VALUES (4, 1)"])
337
339
  end
338
340
 
339
341
  it "should accept a block that each hash gets passed to determine if it should be processed" do
340
342
  @Album.nested_attributes(:tags){|h| h[:name].empty?}
341
343
  a = @Album.new({:name=>'Al', :tags_attributes=>[{:name=>'T'}, {:name=>''}, {:name=>'T2'}]})
342
- @mods.should == []
344
+ @db.sqls.should == []
343
345
  a.save
344
- @mods.should == [[:is, :albums, {:name=>"Al"}, 1], [:is, :tags, {:name=>"T"}, 2], [:i, :at, {:album_id=>1, :tag_id=>2}, 3], [:is, :tags, {:name=>"T2"}, 4], [:i, :at, {:album_id=>1, :tag_id=>4}, 5]]
346
+ check_sql_array("INSERT INTO albums (name) VALUES ('Al')",
347
+ "INSERT INTO tags (name) VALUES ('T')",
348
+ ["INSERT INTO at (album_id, tag_id) VALUES (1, 2)", "INSERT INTO at (tag_id, album_id) VALUES (2, 1)"],
349
+ "INSERT INTO tags (name) VALUES ('T2')",
350
+ ["INSERT INTO at (album_id, tag_id) VALUES (1, 4)", "INSERT INTO at (tag_id, album_id) VALUES (4, 1)"])
345
351
  end
346
352
 
347
353
  it "should return objects created/modified in the internal methods" do
@@ -387,9 +393,12 @@ describe "NestedAttributes plugin" do
387
393
  t = @Tag.load(:id=>30, :name=>'T', :number=>10)
388
394
  al.associations[:tags] = [t]
389
395
  al.set(:tags_attributes=>[{:id=>30, :name=>'T2'}, {:name=>'T3'}])
390
- @mods.should == []
396
+ @db.sqls.should == []
391
397
  al.save
392
- @mods.should == [[:u, :albums, {:name=>'Al'}, '(id = 10)'], [:u, :tags, {:name=>'T2'}, '(id = 30)'], [:is, :tags, {:name=>"T3"}, 1], [:i, :at, {:album_id=>10, :tag_id=>1}, 2]]
398
+ check_sql_array("UPDATE albums SET name = 'Al' WHERE (id = 10)",
399
+ "UPDATE tags SET name = 'T2' WHERE (id = 30)",
400
+ "INSERT INTO tags (name) VALUES ('T3')",
401
+ ["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
393
402
  proc{al.set(:tags_attributes=>[{:id=>30, :name=>'T2', :number=>3}])}.should raise_error(Sequel::Error)
394
403
  proc{al.set(:tags_attributes=>[{:name=>'T2', :number=>3}])}.should raise_error(Sequel::Error)
395
404
  end
@@ -6,11 +6,8 @@ describe "optimistic_locking plugin" do
6
6
  end
7
7
  h = {1=>{:id=>1, :name=>'John', :lock_version=>2}}
8
8
  lv = @lv = "lock_version"
9
- @c.dataset.quote_identifiers = false
10
- @c.dataset.meta_def(:h){h}
11
- @c.dataset.meta_def(:lv){lv}
12
- @c.dataset.meta_def(:update) do |opts|
13
- case update_sql(opts)
9
+ @c.dataset.numrows = proc do |sql|
10
+ case sql
14
11
  when /UPDATE people SET (name|#{lv}) = ('Jim'|'Bob'|\d+), (?:name|#{lv}) = ('Jim'|'Bob'|\d+) WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
15
12
  name, nlv = $1 == 'name' ? [$2, $3] : [$3, $2]
16
13
  m = h[$4.to_i]
@@ -28,20 +25,6 @@ describe "optimistic_locking plugin" do
28
25
  else
29
26
  0
30
27
  end
31
- else
32
- puts update_sql(opts)
33
- end
34
- end
35
- @c.dataset.instance_eval do
36
- def fetch_rows(sql)
37
- m = h[1].dup
38
- v = m.delete(:lock_version)
39
- m[lv.to_sym] = v
40
- yield(m)
41
- end
42
- end
43
- @c.dataset.meta_def(:delete) do
44
- case delete_sql
45
28
  when /DELETE FROM people WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
46
29
  m = h[$1.to_i]
47
30
  if m && m[lv.to_sym] == $2.to_i
@@ -51,9 +34,15 @@ describe "optimistic_locking plugin" do
51
34
  0
52
35
  end
53
36
  else
54
- puts delete_sql
37
+ puts sql
55
38
  end
56
39
  end
40
+ @c.dataset._fetch = proc do |sql|
41
+ m = h[1].dup
42
+ v = m.delete(:lock_version)
43
+ m[lv.to_sym] = v
44
+ m
45
+ end
57
46
  @c.columns :id, :name, :lock_version
58
47
  @c.plugin :optimistic_locking
59
48
  end