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.
- data/CHANGELOG +485 -3
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/association_basics.rdoc +249 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +89 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +129 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +5 -7
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +45 -0
- data/lib/sequel/adapters/jdbc/derby.rb +247 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +56 -29
- data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
- data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
- data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +231 -78
- data/lib/sequel/adapters/mock.rb +335 -0
- data/lib/sequel/adapters/mysql.rb +82 -184
- data/lib/sequel/adapters/mysql2.rb +26 -25
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +1 -6
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +351 -53
- data/lib/sequel/adapters/postgres.rb +194 -33
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +321 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +231 -106
- data/lib/sequel/adapters/shared/mysql.rb +181 -63
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +231 -41
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +4 -7
- data/lib/sequel/adapters/shared/sqlite.rb +201 -57
- data/lib/sequel/adapters/sqlite.rb +29 -21
- data/lib/sequel/adapters/swift/mysql.rb +12 -7
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +160 -19
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +46 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +104 -19
- data/lib/sequel/database/query.rb +153 -58
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +231 -76
- data/lib/sequel/dataset/features.rb +91 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +5 -6
- data/lib/sequel/dataset/prepared_statements.rb +48 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +665 -253
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +1020 -337
- data/lib/sequel/model/base.rb +414 -132
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +15 -8
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +65 -7
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +88 -44
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +109 -52
- data/lib/sequel/timezones.rb +57 -38
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +111 -29
- data/spec/adapters/mysql_spec.rb +135 -123
- data/spec/adapters/oracle_spec.rb +49 -77
- data/spec/adapters/postgres_spec.rb +267 -78
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +21 -30
- data/spec/core/database_spec.rb +788 -512
- data/spec/core/dataset_spec.rb +1073 -1053
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +419 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +114 -22
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +53 -0
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/migration_spec.rb +35 -32
- data/spec/extensions/named_timezones_spec.rb +23 -3
- data/spec/extensions/nested_attributes_spec.rb +97 -88
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +53 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +5 -8
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
- data/spec/extensions/serialization_spec.rb +72 -43
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +18 -29
- data/spec/extensions/spec_helper.rb +13 -61
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +4 -7
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +537 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +461 -65
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +304 -116
- data/spec/integration/prepared_statement_test.rb +212 -122
- data/spec/integration/schema_test.rb +161 -30
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +172 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +865 -662
- data/spec/model/base_spec.rb +275 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +677 -676
- data/spec/model/hooks_spec.rb +309 -67
- data/spec/model/model_spec.rb +222 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +381 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +115 -73
|
@@ -195,14 +195,14 @@ end
|
|
|
195
195
|
|
|
196
196
|
describe "Sequel::IntegerMigrator" do
|
|
197
197
|
before do
|
|
198
|
-
dbc = Class.new(
|
|
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.
|
|
224
|
-
def update(h); db.versions.merge!(h); db.
|
|
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(
|
|
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
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
|
336
|
-
when :schema_migrations
|
|
337
|
-
|
|
338
|
-
when :sm
|
|
339
|
-
|
|
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
|
-
|
|
347
|
-
when :schema_migrations, :sm
|
|
348
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
70
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
@
|
|
42
|
+
@db.sqls.should == []
|
|
58
43
|
a.save
|
|
59
|
-
|
|
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
|
-
@
|
|
52
|
+
@db.sqls.should == []
|
|
67
53
|
a.save
|
|
68
|
-
|
|
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
|
-
@
|
|
62
|
+
@db.sqls.should == []
|
|
74
63
|
a.save
|
|
75
|
-
|
|
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
|
-
@
|
|
70
|
+
@db.sqls.should == []
|
|
81
71
|
a.save
|
|
82
|
-
|
|
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
|
-
@
|
|
88
|
+
@db.sqls.should == []
|
|
97
89
|
al.save
|
|
98
|
-
@
|
|
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
|
-
@
|
|
98
|
+
@db.sqls.should == []
|
|
107
99
|
ar.save
|
|
108
|
-
@
|
|
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
|
-
@
|
|
108
|
+
@db.sqls.should == []
|
|
117
109
|
ar.save
|
|
118
|
-
@
|
|
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
|
-
@
|
|
118
|
+
@db.sqls.should == []
|
|
127
119
|
a.save
|
|
128
|
-
@
|
|
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
|
-
@
|
|
128
|
+
@db.sqls.should == []
|
|
137
129
|
al.save
|
|
138
|
-
|
|
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
|
-
@
|
|
138
|
+
@db.sqls.should == []
|
|
147
139
|
ar.save
|
|
148
|
-
@
|
|
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
|
-
@
|
|
148
|
+
@db.sqls.should == []
|
|
149
|
+
@Album.dataset._fetch = {:id=>1}
|
|
158
150
|
ar.save
|
|
159
|
-
|
|
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
|
-
@
|
|
161
|
+
@db.sqls.should == []
|
|
168
162
|
a.save
|
|
169
|
-
@
|
|
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
|
-
@
|
|
171
|
+
@db.sqls.should == []
|
|
178
172
|
al.save
|
|
179
|
-
|
|
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
|
-
@
|
|
182
|
+
@db.sqls.should == []
|
|
188
183
|
ar.save
|
|
189
|
-
@
|
|
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
|
-
@
|
|
192
|
+
@db.sqls.should == []
|
|
198
193
|
ar.save
|
|
199
|
-
@
|
|
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
|
-
@
|
|
202
|
+
@db.sqls.should == []
|
|
208
203
|
a.save
|
|
209
|
-
@
|
|
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
|
-
@
|
|
212
|
+
@db.sqls.should == []
|
|
218
213
|
a.save
|
|
219
|
-
@
|
|
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
|
-
@
|
|
222
|
+
@db.sqls.should == []
|
|
228
223
|
a.save
|
|
229
|
-
@
|
|
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
|
-
@
|
|
261
|
+
@db.sqls.should == []
|
|
267
262
|
ar.save
|
|
268
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
292
|
+
@db.sqls.should == []
|
|
298
293
|
a.save
|
|
299
|
-
|
|
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
|
-
@
|
|
306
|
+
@db.sqls.should == []
|
|
311
307
|
a.save(:validate=>false)
|
|
312
|
-
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
332
|
+
@db.sqls.should == []
|
|
335
333
|
a.save
|
|
336
|
-
|
|
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
|
-
@
|
|
344
|
+
@db.sqls.should == []
|
|
343
345
|
a.save
|
|
344
|
-
|
|
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
|
-
@
|
|
396
|
+
@db.sqls.should == []
|
|
391
397
|
al.save
|
|
392
|
-
|
|
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.
|
|
10
|
-
|
|
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
|
|
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
|