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
@@ -53,8 +53,19 @@ describe "Dataset::PlaceholderLiteralizer" do
53
53
  loader = @c.loader(@ds){|pl, ds| ds.where(pl.arg)}
54
54
  loader.first(:id=>1).must_equal @h
55
55
  loader.first(Sequel.expr{a(b)}).must_equal @h
56
+ @db.sqls.must_equal ["SELECT * FROM items WHERE (id = 1)", "SELECT * FROM items WHERE a(b)"]
57
+ end
58
+
59
+ deprecated "should handle calls with a literal strings used as filter arguments" do
60
+ loader = @c.loader(@ds){|pl, ds| ds.where(pl.arg)}
56
61
  loader.first("a = 1").must_equal @h
57
- @db.sqls.must_equal ["SELECT * FROM items WHERE (id = 1)", "SELECT * FROM items WHERE a(b)", "SELECT * FROM items WHERE (a = 1)"]
62
+ @db.sqls.must_equal ["SELECT * FROM items WHERE (a = 1)"]
63
+ end
64
+
65
+ it "should handle calls with a literal strings used as filter arguments" do
66
+ loader = @c.loader(@ds){|pl, ds| ds.where(pl.arg)}
67
+ loader.first(Sequel.lit("a = 1")).must_equal @h
68
+ @db.sqls.must_equal ["SELECT * FROM items WHERE (a = 1)"]
58
69
  end
59
70
 
60
71
  it "should handle calls with a placeholders used as right hand side of condition specifiers" do
@@ -72,13 +83,20 @@ describe "Dataset::PlaceholderLiteralizer" do
72
83
  @db.sqls.must_equal ["SELECT * FROM items WHERE ((a = 1) AND (b = 1))", "SELECT * FROM items WHERE ((a = 2) AND (b = 2))"]
73
84
  end
74
85
 
75
- it "should handle calls with a placeholder used multiple times in different capacities" do
86
+ deprecated "should handle calls with a placeholder used multiple times in different capacities" do
76
87
  loader = @c.loader(@ds){|pl, ds| a = pl.arg; ds.where(a).where(:b=>a)}
77
88
  loader.first("a = 1").must_equal @h
78
89
  loader.first(["a = ?", 2]).must_equal @h
79
90
  @db.sqls.must_equal ["SELECT * FROM items WHERE ((a = 1) AND (b = 'a = 1'))", "SELECT * FROM items WHERE ((a = 2) AND (b IN ('a = ?', 2)))"]
80
91
  end
81
92
 
93
+ it "should handle calls with a placeholder used multiple times in different capacities" do
94
+ loader = @c.loader(@ds){|pl, ds| a = pl.arg; ds.select(a).where(:b=>a)}
95
+ loader.first("a").must_equal @h
96
+ loader.first(["a = ?", 2]).must_equal @h
97
+ @db.sqls.must_equal ["SELECT 'a' FROM items WHERE (b = 'a')", "SELECT ('a = ?', 2) FROM items WHERE (b IN ('a = ?', 2))"]
98
+ end
99
+
82
100
  it "should handle calls with manually specified argument positions" do
83
101
  loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg(1)).where(:b=>pl.arg(0))}
84
102
  loader.first(1, 2).must_equal @h
@@ -1,8 +1,8 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
- describe Sequel::Schema::Generator do
3
+ describe Sequel::Schema::CreateTableGenerator do
4
4
  before do
5
- @generator = Sequel::Schema::Generator.new(Sequel.mock) do
5
+ @generator = Sequel::Schema::CreateTableGenerator.new(Sequel.mock) do
6
6
  string :title
7
7
  column :body, :text
8
8
  foreign_key :parent_id
@@ -31,7 +31,7 @@ describe Sequel::Schema::Generator do
31
31
  end
32
32
 
33
33
  it "should respect existing column order if primary_key :keep_order is used" do
34
- generator = Sequel::Schema::Generator.new(Sequel.mock) do
34
+ generator = Sequel::Schema::CreateTableGenerator.new(Sequel.mock) do
35
35
  string :title
36
36
  primary_key :id, :keep_order=>true
37
37
  end
@@ -44,7 +44,7 @@ describe Sequel::Schema::Generator do
44
44
  end
45
45
 
46
46
  it "should handle SQL::Identifier and SQL::QualifiedIdentifier as foreign_key arguments" do
47
- generator = Sequel::Schema::Generator.new(Sequel.mock) do
47
+ generator = Sequel::Schema::CreateTableGenerator.new(Sequel.mock) do
48
48
  foreign_key :a_id, Sequel.identifier(:as)
49
49
  foreign_key :b_id, Sequel.qualify(:c, :b)
50
50
  end
@@ -182,9 +182,9 @@ describe Sequel::Schema::AlterTableGenerator do
182
182
  end
183
183
  end
184
184
 
185
- describe "Sequel::Schema::Generator generic type methods" do
185
+ describe "Sequel::Schema::CreateTableGenerator generic type methods" do
186
186
  it "should store the type class in :type for each column" do
187
- Sequel::Schema::Generator.new(Sequel.mock) do
187
+ Sequel::Schema::CreateTableGenerator.new(Sequel.mock) do
188
188
  String :a
189
189
  Integer :b
190
190
  Fixnum :c
@@ -10,13 +10,17 @@ describe "DB#create_table" do
10
10
  @db.sqls.must_equal ['CREATE TABLE cats ()']
11
11
  end
12
12
 
13
- it "should accept the table name in multiple formats" do
13
+ with_symbol_splitting "should accept the table name with splittable symbols" do
14
14
  @db.create_table(:cats__cats) {}
15
+ @db.sqls.must_equal ['CREATE TABLE cats.cats ()']
16
+ end
17
+
18
+ it "should accept the table name in multiple formats" do
15
19
  @db.create_table(Sequel[:cats][:cats]) {}
16
20
  @db.create_table("cats__cats1") {}
17
21
  @db.create_table(Sequel.identifier(:cats__cats2)) {}
18
22
  @db.create_table(Sequel.qualify(:cats3, :cats)) {}
19
- @db.sqls.must_equal ['CREATE TABLE cats.cats ()', 'CREATE TABLE cats.cats ()', 'CREATE TABLE cats__cats1 ()', 'CREATE TABLE cats__cats2 ()', 'CREATE TABLE cats3.cats ()']
23
+ @db.sqls.must_equal ['CREATE TABLE cats.cats ()', 'CREATE TABLE cats__cats1 ()', 'CREATE TABLE cats__cats2 ()', 'CREATE TABLE cats3.cats ()']
20
24
  end
21
25
 
22
26
  it "should raise an error if the table name argument is not valid" do
@@ -1495,9 +1499,12 @@ describe "Database#create_view" do
1495
1499
  @db.sqls.must_equal ['CREATE VIEW test AS SELECT a, b FROM items ORDER BY c WITH LOCAL CHECK OPTION']
1496
1500
  end
1497
1501
 
1498
- it "should handle create_or_replace_view" do
1502
+ with_symbol_splitting "should handle create_or_replace_view with splittable symbols" do
1499
1503
  @db.create_or_replace_view :sch__test, "SELECT * FROM xyz"
1500
1504
  @db.sqls.must_equal ['DROP VIEW sch.test', 'CREATE VIEW sch.test AS SELECT * FROM xyz']
1505
+ end
1506
+
1507
+ it "should handle create_or_replace_view" do
1501
1508
  @db.create_or_replace_view :test, @db[:items].select(:a, :b).order(:c)
1502
1509
  @db.sqls.must_equal ['DROP VIEW test', 'CREATE VIEW test AS SELECT a, b FROM items ORDER BY c']
1503
1510
  @db.create_or_replace_view Sequel.identifier(:test), @db[:items].select(:a, :b).order(:c)
@@ -1516,12 +1523,16 @@ describe "Database#drop_view" do
1516
1523
  @db = Sequel.mock
1517
1524
  end
1518
1525
 
1526
+ with_symbol_splitting "should construct proper SQL for splittable symbols" do
1527
+ @db.drop_view :sch__test
1528
+ @db.sqls.must_equal ['DROP VIEW sch.test']
1529
+ end
1530
+
1519
1531
  it "should construct proper SQL" do
1520
1532
  @db.drop_view :test
1521
1533
  @db.drop_view Sequel.identifier(:test)
1522
- @db.drop_view :sch__test
1523
1534
  @db.drop_view Sequel.qualify(:sch, :test)
1524
- @db.sqls.must_equal ['DROP VIEW test', 'DROP VIEW test', 'DROP VIEW sch.test', 'DROP VIEW sch.test']
1535
+ @db.sqls.must_equal ['DROP VIEW test', 'DROP VIEW test', 'DROP VIEW sch.test']
1525
1536
  end
1526
1537
 
1527
1538
  it "should drop multiple views at once" do
@@ -1589,6 +1600,19 @@ describe "Schema Parser" do
1589
1600
  end
1590
1601
  @db.schema(:x)
1591
1602
  c.must_equal ["x", {}]
1603
+ @db.schema(Sequel[:s][:x])
1604
+ c.must_equal ["x", {:schema=>"s"}]
1605
+ ds = @db[Sequel[:s][:y]]
1606
+ @db.schema(ds)
1607
+ c.must_equal ["y", {:schema=>"s", :dataset=>ds}]
1608
+ end
1609
+
1610
+ with_symbol_splitting "should provide options if given a table name with splittable symbols" do
1611
+ c = nil
1612
+ meta_def(@db, :schema_parse_table) do |t, opts|
1613
+ c = [t, opts]
1614
+ [[:a, {:db_type=>t.to_s}]]
1615
+ end
1592
1616
  @db.schema(:s__x)
1593
1617
  c.must_equal ["x", {:schema=>"s"}]
1594
1618
  ds = @db[:s__y]
@@ -1646,6 +1670,31 @@ describe "Schema Parser" do
1646
1670
  @db.schema(:x).object_id.must_equal s1.object_id
1647
1671
  @db.schema(Sequel.identifier(:x)).object_id.must_equal s1.object_id
1648
1672
 
1673
+ s2 = @db.schema(Sequel[:x][:y])
1674
+ s2.must_equal [['y', {:schema=>'x', :ruby_default=>nil}]]
1675
+ @db.schema(Sequel[:x][:y]).object_id.must_equal s2.object_id
1676
+ @db.schema(Sequel.qualify(:x, :y)).object_id.must_equal s2.object_id
1677
+
1678
+ s2 = @db.schema(Sequel.qualify(:v, Sequel[:x][:y]))
1679
+ s2.must_equal [['y', {:schema=>'x', :ruby_default=>nil, :information_schema_schema=>Sequel.identifier('v')}]]
1680
+ @db.schema(Sequel.qualify(:v, Sequel[:x][:y])).object_id.must_equal s2.object_id
1681
+ @db.schema(Sequel.qualify(Sequel[:v][:x], :y)).object_id.must_equal s2.object_id
1682
+
1683
+ s2 = @db.schema(Sequel.qualify(Sequel[:u][:v], Sequel[:x][:y]))
1684
+ s2.must_equal [['y', {:schema=>'x', :ruby_default=>nil, :information_schema_schema=>Sequel.qualify('u', 'v')}]]
1685
+ @db.schema(Sequel.qualify(Sequel[:u][:v], Sequel[:x][:y])).object_id.must_equal s2.object_id
1686
+ @db.schema(Sequel.qualify(Sequel.qualify(:u, :v), Sequel.qualify(:x, :y))).object_id.must_equal s2.object_id
1687
+ end
1688
+
1689
+ with_symbol_splitting "should convert splittable symbol arguments" do
1690
+ meta_def(@db, :schema_parse_table) do |t, opts|
1691
+ [[t, opts]]
1692
+ end
1693
+ s1 = @db.schema(:x)
1694
+ s1.must_equal [['x', {:ruby_default=>nil}]]
1695
+ @db.schema(:x).object_id.must_equal s1.object_id
1696
+ @db.schema(Sequel.identifier(:x)).object_id.must_equal s1.object_id
1697
+
1649
1698
  s2 = @db.schema(:x__y)
1650
1699
  s2.must_equal [['y', {:schema=>'x', :ruby_default=>nil}]]
1651
1700
  @db.schema(:x__y).object_id.must_equal s2.object_id
@@ -6,9 +6,8 @@ if ENV['COVERAGE']
6
6
  end
7
7
 
8
8
  unless Object.const_defined?('Sequel') && Sequel.const_defined?('Model')
9
- $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
9
+ $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../lib/"))
10
10
  require 'sequel'
11
- Sequel::Deprecation.backtrace_filter = true
12
11
  end
13
12
 
14
13
  # SEQUEL5: Remove
@@ -26,8 +25,13 @@ if RUBY_VERSION < '1.9.0'
26
25
  Sequel.extension :ruby18_symbol_extensions
27
26
  end
28
27
  Sequel.extension :symbol_aref
28
+ Sequel.extension :virtual_row_method_block
29
29
 
30
+ gem 'minitest'
30
31
  require 'minitest/autorun'
32
+ require 'minitest/hooks/default'
33
+
34
+ require File.expand_path("#{File.dirname(__FILE__)}/deprecation_helper.rb")
31
35
 
32
36
  describe "Sequel core extensions" do
33
37
  it "should have Sequel.core_extensions? be true if enabled" do
@@ -90,6 +94,9 @@ describe "Core extensions" do
90
94
  end
91
95
  it "should support NOT via Symbol#~" do
92
96
  @d.l(~:x).must_equal 'NOT x'
97
+ end
98
+
99
+ with_symbol_splitting "should support NOT via Symbol#~ for splittable symbols" do
93
100
  @d.l(~:x__y).must_equal 'NOT x.y'
94
101
  end
95
102
 
@@ -231,7 +238,7 @@ describe "Core extensions" do
231
238
  @d.lit([:x.sql_function(1), 'y.z'.lit].sql_string_join(', ')).must_equal "(x(1) || ', ' || y.z)"
232
239
  @d.lit([:x, 1, :y].sql_string_join).must_equal "(x || '1' || y)"
233
240
  @d.lit([:x, 1, :y].sql_string_join(', ')).must_equal "(x || ', ' || '1' || ', ' || y)"
234
- @d.lit([:x, 1, :y].sql_string_join(:y__z)).must_equal "(x || y.z || '1' || y.z || y)"
241
+ @d.lit([:x, 1, :y].sql_string_join(Sequel[:y][:z])).must_equal "(x || y.z || '1' || y.z || y)"
235
242
  @d.lit([:x, 1, :y].sql_string_join(1)).must_equal "(x || '1' || '1' || '1' || y)"
236
243
  @d.lit([:x, :y].sql_string_join('y.x || x.y'.lit)).must_equal "(x || y.x || x.y || y)"
237
244
  @d.lit([[:x, :y].sql_string_join, [:a, :b].sql_string_join].sql_string_join).must_equal "(x || y || a || b)"
@@ -282,7 +289,7 @@ describe "Array#case and Hash#case" do
282
289
  @d.literal([[:x, :y]].case(:z)).must_equal '(CASE WHEN x THEN y ELSE z END)'
283
290
  @d.literal([[:x, :y], [:a, :b]].case(:z)).must_equal '(CASE WHEN x THEN y WHEN a THEN b ELSE z END)'
284
291
  @d.literal([[:x, :y], [:a, :b]].case(:z, :exp)).must_equal '(CASE exp WHEN x THEN y WHEN a THEN b ELSE z END)'
285
- @d.literal([[:x, :y], [:a, :b]].case(:z, :exp__w)).must_equal '(CASE exp.w WHEN x THEN y WHEN a THEN b ELSE z END)'
292
+ @d.literal([[:x, :y], [:a, :b]].case(:z, Sequel[:exp][:w])).must_equal '(CASE exp.w WHEN x THEN y WHEN a THEN b ELSE z END)'
286
293
  end
287
294
 
288
295
  it "should return SQL CASE expression with expression even if nil" do
@@ -307,9 +314,9 @@ describe "Array#sql_value_list and #sql_array" do
307
314
  end
308
315
 
309
316
  it "should treat the array as an SQL value list instead of conditions when used as a placeholder value" do
310
- @d.filter("(a, b) IN ?", [[:x, 1], [:y, 2]]).sql.must_equal 'SELECT * WHERE ((a, b) IN ((x = 1) AND (y = 2)))'
311
- @d.filter("(a, b) IN ?", [[:x, 1], [:y, 2]].sql_value_list).sql.must_equal 'SELECT * WHERE ((a, b) IN ((x, 1), (y, 2)))'
312
- @d.filter("(a, b) IN ?", [[:x, 1], [:y, 2]].sql_array).sql.must_equal 'SELECT * WHERE ((a, b) IN ((x, 1), (y, 2)))'
317
+ @d.filter(Sequel.lit("(a, b) IN ?", [[:x, 1], [:y, 2]])).sql.must_equal 'SELECT * WHERE ((a, b) IN ((x = 1) AND (y = 2)))'
318
+ @d.filter(Sequel.lit("(a, b) IN ?", [[:x, 1], [:y, 2]].sql_value_list)).sql.must_equal 'SELECT * WHERE ((a, b) IN ((x, 1), (y, 2)))'
319
+ @d.filter(Sequel.lit("(a, b) IN ?", [[:x, 1], [:y, 2]].sql_array)).sql.must_equal 'SELECT * WHERE ((a, b) IN ((x, 1), (y, 2)))'
313
320
  end
314
321
 
315
322
  it "should be no difference when used as a hash value" do
@@ -401,7 +408,9 @@ describe "#desc" do
401
408
 
402
409
  it "should format a DESC clause for a column ref" do
403
410
  @ds.literal(:test.desc).must_equal 'test DESC'
411
+ end
404
412
 
413
+ with_symbol_splitting "should format a DESC clause for a column ref with a splitting symbol" do
405
414
  @ds.literal(:items__price.desc).must_equal 'items.price DESC'
406
415
  end
407
416
 
@@ -417,7 +426,9 @@ describe "#asc" do
417
426
 
418
427
  it "should format a ASC clause for a column ref" do
419
428
  @ds.literal(:test.asc).must_equal 'test ASC'
429
+ end
420
430
 
431
+ with_symbol_splitting "should format a ASC clause for a column ref for a splittable symbol" do
421
432
  @ds.literal(:items__price.asc).must_equal 'items.price ASC'
422
433
  end
423
434
 
@@ -433,7 +444,9 @@ describe "#as" do
433
444
 
434
445
  it "should format a AS clause for a column ref" do
435
446
  @ds.literal(:test.as(:t)).must_equal 'test AS t'
436
-
447
+ end
448
+
449
+ with_symbol_splitting "should format a AS clause for a column ref for splittable symbols" do
437
450
  @ds.literal(:items__price.as(:p)).must_equal 'items.price AS p'
438
451
  end
439
452
 
@@ -453,15 +466,9 @@ describe "Column references" do
453
466
 
454
467
  it "should be quoted properly" do
455
468
  @ds.literal(:xyz).must_equal "`xyz`"
456
- @ds.literal(:xyz__abc).must_equal "`xyz`.`abc`"
457
-
458
469
  @ds.literal(:xyz.as(:x)).must_equal "`xyz` AS `x`"
459
- @ds.literal(:xyz__abc.as(:x)).must_equal "`xyz`.`abc` AS `x`"
460
-
461
- @ds.literal(:xyz___x).must_equal "`xyz` AS `x`"
462
- @ds.literal(:xyz__abc___x).must_equal "`xyz`.`abc` AS `x`"
463
470
  end
464
-
471
+
465
472
  it "should be quoted properly in SQL functions" do
466
473
  @ds.literal(:avg.sql_function(:xyz)).must_equal "avg(`xyz`)"
467
474
  @ds.literal(:avg.sql_function(:xyz, 1)).must_equal "avg(`xyz`, 1)"
@@ -475,6 +482,13 @@ describe "Column references" do
475
482
 
476
483
  it "should be quoted properly in a cast function" do
477
484
  @ds.literal(:x.cast(:integer)).must_equal "CAST(`x` AS integer)"
485
+ end
486
+
487
+ with_symbol_splitting "should be quoted properly when using symbol splitting" do
488
+ @ds.literal(:xyz__abc).must_equal "`xyz`.`abc`"
489
+ @ds.literal(:xyz__abc.as(:x)).must_equal "`xyz`.`abc` AS `x`"
490
+ @ds.literal(:xyz___x).must_equal "`xyz` AS `x`"
491
+ @ds.literal(:xyz__abc___x).must_equal "`xyz`.`abc` AS `x`"
478
492
  @ds.literal(:x__y.cast('varchar(20)')).must_equal "CAST(`x`.`y` AS varchar(20))"
479
493
  end
480
494
  end
@@ -512,7 +526,7 @@ describe "Symbol#*" do
512
526
  @ds.literal(:abc.*(5)).must_equal '(abc * 5)'
513
527
  end
514
528
 
515
- it "should support qualified symbols if no argument" do
529
+ with_symbol_splitting "should support qualified symbols if no argument" do
516
530
  @ds.literal(:xyz__abc.*).must_equal 'xyz.abc.*'
517
531
  end
518
532
  end
@@ -534,7 +548,7 @@ describe "Symbol" do
534
548
  @ds.literal(:xyz.qualify(:abc).qualify(:def)).must_equal '"def"."abc"."xyz"'
535
549
  end
536
550
 
537
- it "should be able to qualify an identifier" do
551
+ with_symbol_splitting "should be able to qualify an identifier" do
538
552
  @ds.literal(:xyz.identifier.qualify(:xyz__abc)).must_equal '"xyz"."abc"."xyz"'
539
553
  end
540
554
 
@@ -575,11 +589,14 @@ describe "Symbol" do
575
589
 
576
590
  it "should support sql array accesses via sql_subscript" do
577
591
  @ds.literal(:abc.sql_subscript(1)).must_equal "abc[1]"
578
- @ds.literal(:abc__def.sql_subscript(1)).must_equal "abc.def[1]"
579
592
  @ds.literal(:abc.sql_subscript(1)|2).must_equal "abc[1, 2]"
580
593
  @ds.literal(:abc.sql_subscript(1)[2]).must_equal "abc[1][2]"
581
594
  end
582
595
 
596
+ with_symbol_splitting "should support sql array accesses via sql_subscript for splittable symbols" do
597
+ @ds.literal(:abc__def.sql_subscript(1)).must_equal "abc.def[1]"
598
+ end
599
+
583
600
  it "should support cast_numeric and cast_string" do
584
601
  x = :abc.cast_numeric
585
602
  x.must_be_kind_of(Sequel::SQL::NumericExpression)
@@ -726,3 +743,90 @@ describe "symbol_aref extensions" do
726
743
  end
727
744
  end
728
745
  end
746
+
747
+ describe Sequel::SQL::VirtualRow do
748
+ before do
749
+ @d = Sequel.mock[:items].with_quote_identifiers(true).with_extend do
750
+ def supports_window_functions?; true end
751
+ def l(*args, &block)
752
+ literal(filter_expr(*args, &block))
753
+ end
754
+ end
755
+ end
756
+
757
+ it "should treat methods without blocks normally" do
758
+ @d.l{column}.must_equal '"column"'
759
+ @d.l{foo(a)}.must_equal 'foo("a")'
760
+ end
761
+
762
+
763
+ it "should treat methods with a block and no arguments as a function call with no arguments" do
764
+ @d.l{version{}}.must_equal 'version()'
765
+ end
766
+
767
+ it "should treat methods with a block and a leading argument :* as a function call with the SQL wildcard" do
768
+ @d.l{count(:*){}}.must_equal 'count(*)'
769
+ end
770
+
771
+ it "should treat methods with a block and a leading argument :distinct as a function call with DISTINCT and the additional method arguments" do
772
+ @d.l{count(:distinct, column1){}}.must_equal 'count(DISTINCT "column1")'
773
+ @d.l{count(:distinct, column1, column2){}}.must_equal 'count(DISTINCT "column1", "column2")'
774
+ end
775
+
776
+ it "should raise an error if an unsupported argument is used with a block" do
777
+ proc{@d.where{count(:blah){}}}.must_raise(Sequel::Error)
778
+ end
779
+
780
+ it "should treat methods with a block and a leading argument :over as a window function call" do
781
+ @d.l{rank(:over){}}.must_equal 'rank() OVER ()'
782
+ end
783
+
784
+ it "should support :partition options for window function calls" do
785
+ @d.l{rank(:over, :partition=>column1){}}.must_equal 'rank() OVER (PARTITION BY "column1")'
786
+ @d.l{rank(:over, :partition=>[column1, column2]){}}.must_equal 'rank() OVER (PARTITION BY "column1", "column2")'
787
+ end
788
+
789
+ it "should support :args options for window function calls" do
790
+ @d.l{avg(:over, :args=>column1){}}.must_equal 'avg("column1") OVER ()'
791
+ @d.l{avg(:over, :args=>[column1, column2]){}}.must_equal 'avg("column1", "column2") OVER ()'
792
+ end
793
+
794
+ it "should support :order option for window function calls" do
795
+ @d.l{rank(:over, :order=>column1){}}.must_equal 'rank() OVER (ORDER BY "column1")'
796
+ @d.l{rank(:over, :order=>[column1, column2]){}}.must_equal 'rank() OVER (ORDER BY "column1", "column2")'
797
+ end
798
+
799
+ it "should support :window option for window function calls" do
800
+ @d.l{rank(:over, :window=>:win){}}.must_equal 'rank() OVER ("win")'
801
+ end
802
+
803
+ it "should support :*=>true option for window function calls" do
804
+ @d.l{count(:over, :* =>true){}}.must_equal 'count(*) OVER ()'
805
+ end
806
+
807
+ it "should support :frame=>:all option for window function calls" do
808
+ @d.l{rank(:over, :frame=>:all){}}.must_equal 'rank() OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)'
809
+ end
810
+
811
+ it "should support :frame=>:rows option for window function calls" do
812
+ @d.l{rank(:over, :frame=>:rows){}}.must_equal 'rank() OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)'
813
+ end
814
+
815
+ it "should support :frame=>'some string' option for window function calls" do
816
+ @d.l{rank(:over, :frame=>'RANGE BETWEEN 3 PRECEDING AND CURRENT ROW'){}}.must_equal 'rank() OVER (RANGE BETWEEN 3 PRECEDING AND CURRENT ROW)'
817
+ end
818
+
819
+ it "should raise an error if an invalid :frame option is used" do
820
+ proc{@d.l{rank(:over, :frame=>:blah){}}}.must_raise(Sequel::Error)
821
+ end
822
+
823
+ it "should support all these options together" do
824
+ @d.l{count(:over, :* =>true, :partition=>a, :order=>b, :window=>:win, :frame=>:rows){}}.must_equal 'count(*) OVER ("win" PARTITION BY "a" ORDER BY "b" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)'
825
+ end
826
+
827
+ it "should raise an error if window functions are not supported" do
828
+ proc{@d.with_extend{def supports_window_functions?; false end}.l{count(:over, :* =>true, :partition=>a, :order=>b, :window=>:win, :frame=>:rows){}}}.must_raise(Sequel::Error)
829
+ proc{Sequel.mock.dataset.filter{count(:over, :* =>true, :partition=>a, :order=>b, :window=>:win, :frame=>:rows){}}.sql}.must_raise(Sequel::Error)
830
+ end
831
+ end
832
+
@@ -1,8 +1,8 @@
1
1
  Sequel::Deprecation.backtrace_filter = lambda{|line, lineno| lineno < 4 || line =~ /_spec\.rb/}
2
2
 
3
3
  class Minitest::HooksSpec
4
- def self.deprecated(*a, &block)
5
- it(*a) do
4
+ def self.deprecated(a, &block)
5
+ it("#{a} (deprecated)") do
6
6
  deprecated{instance_exec(&block)}
7
7
  end
8
8
  end
@@ -14,4 +14,29 @@ class Minitest::HooksSpec
14
14
  ensure
15
15
  Sequel::Deprecation.output = output
16
16
  end
17
+
18
+ def self.with_symbol_splitting(a, &block)
19
+ it(a) do
20
+ with_symbol_splitting{instance_exec(&block)}
21
+ end
22
+ it("#{a}, except when symbol_splitting disabled") do
23
+ without_symbol_splitting{instance_exec(&block)}
24
+ end
25
+ end
26
+
27
+ def without_symbol_splitting
28
+ Sequel.split_symbols = false
29
+ DB.send(:reset_default_dataset) if defined?(DB)
30
+ proc{yield}.must_raise Minitest::Assertion
31
+ ensure
32
+ Sequel.split_symbols = :deprecated
33
+ DB.send(:reset_default_dataset) if defined?(DB)
34
+ end
35
+
36
+ def with_symbol_splitting
37
+ Sequel.split_symbols = true
38
+ yield
39
+ ensure
40
+ Sequel.split_symbols = :deprecated
41
+ end
17
42
  end