sequel 3.29.0 → 3.30.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 +35 -3
- data/Rakefile +2 -1
- data/doc/association_basics.rdoc +11 -0
- data/doc/opening_databases.rdoc +2 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/testing.rdoc +17 -3
- data/lib/sequel/adapters/amalgalite.rb +2 -2
- data/lib/sequel/adapters/do/mysql.rb +5 -2
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc.rb +126 -43
- data/lib/sequel/adapters/jdbc/as400.rb +11 -3
- data/lib/sequel/adapters/jdbc/db2.rb +2 -1
- data/lib/sequel/adapters/jdbc/derby.rb +44 -19
- data/lib/sequel/adapters/jdbc/h2.rb +32 -19
- data/lib/sequel/adapters/jdbc/hsqldb.rb +21 -17
- data/lib/sequel/adapters/jdbc/jtds.rb +9 -4
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +21 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +48 -18
- data/lib/sequel/adapters/mock.rb +2 -1
- data/lib/sequel/adapters/mysql.rb +4 -2
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/openbase.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +6 -6
- data/lib/sequel/adapters/postgres.rb +25 -12
- data/lib/sequel/adapters/shared/access.rb +14 -6
- data/lib/sequel/adapters/shared/db2.rb +36 -13
- data/lib/sequel/adapters/shared/firebird.rb +12 -5
- data/lib/sequel/adapters/shared/informix.rb +11 -3
- data/lib/sequel/adapters/shared/mssql.rb +94 -47
- data/lib/sequel/adapters/shared/mysql.rb +107 -49
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
- data/lib/sequel/adapters/shared/oracle.rb +54 -27
- data/lib/sequel/adapters/shared/postgres.rb +65 -26
- data/lib/sequel/adapters/shared/progress.rb +4 -1
- data/lib/sequel/adapters/shared/sqlite.rb +36 -20
- data/lib/sequel/adapters/sqlite.rb +2 -3
- data/lib/sequel/adapters/swift/mysql.rb +3 -2
- data/lib/sequel/adapters/swift/sqlite.rb +2 -2
- data/lib/sequel/adapters/tinytds.rb +14 -8
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -4
- data/lib/sequel/database/misc.rb +6 -2
- data/lib/sequel/dataset/graph.rb +33 -7
- data/lib/sequel/dataset/prepared_statements.rb +19 -5
- data/lib/sequel/dataset/sql.rb +611 -201
- data/lib/sequel/model/associations.rb +12 -5
- data/lib/sequel/model/base.rb +20 -5
- data/lib/sequel/plugins/sharding.rb +9 -29
- data/lib/sequel/sql.rb +2 -1
- data/lib/sequel/timezones.rb +14 -4
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +10 -0
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/core/core_sql_spec.rb +3 -1
- data/spec/core/database_spec.rb +42 -0
- data/spec/core/dataset_spec.rb +10 -3
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/object_graph_spec.rb +38 -0
- 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 +35 -39
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +30 -82
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +33 -103
- data/spec/extensions/instance_filters_spec.rb +10 -21
- data/spec/extensions/instance_hooks_spec.rb +6 -24
- 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 +135 -277
- data/spec/extensions/migration_spec.rb +18 -15
- data/spec/extensions/named_timezones_spec.rb +1 -1
- data/spec/extensions/nested_attributes_spec.rb +97 -92
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +22 -37
- data/spec/extensions/prepared_statements_safe_spec.rb +9 -27
- data/spec/extensions/prepared_statements_spec.rb +11 -30
- data/spec/extensions/prepared_statements_with_pk_spec.rb +6 -13
- 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 +3 -6
- data/spec/extensions/serialization_spec.rb +20 -32
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +14 -36
- data/spec/extensions/spec_helper.rb +10 -64
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +1 -2
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- 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/integration/dataset_test.rb +16 -4
- data/spec/integration/prepared_statement_test.rb +4 -2
- data/spec/model/eager_loading_spec.rb +16 -0
- data/spec/model/model_spec.rb +15 -1
- data/spec/model/record_spec.rb +60 -0
- metadata +23 -40
|
@@ -195,7 +195,7 @@ 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
|
|
@@ -211,7 +211,7 @@ 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
|
|
214
|
+
@columns_created << / \(?(\w+) integer.*\)?\z/.match(@sqls.last)[1].to_sym
|
|
215
215
|
@tables_created << name.to_sym
|
|
216
216
|
end
|
|
217
217
|
|
|
@@ -220,8 +220,8 @@ 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
|
|
@@ -315,9 +315,12 @@ 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
326
|
when :schema_info, 'schema_info'
|
|
@@ -332,38 +335,38 @@ describe "Sequel::TimestampMigrator" do
|
|
|
332
335
|
def fetch_rows(sql)
|
|
333
336
|
case opts[:from].first
|
|
334
337
|
when :schema_info, 'schema_info'
|
|
335
|
-
yield({:version
|
|
338
|
+
yield({:version=>sequel_migration_version})
|
|
336
339
|
when :schema_migrations, 'schema_migrations'
|
|
337
|
-
|
|
340
|
+
self.class::FILES.sort.each{|f| yield(:filename=>f)}
|
|
338
341
|
when :sm, 'sm'
|
|
339
|
-
|
|
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
348
|
when :schema_info, 'schema_info'
|
|
346
|
-
|
|
349
|
+
self.sequel_migration_version = h.values.first
|
|
347
350
|
when :schema_migrations, :sm, 'schema_migrations', 'sm'
|
|
348
|
-
|
|
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
357
|
when :schema_info, 'schema_info'
|
|
355
|
-
|
|
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
364
|
when :schema_migrations, :sm, 'schema_migrations', 'sm'
|
|
362
|
-
|
|
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
372
|
define_method(:create_table){|name, *args| tables[name.to_sym] = true}
|
|
@@ -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'
|
|
@@ -1,50 +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(:supports_insert_select?){true}
|
|
17
|
-
define_method(:insert_select) do |h|
|
|
18
|
-
x = ii.call
|
|
19
|
-
mods << [:is, first_source, h, x]
|
|
20
|
-
h.merge(:id=>x)
|
|
21
|
-
end
|
|
22
|
-
define_method(:update) do |h|
|
|
23
|
-
mods << [:u, first_source, h, literal(opts[:where])]
|
|
24
|
-
1
|
|
25
|
-
end
|
|
26
|
-
define_method(:delete) do
|
|
27
|
-
mods << [:d, first_source, literal(opts[:where])]
|
|
28
|
-
1
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
db = Sequel::Database.new({})
|
|
32
|
-
def db.connect(opts)
|
|
33
|
-
Object.new
|
|
34
|
-
end
|
|
35
|
-
db.meta_def(:dataset) do |*a|
|
|
36
|
-
x = super(*a)
|
|
37
|
-
x.extend(ds_mod)
|
|
38
|
-
x
|
|
4
|
+
def check_sqls(should, is)
|
|
5
|
+
if should.is_a?(Array)
|
|
6
|
+
should.should include(is)
|
|
7
|
+
else
|
|
8
|
+
should.should == is
|
|
39
9
|
end
|
|
40
|
-
|
|
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))
|
|
41
21
|
@c.plugin :nested_attributes
|
|
42
22
|
@Artist = Class.new(@c).set_dataset(:artists)
|
|
43
23
|
@Album = Class.new(@c).set_dataset(:albums)
|
|
44
24
|
@Tag = Class.new(@c).set_dataset(:tags)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
25
|
+
@Artist.plugin :skip_create_refresh
|
|
26
|
+
@Album.plugin :skip_create_refresh
|
|
27
|
+
@Tag.plugin :skip_create_refresh
|
|
48
28
|
@Artist.columns :id, :name
|
|
49
29
|
@Album.columns :id, :name, :artist_id
|
|
50
30
|
@Tag.columns :id, :name
|
|
@@ -54,36 +34,44 @@ describe "NestedAttributes plugin" do
|
|
|
54
34
|
@Album.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:at
|
|
55
35
|
@Artist.nested_attributes :albums, :first_album, :destroy=>true, :remove=>true
|
|
56
36
|
@Album.nested_attributes :artist, :tags, :destroy=>true, :remove=>true
|
|
37
|
+
@db.sqls
|
|
57
38
|
end
|
|
58
39
|
|
|
59
40
|
it "should support creating new many_to_one objects" do
|
|
60
41
|
a = @Album.new({:name=>'Al', :artist_attributes=>{:name=>'Ar'}})
|
|
61
|
-
@
|
|
42
|
+
@db.sqls.should == []
|
|
62
43
|
a.save
|
|
63
|
-
|
|
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')"])
|
|
64
46
|
end
|
|
65
47
|
|
|
66
48
|
it "should support creating new one_to_one objects" do
|
|
67
49
|
a = @Artist.new(:name=>'Ar')
|
|
68
50
|
a.id = 1
|
|
69
51
|
a.first_album_attributes = {:name=>'Al'}
|
|
70
|
-
@
|
|
52
|
+
@db.sqls.should == []
|
|
71
53
|
a.save
|
|
72
|
-
|
|
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)"])
|
|
73
58
|
end
|
|
74
59
|
|
|
75
60
|
it "should support creating new one_to_many objects" do
|
|
76
61
|
a = @Artist.new({:name=>'Ar', :albums_attributes=>[{:name=>'Al'}]})
|
|
77
|
-
@
|
|
62
|
+
@db.sqls.should == []
|
|
78
63
|
a.save
|
|
79
|
-
|
|
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)"])
|
|
80
66
|
end
|
|
81
67
|
|
|
82
68
|
it "should support creating new many_to_many objects" do
|
|
83
69
|
a = @Album.new({:name=>'Al', :tags_attributes=>[{:name=>'T'}]})
|
|
84
|
-
@
|
|
70
|
+
@db.sqls.should == []
|
|
85
71
|
a.save
|
|
86
|
-
|
|
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)"])
|
|
87
75
|
end
|
|
88
76
|
|
|
89
77
|
it "should add new objects to the cached association array as soon as the *_attributes= method is called" do
|
|
@@ -97,9 +85,9 @@ describe "NestedAttributes plugin" do
|
|
|
97
85
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
98
86
|
al.associations[:artist] = ar
|
|
99
87
|
al.set(:artist_attributes=>{:id=>'20', :name=>'Ar2'})
|
|
100
|
-
@
|
|
88
|
+
@db.sqls.should == []
|
|
101
89
|
al.save
|
|
102
|
-
@
|
|
90
|
+
@db.sqls.should == ["UPDATE albums SET name = 'Al' WHERE (id = 10)", "UPDATE artists SET name = 'Ar2' WHERE (id = 20)"]
|
|
103
91
|
end
|
|
104
92
|
|
|
105
93
|
it "should support updating one_to_one objects" do
|
|
@@ -107,9 +95,9 @@ describe "NestedAttributes plugin" do
|
|
|
107
95
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
108
96
|
ar.associations[:first_album] = al
|
|
109
97
|
ar.set(:first_album_attributes=>{:id=>10, :name=>'Al2'})
|
|
110
|
-
@
|
|
98
|
+
@db.sqls.should == []
|
|
111
99
|
ar.save
|
|
112
|
-
@
|
|
100
|
+
@db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "UPDATE albums SET name = 'Al2' WHERE (id = 10)"]
|
|
113
101
|
end
|
|
114
102
|
|
|
115
103
|
it "should support updating one_to_many objects" do
|
|
@@ -117,9 +105,9 @@ describe "NestedAttributes plugin" do
|
|
|
117
105
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
118
106
|
ar.associations[:albums] = [al]
|
|
119
107
|
ar.set(:albums_attributes=>[{:id=>10, :name=>'Al2'}])
|
|
120
|
-
@
|
|
108
|
+
@db.sqls.should == []
|
|
121
109
|
ar.save
|
|
122
|
-
@
|
|
110
|
+
@db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "UPDATE albums SET name = 'Al2' WHERE (id = 10)"]
|
|
123
111
|
end
|
|
124
112
|
|
|
125
113
|
it "should support updating many_to_many objects" do
|
|
@@ -127,9 +115,9 @@ describe "NestedAttributes plugin" do
|
|
|
127
115
|
t = @Tag.load(:id=>20, :name=>'T')
|
|
128
116
|
a.associations[:tags] = [t]
|
|
129
117
|
a.set(:tags_attributes=>[{:id=>20, :name=>'T2'}])
|
|
130
|
-
@
|
|
118
|
+
@db.sqls.should == []
|
|
131
119
|
a.save
|
|
132
|
-
@
|
|
120
|
+
@db.sqls.should == ["UPDATE albums SET name = 'Al' WHERE (id = 10)", "UPDATE tags SET name = 'T2' WHERE (id = 20)"]
|
|
133
121
|
end
|
|
134
122
|
|
|
135
123
|
it "should support removing many_to_one objects" do
|
|
@@ -137,9 +125,9 @@ describe "NestedAttributes plugin" do
|
|
|
137
125
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
138
126
|
al.associations[:artist] = ar
|
|
139
127
|
al.set(:artist_attributes=>{:id=>'20', :_remove=>'1'})
|
|
140
|
-
@
|
|
128
|
+
@db.sqls.should == []
|
|
141
129
|
al.save
|
|
142
|
-
|
|
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)"])
|
|
143
131
|
end
|
|
144
132
|
|
|
145
133
|
it "should support removing one_to_one objects" do
|
|
@@ -147,10 +135,9 @@ describe "NestedAttributes plugin" do
|
|
|
147
135
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
148
136
|
ar.associations[:first_album] = al
|
|
149
137
|
ar.set(:first_album_attributes=>{:id=>10, :_remove=>'t'})
|
|
150
|
-
@
|
|
138
|
+
@db.sqls.should == []
|
|
151
139
|
ar.save
|
|
152
|
-
@
|
|
153
|
-
|
|
140
|
+
@db.sqls.should == ["UPDATE albums SET artist_id = NULL WHERE (artist_id = 20)", "UPDATE artists SET name = 'Ar' WHERE (id = 20)"]
|
|
154
141
|
end
|
|
155
142
|
|
|
156
143
|
it "should support removing one_to_many objects" do
|
|
@@ -158,9 +145,12 @@ describe "NestedAttributes plugin" do
|
|
|
158
145
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
159
146
|
ar.associations[:albums] = [al]
|
|
160
147
|
ar.set(:albums_attributes=>[{:id=>10, :_remove=>'t'}])
|
|
161
|
-
@
|
|
148
|
+
@db.sqls.should == []
|
|
149
|
+
@Album.dataset._fetch = {:id=>1}
|
|
162
150
|
ar.save
|
|
163
|
-
|
|
151
|
+
check_sql_array("SELECT 1 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)")
|
|
164
154
|
end
|
|
165
155
|
|
|
166
156
|
it "should support removing many_to_many objects" do
|
|
@@ -168,9 +158,9 @@ describe "NestedAttributes plugin" do
|
|
|
168
158
|
t = @Tag.load(:id=>20, :name=>'T')
|
|
169
159
|
a.associations[:tags] = [t]
|
|
170
160
|
a.set(:tags_attributes=>[{:id=>20, :_remove=>true}])
|
|
171
|
-
@
|
|
161
|
+
@db.sqls.should == []
|
|
172
162
|
a.save
|
|
173
|
-
@
|
|
163
|
+
@db.sqls.should == ["DELETE FROM at WHERE ((album_id = 10) AND (tag_id = 20))", "UPDATE albums SET name = 'Al' WHERE (id = 10)"]
|
|
174
164
|
end
|
|
175
165
|
|
|
176
166
|
it "should support destroying many_to_one objects" do
|
|
@@ -178,9 +168,10 @@ describe "NestedAttributes plugin" do
|
|
|
178
168
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
179
169
|
al.associations[:artist] = ar
|
|
180
170
|
al.set(:artist_attributes=>{:id=>'20', :_delete=>'1'})
|
|
181
|
-
@
|
|
171
|
+
@db.sqls.should == []
|
|
182
172
|
al.save
|
|
183
|
-
|
|
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)")
|
|
184
175
|
end
|
|
185
176
|
|
|
186
177
|
it "should support destroying one_to_one objects" do
|
|
@@ -188,9 +179,9 @@ describe "NestedAttributes plugin" do
|
|
|
188
179
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
189
180
|
ar.associations[:first_album] = al
|
|
190
181
|
ar.set(:first_album_attributes=>{:id=>10, :_delete=>'t'})
|
|
191
|
-
@
|
|
182
|
+
@db.sqls.should == []
|
|
192
183
|
ar.save
|
|
193
|
-
@
|
|
184
|
+
@db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "DELETE FROM albums WHERE (id = 10)"]
|
|
194
185
|
end
|
|
195
186
|
|
|
196
187
|
it "should support destroying one_to_many objects" do
|
|
@@ -198,9 +189,9 @@ describe "NestedAttributes plugin" do
|
|
|
198
189
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
199
190
|
ar.associations[:albums] = [al]
|
|
200
191
|
ar.set(:albums_attributes=>[{:id=>10, :_delete=>'t'}])
|
|
201
|
-
@
|
|
192
|
+
@db.sqls.should == []
|
|
202
193
|
ar.save
|
|
203
|
-
@
|
|
194
|
+
@db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "DELETE FROM albums WHERE (id = 10)"]
|
|
204
195
|
end
|
|
205
196
|
|
|
206
197
|
it "should support destroying many_to_many objects" do
|
|
@@ -208,9 +199,9 @@ describe "NestedAttributes plugin" do
|
|
|
208
199
|
t = @Tag.load(:id=>20, :name=>'T')
|
|
209
200
|
a.associations[:tags] = [t]
|
|
210
201
|
a.set(:tags_attributes=>[{:id=>20, :_delete=>true}])
|
|
211
|
-
@
|
|
202
|
+
@db.sqls.should == []
|
|
212
203
|
a.save
|
|
213
|
-
@
|
|
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)"]
|
|
214
205
|
end
|
|
215
206
|
|
|
216
207
|
it "should support both string and symbol keys in nested attribute hashes" do
|
|
@@ -218,9 +209,9 @@ describe "NestedAttributes plugin" do
|
|
|
218
209
|
t = @Tag.load(:id=>20, :name=>'T')
|
|
219
210
|
a.associations[:tags] = [t]
|
|
220
211
|
a.set('tags_attributes'=>[{'id'=>20, '_delete'=>true}])
|
|
221
|
-
@
|
|
212
|
+
@db.sqls.should == []
|
|
222
213
|
a.save
|
|
223
|
-
@
|
|
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)"]
|
|
224
215
|
end
|
|
225
216
|
|
|
226
217
|
it "should support using a hash instead of an array for to_many nested attributes" do
|
|
@@ -228,9 +219,9 @@ describe "NestedAttributes plugin" do
|
|
|
228
219
|
t = @Tag.load(:id=>20, :name=>'T')
|
|
229
220
|
a.associations[:tags] = [t]
|
|
230
221
|
a.set('tags_attributes'=>{'1'=>{'id'=>20, '_delete'=>true}})
|
|
231
|
-
@
|
|
222
|
+
@db.sqls.should == []
|
|
232
223
|
a.save
|
|
233
|
-
@
|
|
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)"]
|
|
234
225
|
end
|
|
235
226
|
|
|
236
227
|
it "should only allow destroying associated objects if :destroy option is used in the nested_attributes call" do
|
|
@@ -267,9 +258,9 @@ describe "NestedAttributes plugin" do
|
|
|
267
258
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
268
259
|
ar.associations[:albums] = [al]
|
|
269
260
|
ar.set(:albums_attributes=>[{:id=>30, :_delete=>'t'}])
|
|
270
|
-
@
|
|
261
|
+
@db.sqls.should == []
|
|
271
262
|
ar.save
|
|
272
|
-
@
|
|
263
|
+
@db.sqls.should == ["UPDATE artists SET name = 'Ar' WHERE (id = 20)"]
|
|
273
264
|
end
|
|
274
265
|
|
|
275
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
|
|
@@ -280,10 +271,10 @@ describe "NestedAttributes plugin" do
|
|
|
280
271
|
end
|
|
281
272
|
end
|
|
282
273
|
a = @Album.new(:name=>'Al', :artist_attributes=>{:name=>'Ar'})
|
|
283
|
-
@
|
|
274
|
+
@db.sqls.should == []
|
|
284
275
|
proc{a.save}.should raise_error(Sequel::ValidationFailed)
|
|
285
276
|
a.errors.full_messages.should == ['artist name cannot be Ar']
|
|
286
|
-
@
|
|
277
|
+
@db.sqls.should == []
|
|
287
278
|
# Should preserve attributes
|
|
288
279
|
a.artist.name.should == 'Ar'
|
|
289
280
|
end
|
|
@@ -298,9 +289,10 @@ describe "NestedAttributes plugin" do
|
|
|
298
289
|
end
|
|
299
290
|
end
|
|
300
291
|
a = @Album.new(:name=>'Al', :artist_attributes=>{:name=>'Ar'})
|
|
301
|
-
@
|
|
292
|
+
@db.sqls.should == []
|
|
302
293
|
a.save
|
|
303
|
-
|
|
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)"])
|
|
304
296
|
end
|
|
305
297
|
|
|
306
298
|
it "should not attempt to validate nested attributes if the :validate=>false option is passed to save" do
|
|
@@ -311,23 +303,25 @@ describe "NestedAttributes plugin" do
|
|
|
311
303
|
end
|
|
312
304
|
end
|
|
313
305
|
a = @Album.new(:name=>'Al', :artist_attributes=>{:name=>'Ar'})
|
|
314
|
-
@
|
|
306
|
+
@db.sqls.should == []
|
|
315
307
|
a.save(:validate=>false)
|
|
316
|
-
|
|
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)"])
|
|
317
310
|
end
|
|
318
311
|
|
|
319
312
|
it "should not accept nested attributes unless explicitly specified" do
|
|
320
313
|
@Artist.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:at
|
|
321
314
|
proc{@Artist.create({:name=>'Ar', :tags_attributes=>[{:name=>'T'}]})}.should raise_error(Sequel::Error)
|
|
322
|
-
@
|
|
315
|
+
@db.sqls.should == []
|
|
323
316
|
end
|
|
324
317
|
|
|
325
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
|
|
326
319
|
al = @Album.load(:id=>10, :name=>'Al')
|
|
327
320
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
|
328
321
|
al.associations[:artist] = ar
|
|
322
|
+
@db.sqls.should == []
|
|
329
323
|
al.update(:artist_attributes=>{:id=>'20', :name=>'Ar2'})
|
|
330
|
-
@
|
|
324
|
+
@db.sqls.should == ["UPDATE artists SET name = 'Ar2' WHERE (id = 20)"]
|
|
331
325
|
end
|
|
332
326
|
|
|
333
327
|
it "should have a :limit option limiting the amount of entries" do
|
|
@@ -335,17 +329,25 @@ describe "NestedAttributes plugin" do
|
|
|
335
329
|
arr = [{:name=>'T'}]
|
|
336
330
|
proc{@Album.new({:name=>'Al', :tags_attributes=>arr*3})}.should raise_error(Sequel::Error)
|
|
337
331
|
a = @Album.new({:name=>'Al', :tags_attributes=>arr*2})
|
|
338
|
-
@
|
|
332
|
+
@db.sqls.should == []
|
|
339
333
|
a.save
|
|
340
|
-
|
|
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)"])
|
|
341
339
|
end
|
|
342
340
|
|
|
343
341
|
it "should accept a block that each hash gets passed to determine if it should be processed" do
|
|
344
342
|
@Album.nested_attributes(:tags){|h| h[:name].empty?}
|
|
345
343
|
a = @Album.new({:name=>'Al', :tags_attributes=>[{:name=>'T'}, {:name=>''}, {:name=>'T2'}]})
|
|
346
|
-
@
|
|
344
|
+
@db.sqls.should == []
|
|
347
345
|
a.save
|
|
348
|
-
|
|
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)"])
|
|
349
351
|
end
|
|
350
352
|
|
|
351
353
|
it "should return objects created/modified in the internal methods" do
|
|
@@ -391,9 +393,12 @@ describe "NestedAttributes plugin" do
|
|
|
391
393
|
t = @Tag.load(:id=>30, :name=>'T', :number=>10)
|
|
392
394
|
al.associations[:tags] = [t]
|
|
393
395
|
al.set(:tags_attributes=>[{:id=>30, :name=>'T2'}, {:name=>'T3'}])
|
|
394
|
-
@
|
|
396
|
+
@db.sqls.should == []
|
|
395
397
|
al.save
|
|
396
|
-
|
|
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)"])
|
|
397
402
|
proc{al.set(:tags_attributes=>[{:id=>30, :name=>'T2', :number=>3}])}.should raise_error(Sequel::Error)
|
|
398
403
|
proc{al.set(:tags_attributes=>[{:name=>'T2', :number=>3}])}.should raise_error(Sequel::Error)
|
|
399
404
|
end
|