sequel 4.45.0 → 4.46.0

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