sequel 4.45.0 → 4.46.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +108 -0
  3. data/doc/release_notes/4.46.0.txt +404 -0
  4. data/doc/security.rdoc +9 -0
  5. data/doc/sql.rdoc +2 -2
  6. data/doc/testing.rdoc +1 -1
  7. data/doc/validations.rdoc +1 -2
  8. data/lib/sequel/adapters/ado.rb +8 -3
  9. data/lib/sequel/adapters/ado/access.rb +8 -4
  10. data/lib/sequel/adapters/ado/mssql.rb +3 -1
  11. data/lib/sequel/adapters/amalgalite.rb +5 -0
  12. data/lib/sequel/adapters/cubrid.rb +16 -7
  13. data/lib/sequel/adapters/do.rb +7 -1
  14. data/lib/sequel/adapters/do/mysql.rb +8 -4
  15. data/lib/sequel/adapters/ibmdb.rb +10 -5
  16. data/lib/sequel/adapters/jdbc.rb +8 -2
  17. data/lib/sequel/adapters/jdbc/as400.rb +10 -3
  18. data/lib/sequel/adapters/jdbc/db2.rb +27 -16
  19. data/lib/sequel/adapters/jdbc/derby.rb +47 -20
  20. data/lib/sequel/adapters/jdbc/h2.rb +13 -7
  21. data/lib/sequel/adapters/jdbc/hsqldb.rb +18 -9
  22. data/lib/sequel/adapters/jdbc/mssql.rb +5 -2
  23. data/lib/sequel/adapters/jdbc/mysql.rb +3 -2
  24. data/lib/sequel/adapters/jdbc/oracle.rb +3 -2
  25. data/lib/sequel/adapters/jdbc/postgresql.rb +4 -3
  26. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +2 -1
  27. data/lib/sequel/adapters/jdbc/sqlite.rb +10 -3
  28. data/lib/sequel/adapters/jdbc/sqlserver.rb +23 -0
  29. data/lib/sequel/adapters/jdbc/transactions.rb +16 -10
  30. data/lib/sequel/adapters/mock.rb +5 -0
  31. data/lib/sequel/adapters/mysql.rb +8 -1
  32. data/lib/sequel/adapters/mysql2.rb +6 -1
  33. data/lib/sequel/adapters/odbc.rb +20 -8
  34. data/lib/sequel/adapters/odbc/mssql.rb +6 -3
  35. data/lib/sequel/adapters/oracle.rb +12 -6
  36. data/lib/sequel/adapters/postgres.rb +20 -8
  37. data/lib/sequel/adapters/shared/access.rb +76 -47
  38. data/lib/sequel/adapters/shared/cubrid.rb +16 -11
  39. data/lib/sequel/adapters/shared/db2.rb +46 -19
  40. data/lib/sequel/adapters/shared/firebird.rb +20 -8
  41. data/lib/sequel/adapters/shared/informix.rb +6 -3
  42. data/lib/sequel/adapters/shared/mssql.rb +132 -72
  43. data/lib/sequel/adapters/shared/mysql.rb +112 -65
  44. data/lib/sequel/adapters/shared/oracle.rb +36 -21
  45. data/lib/sequel/adapters/shared/postgres.rb +91 -56
  46. data/lib/sequel/adapters/shared/sqlanywhere.rb +65 -37
  47. data/lib/sequel/adapters/shared/sqlite.rb +67 -32
  48. data/lib/sequel/adapters/sqlanywhere.rb +9 -1
  49. data/lib/sequel/adapters/sqlite.rb +8 -1
  50. data/lib/sequel/adapters/swift.rb +5 -0
  51. data/lib/sequel/adapters/swift/mysql.rb +4 -2
  52. data/lib/sequel/adapters/swift/sqlite.rb +1 -1
  53. data/lib/sequel/adapters/tinytds.rb +10 -3
  54. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
  55. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
  56. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -0
  57. data/lib/sequel/adapters/utils/pg_types.rb +14 -6
  58. data/lib/sequel/adapters/utils/replace.rb +4 -2
  59. data/lib/sequel/connection_pool/single.rb +2 -2
  60. data/lib/sequel/core.rb +24 -11
  61. data/lib/sequel/database/connecting.rb +9 -3
  62. data/lib/sequel/database/dataset_defaults.rb +7 -1
  63. data/lib/sequel/database/logging.rb +1 -0
  64. data/lib/sequel/database/misc.rb +5 -2
  65. data/lib/sequel/database/query.rb +7 -5
  66. data/lib/sequel/database/schema_generator.rb +1 -0
  67. data/lib/sequel/database/schema_methods.rb +50 -27
  68. data/lib/sequel/database/transactions.rb +19 -9
  69. data/lib/sequel/dataset/actions.rb +15 -6
  70. data/lib/sequel/dataset/graph.rb +15 -5
  71. data/lib/sequel/dataset/misc.rb +12 -4
  72. data/lib/sequel/dataset/mutation.rb +17 -8
  73. data/lib/sequel/dataset/prepared_statements.rb +3 -2
  74. data/lib/sequel/dataset/query.rb +84 -38
  75. data/lib/sequel/dataset/sql.rb +302 -191
  76. data/lib/sequel/deprecated.rb +26 -17
  77. data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +2 -2
  78. data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
  79. data/lib/sequel/extensions/from_block.rb +1 -0
  80. data/lib/sequel/extensions/graph_each.rb +1 -1
  81. data/lib/sequel/extensions/identifier_mangling.rb +2 -2
  82. data/lib/sequel/extensions/migration.rb +28 -4
  83. data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -0
  84. data/lib/sequel/extensions/schema_dumper.rb +4 -4
  85. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +5 -3
  86. data/lib/sequel/extensions/set_overrides.rb +2 -0
  87. data/lib/sequel/extensions/split_array_nil.rb +2 -2
  88. data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
  89. data/lib/sequel/model.rb +11 -7
  90. data/lib/sequel/model/associations.rb +5 -7
  91. data/lib/sequel/model/base.rb +47 -45
  92. data/lib/sequel/model/dataset_module.rb +9 -14
  93. data/lib/sequel/model/plugins.rb +3 -0
  94. data/lib/sequel/no_core_ext.rb +1 -0
  95. data/lib/sequel/plugins/blacklist_security.rb +1 -1
  96. data/lib/sequel/plugins/boolean_subsets.rb +7 -5
  97. data/lib/sequel/plugins/class_table_inheritance.rb +47 -10
  98. data/lib/sequel/plugins/dataset_associations.rb +1 -1
  99. data/lib/sequel/plugins/def_dataset_method.rb +90 -0
  100. data/lib/sequel/plugins/finder.rb +240 -0
  101. data/lib/sequel/plugins/inverted_subsets.rb +19 -12
  102. data/lib/sequel/plugins/many_through_many.rb +1 -1
  103. data/lib/sequel/plugins/nested_attributes.rb +1 -1
  104. data/lib/sequel/plugins/schema.rb +1 -1
  105. data/lib/sequel/plugins/single_table_inheritance.rb +7 -1
  106. data/lib/sequel/plugins/subset_conditions.rb +11 -3
  107. data/lib/sequel/plugins/whitelist_security.rb +118 -0
  108. data/lib/sequel/sql.rb +80 -36
  109. data/lib/sequel/timezones.rb +2 -0
  110. data/lib/sequel/version.rb +1 -1
  111. data/spec/adapters/mssql_spec.rb +20 -0
  112. data/spec/adapters/mysql_spec.rb +1 -1
  113. data/spec/adapters/oracle_spec.rb +12 -8
  114. data/spec/adapters/postgres_spec.rb +1 -1
  115. data/spec/adapters/spec_helper.rb +1 -1
  116. data/spec/adapters/sqlite_spec.rb +36 -34
  117. data/spec/core/connection_pool_spec.rb +2 -1
  118. data/spec/core/database_spec.rb +87 -9
  119. data/spec/core/dataset_spec.rb +501 -129
  120. data/spec/core/deprecated_spec.rb +1 -1
  121. data/spec/core/expression_filters_spec.rb +146 -60
  122. data/spec/core/mock_adapter_spec.rb +1 -1
  123. data/spec/core/object_graph_spec.rb +61 -9
  124. data/spec/core/placeholder_literalizer_spec.rb +20 -2
  125. data/spec/core/schema_generator_spec.rb +6 -6
  126. data/spec/core/schema_spec.rb +54 -5
  127. data/spec/core_extensions_spec.rb +122 -18
  128. data/spec/deprecation_helper.rb +27 -2
  129. data/spec/extensions/_deprecated_identifier_mangling_spec.rb +6 -6
  130. data/spec/extensions/association_proxies_spec.rb +2 -2
  131. data/spec/extensions/auto_literal_strings_spec.rb +212 -0
  132. data/spec/extensions/blacklist_security_spec.rb +1 -0
  133. data/spec/extensions/class_table_inheritance_spec.rb +1037 -39
  134. data/spec/extensions/column_select_spec.rb +20 -8
  135. data/spec/extensions/columns_introspection_spec.rb +3 -3
  136. data/spec/extensions/core_refinements_spec.rb +29 -12
  137. data/spec/extensions/dataset_associations_spec.rb +12 -12
  138. data/spec/extensions/def_dataset_method_spec.rb +100 -0
  139. data/spec/extensions/error_sql_spec.rb +1 -1
  140. data/spec/extensions/finder_spec.rb +260 -0
  141. data/spec/extensions/graph_each_spec.rb +2 -2
  142. data/spec/extensions/identifier_mangling_spec.rb +14 -8
  143. data/spec/extensions/inverted_subsets_spec.rb +4 -4
  144. data/spec/extensions/lazy_attributes_spec.rb +7 -0
  145. data/spec/extensions/many_through_many_spec.rb +38 -14
  146. data/spec/extensions/nested_attributes_spec.rb +18 -6
  147. data/spec/extensions/no_auto_literal_strings_spec.rb +1 -1
  148. data/spec/extensions/pg_enum_spec.rb +16 -1
  149. data/spec/extensions/pg_interval_spec.rb +11 -2
  150. data/spec/extensions/pg_loose_count_spec.rb +5 -0
  151. data/spec/extensions/pg_row_spec.rb +25 -0
  152. data/spec/extensions/prepared_statements_spec.rb +10 -1
  153. data/spec/extensions/query_spec.rb +2 -2
  154. data/spec/extensions/schema_dumper_spec.rb +2 -2
  155. data/spec/extensions/schema_spec.rb +2 -2
  156. data/spec/extensions/set_overrides_spec.rb +7 -3
  157. data/spec/extensions/sql_expr_spec.rb +0 -1
  158. data/spec/extensions/subset_conditions_spec.rb +6 -6
  159. data/spec/extensions/table_select_spec.rb +24 -12
  160. data/spec/extensions/to_dot_spec.rb +4 -4
  161. data/spec/extensions/whitelist_security_spec.rb +131 -0
  162. data/spec/integration/dataset_test.rb +9 -5
  163. data/spec/integration/model_test.rb +2 -0
  164. data/spec/integration/plugin_test.rb +2 -2
  165. data/spec/integration/spec_helper.rb +1 -1
  166. data/spec/model/associations_spec.rb +39 -11
  167. data/spec/model/base_spec.rb +44 -24
  168. data/spec/model/class_dataset_methods_spec.rb +18 -16
  169. data/spec/model/dataset_methods_spec.rb +4 -4
  170. data/spec/model/eager_loading_spec.rb +84 -24
  171. data/spec/model/model_spec.rb +97 -63
  172. data/spec/model/record_spec.rb +21 -13
  173. metadata +13 -2
@@ -38,7 +38,7 @@ describe Sequel::Dataset, " graphing" do
38
38
 
39
39
  @ds1.graph(@ds2, :x=>:id).all.must_equal [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}}]
40
40
  @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id).all.must_equal [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}]
41
- @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph).all.must_equal [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graph=>{:id=>8, :x=>9, :y=>10, :graph_id=>11}}]
41
+ @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>Sequel[:points][:id]}, :table_alias=>:graph).all.must_equal [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graph=>{:id=>8, :x=>9, :y=>10, :graph_id=>11}}]
42
42
  end
43
43
 
44
44
  it "#graph_each should split the result set into component tables when using first" do
@@ -48,7 +48,7 @@ describe Sequel::Dataset, " graphing" do
48
48
 
49
49
  @ds1.graph(@ds2, :x=>:id).first.must_equal(:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7})
50
50
  @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id).first.must_equal(:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12})
51
- @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph).first.must_equal(:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graph=>{:id=>8, :x=>9, :y=>10, :graph_id=>11})
51
+ @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>Sequel[:points][:id]}, :table_alias=>:graph).first.must_equal(:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graph=>{:id=>8, :x=>9, :y=>10, :graph_id=>11})
52
52
  end
53
53
 
54
54
  it "#graph_each should give a nil value instead of a hash when all values for a table are nil" do
@@ -24,7 +24,8 @@ describe "identifier_mangling extension" do
24
24
  end
25
25
 
26
26
  it "should upcase on input and downcase on output by default" do
27
- db = Sequel::Database.new.extension(:identifier_mangling)
27
+ # SEQUEL5: Remove :identifier_mangling=>false
28
+ db = Sequel::Database.new(:identifier_mangling=>false).extension(:identifier_mangling)
28
29
  db.send(:identifier_input_method_default).must_equal :upcase
29
30
  db.send(:identifier_output_method_default).must_equal :downcase
30
31
  end
@@ -141,9 +142,9 @@ describe "identifier_mangling extension" do
141
142
  deprecated "should respect the quote_indentifiers_default method if Sequel.quote_identifiers = nil" do
142
143
  Sequel.quote_identifiers = nil
143
144
  Sequel::Database.new.extension(:identifier_mangling).quote_identifiers?.must_equal true
144
- x = Class.new(Sequel::Database){def quote_identifiers_default; false end}
145
+ x = Class.new(Sequel::Database){def dataset_class_default; Sequel::Dataset end; def quote_identifiers_default; false end}
145
146
  x.new.extension(:identifier_mangling).quote_identifiers?.must_equal false
146
- y = Class.new(Sequel::Database){def quote_identifiers_default; true end}
147
+ y = Class.new(Sequel::Database){def dataset_class_default; Sequel::Dataset end; def quote_identifiers_default; true end}
147
148
  y.new.extension(:identifier_mangling).quote_identifiers?.must_equal true
148
149
  end
149
150
 
@@ -151,9 +152,9 @@ describe "identifier_mangling extension" do
151
152
  class Sequel::Database
152
153
  @identifier_input_method = nil
153
154
  end
154
- x = Class.new(Sequel::Database){def identifier_input_method_default; :downcase end}
155
+ x = Class.new(Sequel::Database){def dataset_class_default; Sequel::Dataset end; def identifier_input_method_default; :downcase end}
155
156
  x.new.extension(:identifier_mangling).identifier_input_method.must_equal :downcase
156
- y = Class.new(Sequel::Database){def identifier_input_method_default; :camelize end}
157
+ y = Class.new(Sequel::Database){def dataset_class_default; Sequel::Dataset end; def identifier_input_method_default; :camelize end}
157
158
  y.new.extension(:identifier_mangling).identifier_input_method.must_equal :camelize
158
159
  end
159
160
 
@@ -161,9 +162,9 @@ describe "identifier_mangling extension" do
161
162
  class Sequel::Database
162
163
  @identifier_output_method = nil
163
164
  end
164
- x = Class.new(Sequel::Database){def identifier_output_method_default; :upcase end}
165
+ x = Class.new(Sequel::Database){def dataset_class_default; Sequel::Dataset end; def identifier_output_method_default; :upcase end}
165
166
  x.new.extension(:identifier_mangling).identifier_output_method.must_equal :upcase
166
- y = Class.new(Sequel::Database){def identifier_output_method_default; :underscore end}
167
+ y = Class.new(Sequel::Database){def dataset_class_default; Sequel::Dataset end; def identifier_output_method_default; :underscore end}
167
168
  y.new.extension(:identifier_mangling).identifier_output_method.must_equal :underscore
168
169
  end
169
170
  end
@@ -315,7 +316,7 @@ describe "identifier_mangling extension" do
315
316
  Sequel.mock(:host=>'oracle')[:a].limit(1).sql.must_equal 'SELECT * FROM (SELECT * FROM "A") "T1" WHERE (ROWNUM <= 1)'
316
317
  Sequel.mock(:host=>'postgres')[:a].full_text_search(:b, 'c').sql.must_equal "SELECT * FROM \"a\" WHERE (to_tsvector(CAST('simple' AS regconfig), (COALESCE(\"b\", ''))) @@ to_tsquery(CAST('simple' AS regconfig), 'c'))"
317
318
  Sequel.mock(:host=>'sqlanywhere').from(:a).offset(1).sql.must_equal 'SELECT TOP 2147483647 START AT (1 + 1) * FROM "A"'
318
- Sequel.mock(:host=>'sqlite')[:a___b].sql.must_equal "SELECT * FROM `a` AS 'b'"
319
+ Sequel.mock(:host=>'sqlite')[Sequel[:a].as(:b)].sql.must_equal "SELECT * FROM `a` AS 'b'"
319
320
  ensure
320
321
  deprecated do
321
322
  Sequel.quote_identifiers = qi
@@ -341,7 +342,12 @@ describe Sequel::Model, ".[] optimization" do
341
342
  @c.simple_table.must_equal '"ba"'
342
343
  @c.set_primary_key :cd
343
344
  @c.simple_pk.must_equal '"dc"'
345
+ @c.set_dataset ds.from(Sequel[:ef][:gh])
346
+ @c.simple_table.must_equal '"fe"."hg"'
347
+ end
344
348
 
349
+ with_symbol_splitting "should have simple_pk and simple_table respect dataset's identifier input methods when using splittable symbols" do
350
+ ds = @db.from(:ab).with_identifier_input_method(:reverse)
345
351
  @c.set_dataset ds.from(:ef__gh)
346
352
  @c.simple_table.must_equal '"fe"."hg"'
347
353
  end
@@ -4,21 +4,21 @@ describe "Sequel::Plugins::InvertedSubsets" do
4
4
  it "should add an inverted subset method which inverts the condition" do
5
5
  c = Class.new(Sequel::Model(:a))
6
6
  c.plugin :inverted_subsets
7
- c.subset(:published, :published => true)
7
+ c.dataset_module{subset(:published, :published => true)}
8
8
  c.not_published.sql.must_equal 'SELECT * FROM a WHERE (published IS NOT TRUE)'
9
9
  end
10
10
 
11
11
  it "should support a configuration block to customise the inverted method name" do
12
12
  c = Class.new(Sequel::Model(:a))
13
13
  c.plugin(:inverted_subsets){|name| "exclude_#{name}"}
14
- c.subset(:published, :published => true)
14
+ c.dataset_module{where(:published, :published => true)}
15
15
  c.exclude_published.sql.must_equal 'SELECT * FROM a WHERE (published IS NOT TRUE)'
16
16
  end
17
17
 
18
18
  it "should chain to existing dataset" do
19
19
  c = Class.new(Sequel::Model(:a))
20
20
  c.plugin :inverted_subsets
21
- c.subset(:published, :published => true)
21
+ c.dataset_module{where(:published, :published => true)}
22
22
  c.where(1=>0).not_published.sql.must_equal 'SELECT * FROM a WHERE ((1 = 0) AND (published IS NOT TRUE))'
23
23
  end
24
24
 
@@ -27,7 +27,7 @@ describe "Sequel::Plugins::InvertedSubsets" do
27
27
  c.plugin(:inverted_subsets){|name| "exclude_#{name}"}
28
28
  c = Class.new(c)
29
29
  c.dataset = :a
30
- c.subset(:published, :published => true)
30
+ c.dataset_module{subset(:published, :published => true)}
31
31
  c.exclude_published.sql.must_equal 'SELECT * FROM a WHERE (published IS NOT TRUE)'
32
32
  end
33
33
  end
@@ -63,6 +63,13 @@ describe "Sequel::Plugins::LazyAttributes" do
63
63
  end
64
64
 
65
65
  it "should handle lazy attributes that are qualified in the selection" do
66
+ @c.set_dataset(@ds.select(Sequel[:la][:id], Sequel[:la][:blah]))
67
+ @c.dataset.sql.must_equal 'SELECT la.id, la.blah FROM la'
68
+ @c.plugin :lazy_attributes, :blah
69
+ @c.dataset.sql.must_equal 'SELECT la.id FROM la'
70
+ end
71
+
72
+ with_symbol_splitting "should handle lazy attributes that are qualified in the selection using symbol splitting" do
66
73
  @c.set_dataset(@ds.select(:la__id, :la__blah))
67
74
  @c.dataset.sql.must_equal 'SELECT la.id, la.blah FROM la'
68
75
  @c.plugin :lazy_attributes, :blah
@@ -62,7 +62,7 @@ describe Sequel::Model, "many_through_many" do
62
62
  it "should handle a :eager_loading_predicate_key option to change the SQL used in the lookup" do
63
63
  @c1.dataset = @c1.dataset.with_fetch(:id=>1)
64
64
  @c2.dataset = @c2.dataset.with_fetch(:id=>4, :x_foreign_key_x=>1)
65
- @c1.many_through_many :tags, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager_loading_predicate_key=>Sequel./(:albums_artists__artist_id, 3)
65
+ @c1.many_through_many :tags, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager_loading_predicate_key=>(Sequel[:albums_artists][:artist_id] / 3)
66
66
  a = @c1.eager(:tags).all
67
67
  a.must_equal [@c1.load(:id => 1)]
68
68
  DB.sqls.must_equal ['SELECT * FROM artists', "SELECT tags.*, (albums_artists.artist_id / 3) AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE ((albums_artists.artist_id / 3) IN (1))"]
@@ -70,6 +70,20 @@ describe Sequel::Model, "many_through_many" do
70
70
  end
71
71
 
72
72
  it "should handle schema qualified tables" do
73
+ @c1.many_through_many :tags, :through=>[[Sequel[:myschema][:albums_artists], :artist_id, :album_id], [Sequel[:myschema][:albums], :id, :id], [Sequel[:myschema][:albums_tags], :album_id, :tag_id]]
74
+ @c1.load(:id=>1).tags_dataset.sql.must_equal "SELECT tags.* FROM tags INNER JOIN myschema.albums_tags ON (myschema.albums_tags.tag_id = tags.id) INNER JOIN myschema.albums ON (myschema.albums.id = myschema.albums_tags.album_id) INNER JOIN myschema.albums_artists ON (myschema.albums_artists.album_id = myschema.albums.id) WHERE (myschema.albums_artists.artist_id = 1)"
75
+
76
+ @c1.dataset = @c1.dataset.with_fetch(:id=>1)
77
+ @c2.dataset = @c2.dataset.with_fetch(:id=>4, :x_foreign_key_x=>1)
78
+ a = @c1.eager(:tags).all
79
+ a.must_equal [@c1.load(:id => 1)]
80
+ DB.sqls.must_equal ['SELECT * FROM artists', "SELECT tags.*, myschema.albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN myschema.albums_tags ON (myschema.albums_tags.tag_id = tags.id) INNER JOIN myschema.albums ON (myschema.albums.id = myschema.albums_tags.album_id) INNER JOIN myschema.albums_artists ON (myschema.albums_artists.album_id = myschema.albums.id) WHERE (myschema.albums_artists.artist_id IN (1))"]
81
+
82
+ Tag.dataset.columns(:id, :h1, :h2)
83
+ @c1.eager_graph(:tags).sql.must_equal 'SELECT artists.id, tags.id AS tags_id, tags.h1, tags.h2 FROM artists LEFT OUTER JOIN myschema.albums_artists AS albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN myschema.albums AS albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN myschema.albums_tags AS albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)'
84
+ end
85
+
86
+ with_symbol_splitting "should handle schema qualified table symbols" do
73
87
  @c1.many_through_many :tags, :through=>[[:myschema__albums_artists, :artist_id, :album_id], [:myschema__albums, :id, :id], [:myschema__albums_tags, :album_id, :tag_id]]
74
88
  @c1.load(:id=>1).tags_dataset.sql.must_equal "SELECT tags.* FROM tags INNER JOIN myschema.albums_tags ON (myschema.albums_tags.tag_id = tags.id) INNER JOIN myschema.albums ON (myschema.albums.id = myschema.albums_tags.album_id) INNER JOIN myschema.albums_artists ON (myschema.albums_artists.album_id = myschema.albums.id) WHERE (myschema.albums_artists.artist_id = 1)"
75
89
 
@@ -335,7 +349,7 @@ describe Sequel::Model, "many_through_many" do
335
349
  n.tags_dataset.sql.must_equal 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE ((a = 32) AND (albums_artists.artist_id = 1234))'
336
350
  n.tags.must_equal [@c2.load(:id=>1)]
337
351
 
338
- @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :conditions=>['a = ?', 42]
352
+ @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :conditions=>Sequel.lit('a = ?', 42)
339
353
  n = @c1.load(:id => 1234)
340
354
  n.tags_dataset.sql.must_equal 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE ((a = 42) AND (albums_artists.artist_id = 1234))'
341
355
  n.tags.must_equal [@c2.load(:id=>1)]
@@ -363,7 +377,7 @@ describe Sequel::Model, "many_through_many" do
363
377
  end
364
378
 
365
379
  it "should support an array for the select option" do
366
- @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>[Sequel::SQL::ColumnAll.new(:tags), :albums__name]
380
+ @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>[Sequel::SQL::ColumnAll.new(:tags), Sequel[:albums][:name]]
367
381
  n = @c1.load(:id => 1234)
368
382
  n.tags_dataset.sql.must_equal 'SELECT tags.*, albums.name FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id = 1234)'
369
383
  n.tags.must_equal [@c2.load(:id=>1)]
@@ -386,7 +400,7 @@ describe Sequel::Model, "many_through_many" do
386
400
  end
387
401
 
388
402
  it "should support a :dataset option that is used instead of the default" do
389
- @c1.many_through_many :tags, [[:a, :b, :c]], :dataset=>proc{Tag.join(:albums_tags, [:tag_id]).join(:albums, [:album_id]).join(:albums_artists, [:album_id]).filter(:albums_artists__artist_id=>id)}
403
+ @c1.many_through_many :tags, [[:a, :b, :c]], :dataset=>proc{Tag.join(:albums_tags, [:tag_id]).join(:albums, [:album_id]).join(:albums_artists, [:album_id]).filter(Sequel[:albums_artists][:artist_id]=>id)}
390
404
  n = @c1.load(:id => 1234)
391
405
  n.tags_dataset.sql.must_equal 'SELECT tags.* FROM tags INNER JOIN albums_tags USING (tag_id) INNER JOIN albums USING (album_id) INNER JOIN albums_artists USING (album_id) WHERE (albums_artists.artist_id = 1234)'
392
406
  n.tags.must_equal [@c2.load(:id=>1)]
@@ -839,7 +853,7 @@ describe "many_through_many eager loading methods" do
839
853
  end
840
854
 
841
855
  it "should respect the association's :select option" do
842
- @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>:tags__name
856
+ @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>Sequel[:tags][:name]
843
857
  a = @c1.eager(:tags).all
844
858
  a.must_equal [@c1.load(:id=>1)]
845
859
  DB.sqls.must_equal ['SELECT * FROM artists',
@@ -1103,17 +1117,22 @@ describe "many_through_many eager loading methods" do
1103
1117
 
1104
1118
  it "should respect the association's :order" do
1105
1119
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[:blah1, :blah2]
1106
- @c1.order(:artists__blah2, :artists__blah3).eager_graph(:tags).sql.must_equal 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tags.blah1, tags.blah2'
1120
+ @c1.order(Sequel[:artists][:blah2], Sequel[:artists][:blah3]).eager_graph(:tags).sql.must_equal 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tags.blah1, tags.blah2'
1107
1121
  end
1108
1122
 
1109
- it "should only qualify unqualified symbols, identifiers, or ordered versions in association's :order" do
1123
+ with_symbol_splitting "should not qualify qualified symbols" do
1110
1124
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[Sequel.identifier(:blah__id), Sequel.identifier(:blah__id).desc, Sequel.desc(:blah__id), :blah__id, :album_id, Sequel.desc(:album_id), 1, Sequel.lit('RANDOM()'), Sequel.qualify(:b, :a)]
1111
1125
  @c1.order(:artists__blah2, :artists__blah3).eager_graph(:tags).sql.must_equal 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tags.blah__id, tags.blah__id DESC, blah.id DESC, blah.id, tags.album_id, tags.album_id DESC, 1, RANDOM(), b.a'
1112
1126
  end
1113
1127
 
1128
+ it "should only qualify symbols, identifiers, or ordered versions in association's :order" do
1129
+ @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[Sequel.identifier(:blah__id), Sequel.identifier(:blah__id).desc, Sequel.desc(Sequel[:blah][:id]), Sequel[:blah][:id], :album_id, Sequel.desc(:album_id), 1, Sequel.lit('RANDOM()'), Sequel.qualify(:b, :a)]
1130
+ @c1.order(Sequel[:artists][:blah2], Sequel[:artists][:blah3]).eager_graph(:tags).sql.must_equal 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tags.blah__id, tags.blah__id DESC, blah.id DESC, blah.id, tags.album_id, tags.album_id DESC, 1, RANDOM(), b.a'
1131
+ end
1132
+
1114
1133
  it "should not respect the association's :order if :order_eager_graph is false" do
1115
1134
  @c1.many_through_many :tags, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[:blah1, :blah2], :order_eager_graph=>false
1116
- @c1.order(:artists__blah2, :artists__blah3).eager_graph(:tags).sql.must_equal 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3'
1135
+ @c1.order(Sequel[:artists][:blah2], Sequel[:artists][:blah3]).eager_graph(:tags).sql.must_equal 'SELECT artists.id, tags.id AS tags_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3'
1117
1136
  end
1118
1137
 
1119
1138
  it "should add the associations :order for multiple associations" do
@@ -1215,7 +1234,7 @@ describe Sequel::Model, "one_through_many" do
1215
1234
  it "should handle a :eager_loading_predicate_key option to change the SQL used in the lookup" do
1216
1235
  @c1.dataset = @c1.dataset.with_fetch(:id=>1)
1217
1236
  @c2.dataset = @c2.dataset.with_fetch(:id=>4, :x_foreign_key_x=>1)
1218
- @c1.one_through_many :tag, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager_loading_predicate_key=>Sequel./(:albums_artists__artist_id, 3)
1237
+ @c1.one_through_many :tag, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager_loading_predicate_key=>(Sequel[:albums_artists][:artist_id] / 3)
1219
1238
  a = @c1.eager(:tag).all
1220
1239
  a.must_equal [@c1.load(:id => 1)]
1221
1240
  DB.sqls.must_equal ['SELECT * FROM artists', "SELECT tags.*, (albums_artists.artist_id / 3) AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE ((albums_artists.artist_id / 3) IN (1))"]
@@ -1458,7 +1477,7 @@ describe Sequel::Model, "one_through_many" do
1458
1477
  n.tag_dataset.sql.must_equal 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE ((a = 32) AND (albums_artists.artist_id = 1234)) LIMIT 1'
1459
1478
  n.tag.must_equal @c2.load(:id=>1)
1460
1479
 
1461
- @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :conditions=>['a = ?', 42]
1480
+ @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :conditions=>Sequel.lit('a = ?', 42)
1462
1481
  n = @c1.load(:id => 1234)
1463
1482
  n.tag_dataset.sql.must_equal 'SELECT tags.* FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE ((a = 42) AND (albums_artists.artist_id = 1234)) LIMIT 1'
1464
1483
  n.tag.must_equal @c2.load(:id=>1)
@@ -1486,7 +1505,7 @@ describe Sequel::Model, "one_through_many" do
1486
1505
  end
1487
1506
 
1488
1507
  it "should support an array for the select option" do
1489
- @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>[Sequel::SQL::ColumnAll.new(:tags), :albums__name]
1508
+ @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>[Sequel::SQL::ColumnAll.new(:tags), Sequel[:albums][:name]]
1490
1509
  n = @c1.load(:id => 1234)
1491
1510
  n.tag_dataset.sql.must_equal 'SELECT tags.*, albums.name FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON (albums_artists.album_id = albums.id) WHERE (albums_artists.artist_id = 1234) LIMIT 1'
1492
1511
  n.tag.must_equal @c2.load(:id=>1)
@@ -1509,7 +1528,7 @@ describe Sequel::Model, "one_through_many" do
1509
1528
  end
1510
1529
 
1511
1530
  it "should support a :dataset option that is used instead of the default" do
1512
- @c1.one_through_many :tag, [[:a, :b, :c]], :dataset=>proc{Tag.join(:albums_tags, [:tag_id]).join(:albums, [:album_id]).join(:albums_artists, [:album_id]).filter(:albums_artists__artist_id=>id)}
1531
+ @c1.one_through_many :tag, [[:a, :b, :c]], :dataset=>proc{Tag.join(:albums_tags, [:tag_id]).join(:albums, [:album_id]).join(:albums_artists, [:album_id]).filter(Sequel[:albums_artists][:artist_id]=>id)}
1513
1532
  n = @c1.load(:id => 1234)
1514
1533
  n.tag_dataset.sql.must_equal 'SELECT tags.* FROM tags INNER JOIN albums_tags USING (tag_id) INNER JOIN albums USING (album_id) INNER JOIN albums_artists USING (album_id) WHERE (albums_artists.artist_id = 1234) LIMIT 1'
1515
1534
  n.tag.must_equal @c2.load(:id=>1)
@@ -1856,7 +1875,7 @@ describe "one_through_many eager loading methods" do
1856
1875
  end
1857
1876
 
1858
1877
  it "should respect the association's :select option" do
1859
- @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>:tags__name
1878
+ @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :select=>Sequel[:tags][:name]
1860
1879
  a = @c1.eager(:tag).all
1861
1880
  a.must_equal [@c1.load(:id=>1)]
1862
1881
  DB.sqls.must_equal ['SELECT * FROM artists',
@@ -2107,10 +2126,15 @@ describe "one_through_many eager loading methods" do
2107
2126
 
2108
2127
  it "should respect the association's :order" do
2109
2128
  @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[:blah1, :blah2]
2110
- @c1.order(:artists__blah2, :artists__blah3).eager_graph(:tag).sql.must_equal 'SELECT artists.id, tag.id AS tag_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags AS tag ON (tag.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tag.blah1, tag.blah2'
2129
+ @c1.order(Sequel[:artists][:blah2], Sequel[:artists][:blah3]).eager_graph(:tag).sql.must_equal 'SELECT artists.id, tag.id AS tag_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags AS tag ON (tag.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tag.blah1, tag.blah2'
2111
2130
  end
2112
2131
 
2113
2132
  it "should only qualify unqualified symbols, identifiers, or ordered versions in association's :order" do
2133
+ @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[Sequel.identifier(:blah__id), Sequel.identifier(:blah__id).desc, Sequel.desc(Sequel[:blah][:id]), Sequel[:blah][:id], :album_id, Sequel.desc(:album_id), 1, Sequel.lit('RANDOM()'), Sequel.qualify(:b, :a)]
2134
+ @c1.order(Sequel[:artists][:blah2], Sequel[:artists][:blah3]).eager_graph(:tag).sql.must_equal 'SELECT artists.id, tag.id AS tag_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags AS tag ON (tag.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tag.blah__id, tag.blah__id DESC, blah.id DESC, blah.id, tag.album_id, tag.album_id DESC, 1, RANDOM(), b.a'
2135
+ end
2136
+
2137
+ with_symbol_splitting "should not qualify qualified symbols in association's :order" do
2114
2138
  @c1.one_through_many :tag, [[:albums_artists, :artist_id, :album_id], {:table=>:albums, :left=>:id, :right=>:id}, [:albums_tags, :album_id, :tag_id]], :order=>[Sequel.identifier(:blah__id), Sequel.identifier(:blah__id).desc, Sequel.desc(:blah__id), :blah__id, :album_id, Sequel.desc(:album_id), 1, Sequel.lit('RANDOM()'), Sequel.qualify(:b, :a)]
2115
2139
  @c1.order(:artists__blah2, :artists__blah3).eager_graph(:tag).sql.must_equal 'SELECT artists.id, tag.id AS tag_id FROM artists LEFT OUTER JOIN albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags AS tag ON (tag.id = albums_tags.tag_id) ORDER BY artists.blah2, artists.blah3, tag.blah__id, tag.blah__id DESC, blah.id DESC, blah.id, tag.album_id, tag.album_id DESC, 1, RANDOM(), b.a'
2116
2140
  end
@@ -652,8 +652,12 @@ describe "NestedAttributes plugin" do
652
652
  "UPDATE tags SET name = 'T2' WHERE (id = 30)",
653
653
  "INSERT INTO tags (name) VALUES ('T3')",
654
654
  ["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
655
- proc{al.set(:tags_attributes=>[{:id=>30, :name=>'T2', :number=>3}])}.must_raise(Sequel::MassAssignmentRestriction)
656
- proc{al.set(:tags_attributes=>[{:name=>'T2', :number=>3}])}.must_raise(Sequel::MassAssignmentRestriction)
655
+ al.set(:tags_attributes=>[{:id=>30, :name=>'T3', :number=>3}])
656
+ al.tags.first.name.must_equal 'T3'
657
+ al.tags.first.number.must_equal 10
658
+ al.set(:tags_attributes=>[{:name=>'T4', :number=>3}])
659
+ al.tags.last.name.must_equal 'T4'
660
+ al.tags.last.number.must_be_nil
657
661
  end
658
662
 
659
663
  it "should accept a proc for the :fields option that accepts the associated object and returns an array of fields" do
@@ -670,8 +674,12 @@ describe "NestedAttributes plugin" do
670
674
  "UPDATE tags SET name = 'T2' WHERE (id = 30)",
671
675
  "INSERT INTO tags (name) VALUES ('T3')",
672
676
  ["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
673
- proc{al.set(:tags_attributes=>[{:id=>30, :name=>'T2', :number=>3}])}.must_raise(Sequel::MassAssignmentRestriction)
674
- proc{al.set(:tags_attributes=>[{:name=>'T2', :number=>3}])}.must_raise(Sequel::MassAssignmentRestriction)
677
+ al.set_nested_attributes(:tags, [{:id=>30, :name=>'T3', :number=>3}], :fields=>[:name])
678
+ al.tags.first.name.must_equal 'T3'
679
+ al.tags.first.number.must_equal 10
680
+ al.set_nested_attributes(:tags, [{:name=>'T4', :number=>3}], :fields=>[:name])
681
+ al.tags.last.name.must_equal 'T4'
682
+ al.tags.last.number.must_be_nil
675
683
  end
676
684
 
677
685
  it "should allow per-call options via the set_nested_attributes method" do
@@ -688,8 +696,12 @@ describe "NestedAttributes plugin" do
688
696
  "UPDATE tags SET name = 'T2' WHERE (id = 30)",
689
697
  "INSERT INTO tags (name) VALUES ('T3')",
690
698
  ["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
691
- proc{al.set_nested_attributes(:tags, [{:id=>30, :name=>'T2', :number=>3}], :fields=>[:name])}.must_raise(Sequel::MassAssignmentRestriction)
692
- proc{al.set_nested_attributes(:tags, [{:name=>'T2', :number=>3}], :fields=>[:name])}.must_raise(Sequel::MassAssignmentRestriction)
699
+ al.set_nested_attributes(:tags, [{:id=>30, :name=>'T3', :number=>3}], :fields=>[:name])
700
+ al.tags.first.name.must_equal 'T3'
701
+ al.tags.first.number.must_equal 10
702
+ al.set_nested_attributes(:tags, [{:name=>'T4', :number=>3}], :fields=>[:name])
703
+ al.tags.last.name.must_equal 'T4'
704
+ al.tags.last.number.must_be_nil
693
705
  end
694
706
 
695
707
  it "should have set_nested_attributes method raise error if called with a bad association" do
@@ -38,7 +38,7 @@ describe "no_auto_literal_strings extension" do
38
38
  "SELECT * FROM t WHERE (a) LIMIT 1"]
39
39
  end
40
40
 
41
- it "should handle literal strings in arrays in filter methods" do
41
+ deprecated "should handle literal strings in arrays in filter methods" do
42
42
  @ds.where([Sequel.lit("a")]).sql.must_equal 'SELECT * FROM t WHERE (a)'
43
43
  end
44
44
 
@@ -33,6 +33,11 @@ describe "pg_enum extension" do
33
33
  it "should support #create_enum method for adding a new enum" do
34
34
  @db.create_enum(:foo, [:a, :b, :c])
35
35
  @db.sqls.first.must_equal "CREATE TYPE foo AS ENUM ('a', 'b', 'c')"
36
+ @db.create_enum(Sequel[:sch][:foo], %w'a b c')
37
+ @db.sqls.first.must_equal "CREATE TYPE sch.foo AS ENUM ('a', 'b', 'c')"
38
+ end
39
+
40
+ with_symbol_splitting "should support #create_enum method for adding a new enum with qualified symbol" do
36
41
  @db.create_enum(:sch__foo, %w'a b c')
37
42
  @db.sqls.first.must_equal "CREATE TYPE sch.foo AS ENUM ('a', 'b', 'c')"
38
43
  end
@@ -40,12 +45,17 @@ describe "pg_enum extension" do
40
45
  it "should support #drop_enum method for dropping an enum" do
41
46
  @db.drop_enum(:foo)
42
47
  @db.sqls.first.must_equal "DROP TYPE foo"
43
- @db.drop_enum(:sch__foo, :if_exists=>true)
48
+ @db.drop_enum(Sequel[:sch][:foo], :if_exists=>true)
44
49
  @db.sqls.first.must_equal "DROP TYPE IF EXISTS sch.foo"
45
50
  @db.drop_enum('foo', :cascade=>true)
46
51
  @db.sqls.first.must_equal "DROP TYPE foo CASCADE"
47
52
  end
48
53
 
54
+ with_symbol_splitting "should support #drop_enum method for dropping an enum with a splittable symbol" do
55
+ @db.drop_enum(:sch__foo, :if_exists=>true)
56
+ @db.sqls.first.must_equal "DROP TYPE IF EXISTS sch.foo"
57
+ end
58
+
49
59
  it "should support #add_enum_value method for adding value to an existing enum" do
50
60
  @db.add_enum_value(:foo, :a)
51
61
  @db.sqls.first.must_equal "ALTER TYPE foo ADD VALUE 'a'"
@@ -57,6 +67,11 @@ describe "pg_enum extension" do
57
67
  end
58
68
 
59
69
  it "should support :after option for #add_enum_value method for adding value after an existing enum value" do
70
+ @db.add_enum_value(Sequel[:sch][:foo], :a, :after=>:b)
71
+ @db.sqls.first.must_equal "ALTER TYPE sch.foo ADD VALUE 'a' AFTER 'b'"
72
+ end
73
+
74
+ with_symbol_splitting "should support :after option for #add_enum_value method for adding value after an existing enum value with splittable symbol" do
60
75
  @db.add_enum_value(:sch__foo, :a, :after=>:b)
61
76
  @db.sqls.first.must_equal "ALTER TYPE sch.foo ADD VALUE 'a' AFTER 'b'"
62
77
  end
@@ -2,6 +2,10 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  begin
4
4
  require 'active_support/duration'
5
+ begin
6
+ require 'active_support/gem_version'
7
+ rescue LoadError
8
+ end
5
9
  rescue LoadError => exc
6
10
  skip_warn "pg_interval plugin: can't load active_support/duration (#{exc.class}: #{exc})"
7
11
  else
@@ -21,8 +25,13 @@ describe "pg_interval extension" do
21
25
  end
22
26
 
23
27
  it "should literalize ActiveSupport::Duration instances with repeated parts correctly" do
24
- @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1]])).must_equal "'3 seconds '::interval"
25
- @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1], [:days, 1], [:days, 4]])).must_equal "'5 days 3 seconds '::interval"
28
+ if defined?(ActiveSupport::VERSION::STRING) && ActiveSupport::VERSION::STRING >= '5.1'
29
+ @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1]])).must_equal "'1 seconds '::interval"
30
+ @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1], [:days, 1], [:days, 4]])).must_equal "'4 days 1 seconds '::interval"
31
+ else
32
+ @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1]])).must_equal "'3 seconds '::interval"
33
+ @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1], [:days, 1], [:days, 4]])).must_equal "'5 days 3 seconds '::interval"
34
+ end
26
35
  end
27
36
 
28
37
  it "should not affect literalization of custom objects" do
@@ -12,6 +12,11 @@ describe "pg_loose_count extension" do
12
12
  end
13
13
 
14
14
  it "should support schema qualified tables" do
15
+ @db.loose_count(Sequel[:a][:b]).must_equal 1
16
+ @db.sqls.must_equal ["SELECT CAST(reltuples AS integer) AS v FROM pg_class WHERE (oid = CAST(CAST('a.b' AS regclass) AS oid)) LIMIT 1"]
17
+ end
18
+
19
+ with_symbol_splitting "should support schema qualified table symbols" do
15
20
  @db.loose_count(:a__b).must_equal 1
16
21
  @db.sqls.must_equal ["SELECT CAST(reltuples AS integer) AS v FROM pg_class WHERE (oid = CAST(CAST('a.b' AS regclass) AS oid)) LIMIT 1"]
17
22
  end
@@ -207,6 +207,31 @@ describe "pg_row extension" do
207
207
  end
208
208
 
209
209
  it "should allow registering row type parsers for schema qualify types" do
210
+ @db.conversion_procs[4] = p4 = proc{|s| s.to_i}
211
+ @db.conversion_procs[5] = p5 = proc{|s| s * 2}
212
+ @db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
213
+ @db.register_row_type(Sequel[:foo][:bar])
214
+ @db.sqls.must_equal ["SELECT pg_type.oid, typrelid, typarray FROM pg_type INNER JOIN pg_namespace ON ((pg_namespace.oid = pg_type.typnamespace) AND (pg_namespace.nspname = 'foo')) WHERE ((typtype = 'c') AND (typname = 'bar')) LIMIT 1",
215
+ "SELECT attname, (CASE pg_type.typbasetype WHEN 0 THEN atttypid ELSE pg_type.typbasetype END) AS atttypid FROM pg_attribute INNER JOIN pg_type ON (pg_type.oid = pg_attribute.atttypid) WHERE ((attrelid = 2) AND (attnum > 0) AND NOT attisdropped) ORDER BY attnum"]
216
+ p1 = @db.conversion_procs[1]
217
+ p1.columns.must_equal [:bar, :baz]
218
+ p1.column_oids.must_equal [4, 5]
219
+ p1.column_converters.must_equal [p4, p5]
220
+ p1.oid.must_equal 1
221
+
222
+ c = p1.converter
223
+ c.superclass.must_equal @m::HashRow
224
+ c.columns.must_equal [:bar, :baz]
225
+ c.db_type.must_equal Sequel[:foo][:bar]
226
+ p1.typecaster.must_equal c
227
+
228
+ p1.call('(1,b)').must_equal(:bar=>1, :baz=>'bb')
229
+ @db.typecast_value(:pg_row_foo__bar, %w'1 b').must_equal(:bar=>'1', :baz=>'b')
230
+ @db.typecast_value(:pg_row_foo__bar, :bar=>'1', :baz=>'b').must_equal(:bar=>'1', :baz=>'b')
231
+ @db.literal(p1.call('(1,b)')).must_equal "ROW(1, 'bb')::foo.bar"
232
+ end
233
+
234
+ with_symbol_splitting "should allow registering row type parsers for schema qualify type symbols" do
210
235
  @db.conversion_procs[4] = p4 = proc{|s| s.to_i}
211
236
  @db.conversion_procs[5] = p5 = proc{|s| s * 2}
212
237
  @db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]