sequel 4.39.0 → 4.40.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +34 -0
  3. data/README.rdoc +8 -4
  4. data/doc/active_record.rdoc +1 -1
  5. data/doc/advanced_associations.rdoc +7 -7
  6. data/doc/association_basics.rdoc +7 -7
  7. data/doc/cheat_sheet.rdoc +5 -3
  8. data/doc/core_extensions.rdoc +3 -3
  9. data/doc/dataset_filtering.rdoc +1 -1
  10. data/doc/object_model.rdoc +16 -7
  11. data/doc/postgresql.rdoc +3 -3
  12. data/doc/querying.rdoc +3 -3
  13. data/doc/release_notes/4.40.0.txt +179 -0
  14. data/doc/security.rdoc +2 -1
  15. data/doc/sql.rdoc +34 -18
  16. data/doc/testing.rdoc +1 -0
  17. data/doc/virtual_rows.rdoc +11 -2
  18. data/lib/sequel/adapters/jdbc/derby.rb +7 -1
  19. data/lib/sequel/adapters/jdbc/h2.rb +15 -1
  20. data/lib/sequel/adapters/oracle.rb +9 -5
  21. data/lib/sequel/adapters/postgres.rb +0 -1
  22. data/lib/sequel/adapters/shared/cubrid.rb +11 -11
  23. data/lib/sequel/adapters/shared/db2.rb +4 -8
  24. data/lib/sequel/adapters/shared/mssql.rb +41 -28
  25. data/lib/sequel/adapters/shared/mysql.rb +9 -6
  26. data/lib/sequel/adapters/shared/oracle.rb +16 -5
  27. data/lib/sequel/adapters/shared/postgres.rb +84 -45
  28. data/lib/sequel/adapters/shared/sqlanywhere.rb +29 -15
  29. data/lib/sequel/adapters/shared/sqlite.rb +6 -6
  30. data/lib/sequel/core.rb +61 -10
  31. data/lib/sequel/database/connecting.rb +2 -1
  32. data/lib/sequel/database/features.rb +7 -0
  33. data/lib/sequel/database/query.rb +1 -1
  34. data/lib/sequel/database/schema_methods.rb +30 -3
  35. data/lib/sequel/database/transactions.rb +4 -2
  36. data/lib/sequel/dataset/actions.rb +1 -1
  37. data/lib/sequel/dataset/graph.rb +6 -1
  38. data/lib/sequel/dataset/query.rb +14 -7
  39. data/lib/sequel/dataset/sql.rb +2 -2
  40. data/lib/sequel/extensions/core_extensions.rb +2 -1
  41. data/lib/sequel/extensions/pg_row.rb +2 -2
  42. data/lib/sequel/extensions/s.rb +57 -0
  43. data/lib/sequel/extensions/set_overrides.rb +5 -1
  44. data/lib/sequel/extensions/sql_expr.rb +1 -0
  45. data/lib/sequel/extensions/symbol_aref.rb +71 -0
  46. data/lib/sequel/extensions/symbol_aref_refinement.rb +41 -0
  47. data/lib/sequel/extensions/symbol_as.rb +23 -0
  48. data/lib/sequel/extensions/symbol_as_refinement.rb +35 -0
  49. data/lib/sequel/model/base.rb +3 -3
  50. data/lib/sequel/plugins/class_table_inheritance.rb +14 -3
  51. data/lib/sequel/plugins/column_select.rb +4 -2
  52. data/lib/sequel/plugins/dataset_associations.rb +12 -4
  53. data/lib/sequel/plugins/insert_returning_select.rb +1 -1
  54. data/lib/sequel/plugins/mssql_optimistic_locking.rb +1 -1
  55. data/lib/sequel/plugins/prepared_statements.rb +1 -0
  56. data/lib/sequel/sql.rb +40 -8
  57. data/lib/sequel/version.rb +1 -1
  58. data/spec/adapters/firebird_spec.rb +3 -3
  59. data/spec/adapters/mssql_spec.rb +40 -40
  60. data/spec/adapters/mysql_spec.rb +5 -5
  61. data/spec/adapters/oracle_spec.rb +4 -4
  62. data/spec/adapters/postgres_spec.rb +135 -124
  63. data/spec/adapters/spec_helper.rb +1 -0
  64. data/spec/adapters/sqlite_spec.rb +6 -6
  65. data/spec/core/dataset_spec.rb +2 -2
  66. data/spec/core/expression_filters_spec.rb +43 -2
  67. data/spec/core/schema_spec.rb +35 -1
  68. data/spec/core_extensions_spec.rb +27 -0
  69. data/spec/extensions/class_table_inheritance_spec.rb +8 -0
  70. data/spec/extensions/column_select_spec.rb +8 -0
  71. data/spec/extensions/core_refinements_spec.rb +1 -1
  72. data/spec/extensions/dataset_associations_spec.rb +9 -0
  73. data/spec/extensions/insert_returning_select_spec.rb +20 -0
  74. data/spec/extensions/prepared_statements_spec.rb +7 -0
  75. data/spec/extensions/s_spec.rb +60 -0
  76. data/spec/extensions/symbol_aref_refinement_spec.rb +28 -0
  77. data/spec/extensions/symbol_as_refinement_spec.rb +21 -0
  78. data/spec/integration/associations_test.rb +62 -57
  79. data/spec/integration/dataset_test.rb +54 -54
  80. data/spec/integration/eager_loader_test.rb +7 -7
  81. data/spec/integration/plugin_test.rb +20 -20
  82. data/spec/integration/prepared_statement_test.rb +1 -1
  83. data/spec/integration/schema_test.rb +21 -0
  84. data/spec/integration/spec_helper.rb +1 -0
  85. metadata +12 -2
@@ -15,6 +15,7 @@ begin
15
15
  rescue LoadError
16
16
  end
17
17
 
18
+ Sequel.split_symbols = false if ENV['SEQUEL_NO_SPLIT_SYMBOLS']
18
19
  Sequel::Database.extension :duplicate_column_handler if ENV['SEQUEL_DUPLICATE_COLUMN_HANDLER']
19
20
  Sequel::Database.extension :columns_introspection if ENV['SEQUEL_COLUMNS_INTROSPECTION']
20
21
  Sequel::Model.cache_associations = false if ENV['SEQUEL_NO_CACHE_ASSOCIATIONS']
@@ -309,12 +309,12 @@ describe "An SQLite dataset" do
309
309
  end
310
310
 
311
311
  describe "An SQLite dataset AS clause" do
312
- it "should use a string literal for :col___alias" do
313
- DB.literal(:c___a).must_equal "`c` AS 'a'"
312
+ it "should use a string literal for Sequel[:col].as(:alias)" do
313
+ DB.literal(Sequel[:c].as(:a)).must_equal "`c` AS 'a'"
314
314
  end
315
315
 
316
- it "should use a string literal for :table__col___alias" do
317
- DB.literal(:t__c___a).must_equal "`t`.`c` AS 'a'"
316
+ it "should use a string literal for Sequel[:table][:col].as(:alias)" do
317
+ DB.literal(Sequel[:t][:c].as(:a)).must_equal "`t`.`c` AS 'a'"
318
318
  end
319
319
 
320
320
  it "should use a string literal for :column.as(:alias)" do
@@ -322,11 +322,11 @@ describe "An SQLite dataset AS clause" do
322
322
  end
323
323
 
324
324
  it "should use a string literal in the SELECT clause" do
325
- DB[:t].select(:c___a).sql.must_equal "SELECT `c` AS 'a' FROM `t`"
325
+ DB[:t].select(Sequel[:c].as(:a)).sql.must_equal "SELECT `c` AS 'a' FROM `t`"
326
326
  end
327
327
 
328
328
  it "should use a string literal in the FROM clause" do
329
- DB[:t___a].sql.must_equal "SELECT * FROM `t` AS 'a'"
329
+ DB[Sequel[:t].as(:a)].sql.must_equal "SELECT * FROM `t` AS 'a'"
330
330
  end
331
331
 
332
332
  it "should use a string literal in the JOIN clause" do
@@ -5108,13 +5108,13 @@ describe "Dataset emulated complex expression operators" do
5108
5108
  it "should emulate >>" do
5109
5109
  @ds.literal(Sequel::SQL::NumericExpression.new(:>>, @n)).must_equal "x"
5110
5110
  @ds.literal(@n >> 1).must_equal "(x / power(2, 1))"
5111
- @ds.literal(@n >> 1 >> 2).must_equal "(x / power(2, 1) / power(2, 2))"
5111
+ @ds.literal(@n >> 1 >> 2).must_equal "((x / power(2, 1)) / power(2, 2))"
5112
5112
  end
5113
5113
 
5114
5114
  it "should emulate <<" do
5115
5115
  @ds.literal(Sequel::SQL::NumericExpression.new(:<<, @n)).must_equal "x"
5116
5116
  @ds.literal(@n << 1).must_equal "(x * power(2, 1))"
5117
- @ds.literal(@n << 1 << 2).must_equal "(x * power(2, 1) * power(2, 2))"
5117
+ @ds.literal(@n << 1 << 2).must_equal "((x * power(2, 1)) * power(2, 2))"
5118
5118
  end
5119
5119
 
5120
5120
  it "should emulate B~" do
@@ -16,8 +16,26 @@ describe "Blockless Ruby Filters" do
16
16
  @d.l(:x).must_equal 'x'
17
17
  end
18
18
 
19
- it "should support qualified columns" do
19
+ it "should support qualified columns and aliased columns using symbols" do
20
20
  @d.l(:x__y).must_equal 'x.y'
21
+ @d.l(:x___y).must_equal 'x AS y'
22
+ @d.l(:x__y___z).must_equal 'x.y AS z'
23
+ end
24
+
25
+ it "should support qualified columns using virtual rows" do
26
+ @d.l(Sequel.expr{x__y}).must_equal 'x.y'
27
+ end
28
+
29
+ it "should not split symbols or virtual row methods if symbol splitting is disabled" do
30
+ begin
31
+ Sequel.split_symbols = false
32
+ @d.l(:x__y).must_equal 'x__y'
33
+ @d.l(:x___y).must_equal 'x___y'
34
+ @d.l(:x__y___z).must_equal 'x__y___z'
35
+ @d.l(Sequel.expr{x__y}).must_equal 'x__y'
36
+ ensure
37
+ Sequel.split_symbols = true
38
+ end
21
39
  end
22
40
 
23
41
  it "should support NOT with SQL functions" do
@@ -129,6 +147,21 @@ describe "Blockless Ruby Filters" do
129
147
  proc{~Sequel.expr(:x).sql_string}.must_raise(NoMethodError)
130
148
  end
131
149
 
150
+ it "should only allow combining associative operators" do
151
+ @d.lit(Sequel.expr{a + b + c}).must_equal '(a + b + c)'
152
+ @d.lit(Sequel.expr{a - b - c}).must_equal '((a - b) - c)'
153
+ @d.lit(Sequel.expr{a * b * c}).must_equal '(a * b * c)'
154
+ @d.lit(Sequel.expr{a / b / c}).must_equal '((a / b) / c)'
155
+ @d.lit(Sequel.expr{a & b & c}).must_equal '(a AND b AND c)'
156
+ @d.lit(Sequel.expr{a | b | c}).must_equal '(a OR b OR c)'
157
+ @d.lit(Sequel.expr{a.sql_string + b + c}).must_equal '(a || b || c)'
158
+ @d.lit(Sequel.expr{a.sql_number >> b >> c}).must_equal '((a >> b) >> c)'
159
+ @d.lit(Sequel.expr{a.sql_number << b << c}).must_equal '((a << b) << c)'
160
+ @d.lit(Sequel.expr{a.sql_number % b % c}).must_equal '((a % b) % c)'
161
+ @d.lit(Sequel.expr{a.sql_number & b & c}).must_equal '(a & b & c)'
162
+ @d.lit(Sequel.expr{a.sql_number | b | c}).must_equal '(a | b | c)'
163
+ end
164
+
132
165
  it "should allow mathematical or string operations on true, false, or nil" do
133
166
  @d.lit(Sequel.expr(:x) + 1).must_equal '(x + 1)'
134
167
  @d.lit(Sequel.expr(:x) - true).must_equal "(x - 't')"
@@ -206,7 +239,7 @@ describe "Blockless Ruby Filters" do
206
239
  @d.l((Sequel.lit('x') * :y) < 100.01).must_equal '((x * y) < 100.01)'
207
240
  @d.l((Sequel.lit('x') ** :y) < 100.01).must_equal '(power(x, y) < 100.01)'
208
241
  @d.l((Sequel.lit('x') - Sequel.expr(:y)/2) >= 100000000000000000000000000000000000).must_equal '((x - (y / 2)) >= 100000000000000000000000000000000000)'
209
- @d.l((Sequel.lit('z') * ((Sequel.lit('x') / :y)/(Sequel.expr(:x) + :y))) <= 100).must_equal '((z * (x / y / (x + y))) <= 100)'
242
+ @d.l((Sequel.lit('z') * ((Sequel.lit('x') / :y)/(Sequel.expr(:x) + :y))) <= 100).must_equal '((z * ((x / y) / (x + y))) <= 100)'
210
243
  @d.l(~((((Sequel.lit('x') - :y)/(Sequel.expr(:x) + :y))*:z) <= 100)).must_equal '((((x - y) / (x + y)) * z) > 100)'
211
244
  end
212
245
 
@@ -921,6 +954,14 @@ describe "Sequel core extension replacements" do
921
954
  l(Sequel.qualify(:t, :c), "t.c")
922
955
  end
923
956
 
957
+ it "Sequel::SQL::Identifier#[] should return a qualified identifier" do
958
+ l(Sequel[:t][:c], "t.c")
959
+ end
960
+
961
+ it "Sequel::SQL::QualifiedIdentifier#[] should return a nested qualified identifier" do
962
+ l(Sequel[:s][:t][:c], "s.t.c")
963
+ end
964
+
924
965
  it "Sequel.identifier should return an identifier" do
925
966
  l(Sequel.identifier(:t__c), "t__c")
926
967
  end
@@ -12,10 +12,11 @@ describe "DB#create_table" do
12
12
 
13
13
  it "should accept the table name in multiple formats" do
14
14
  @db.create_table(:cats__cats) {}
15
+ @db.create_table(Sequel[:cats][:cats]) {}
15
16
  @db.create_table("cats__cats1") {}
16
17
  @db.create_table(Sequel.identifier(:cats__cats2)) {}
17
18
  @db.create_table(Sequel.qualify(:cats3, :cats)) {}
18
- @db.sqls.must_equal ['CREATE TABLE cats.cats ()', 'CREATE TABLE cats__cats1 ()', 'CREATE TABLE cats__cats2 ()', 'CREATE TABLE 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 ()']
19
20
  end
20
21
 
21
22
  it "should raise an error if the table name argument is not valid" do
@@ -132,6 +133,23 @@ describe "DB#create_table" do
132
133
  @db.sqls.must_equal ['CREATE TABLE cats (id integer CONSTRAINT foo PRIMARY KEY AUTOINCREMENT)']
133
134
  end
134
135
 
136
+ it "should automatically set primary key column NOT NULL if database doesn't do it automatically" do
137
+ def @db.can_add_primary_key_constraint_on_nullable_columns?; false end
138
+ @db.create_table(:cats) do
139
+ primary_key :id
140
+ end
141
+ @db.sqls.must_equal ['CREATE TABLE cats (id integer NOT NULL PRIMARY KEY AUTOINCREMENT)']
142
+ end
143
+
144
+ it "should automatically set primary key column NOT NULL when adding constraint if database doesn't do it automatically" do
145
+ def @db.can_add_primary_key_constraint_on_nullable_columns?; false end
146
+ @db.create_table(:cats) do
147
+ String :id
148
+ primary_key [:id]
149
+ end
150
+ @db.sqls.must_equal ['CREATE TABLE cats (id varchar(255) NOT NULL, PRIMARY KEY (id))']
151
+ end
152
+
135
153
  it "should handling splitting named column constraints into table constraints if unsupported" do
136
154
  def @db.supports_named_column_constraints?; false end
137
155
  @db.create_table(:cats) do
@@ -1100,6 +1118,22 @@ describe "DB#alter_table" do
1100
1118
  @db.sqls.must_equal ["ALTER TABLE cats ADD CONSTRAINT cpk PRIMARY KEY (id, type)"]
1101
1119
  end
1102
1120
 
1121
+ it "should set primary key column NOT NULL when using add_primary_key if database doesn't handle it" do
1122
+ def @db.can_add_primary_key_constraint_on_nullable_columns?; false end
1123
+ @db.alter_table(:cats) do
1124
+ add_primary_key :id
1125
+ end
1126
+ @db.sqls.must_equal ["ALTER TABLE cats ADD COLUMN id integer NOT NULL PRIMARY KEY AUTOINCREMENT"]
1127
+ end
1128
+
1129
+ it "should set primary key column NOT NULL when adding primary key constraint if database doesn't handle it" do
1130
+ def @db.can_add_primary_key_constraint_on_nullable_columns?; false end
1131
+ @db.alter_table(:cats) do
1132
+ add_primary_key [:id, :type]
1133
+ end
1134
+ @db.sqls.must_equal ["ALTER TABLE cats ALTER COLUMN id SET NOT NULL", "ALTER TABLE cats ALTER COLUMN type SET NOT NULL", "ALTER TABLE cats ADD PRIMARY KEY (id, type)"]
1135
+ end
1136
+
1103
1137
  it "should support drop_column" do
1104
1138
  @db.alter_table(:cats) do
1105
1139
  drop_column :score
@@ -21,6 +21,7 @@ Sequel.extension :core_extensions
21
21
  if RUBY_VERSION < '1.9.0'
22
22
  Sequel.extension :ruby18_symbol_extensions
23
23
  end
24
+ Sequel.extension :symbol_aref
24
25
 
25
26
  require 'minitest/autorun'
26
27
 
@@ -702,3 +703,29 @@ describe "Postgres extensions integration" do
702
703
  @db.literal((1..2).pg_range(:int4range)).must_equal "int4range(1,2,'[]')"
703
704
  end
704
705
  end
706
+
707
+ describe "symbol_aref extensions" do
708
+ before do
709
+ @db = Sequel.mock
710
+ end
711
+
712
+ it "Symbol#[] should create qualified identifier if given a symbol" do
713
+ @db.literal(:x[:y]).must_equal "x.y"
714
+ end
715
+
716
+ it "Symbol#[] should create qualified identifier if given an identifier" do
717
+ @db.literal(:x[Sequel[:y]]).must_equal "x.y"
718
+ end
719
+
720
+ it "Symbol#[] should create qualified identifier if given a qualified identifier" do
721
+ @db.literal(:x[:y[:z]]).must_equal "x.y.z"
722
+ end
723
+
724
+ it "should not affect other arguments to Symbol#[]" do
725
+ if RUBY_VERSION >= '1.9'
726
+ :x[0].must_equal "x"
727
+ else
728
+ @db.literal(:x[0]).must_equal "x(0)"
729
+ end
730
+ end
731
+ end
@@ -51,6 +51,14 @@ describe "class_table_inheritance plugin" do
51
51
  Object.send(:remove_const, :Employee)
52
52
  end
53
53
 
54
+ it "should not attempt to use prepared statements" do
55
+ Manager.plugin :prepared_statements
56
+ Manager[1]
57
+ @db.sqls.must_equal ["SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id = 1) LIMIT 1"]
58
+ Manager.load(:id=>1, :kind=>'Manager', :num_staff=>2).save
59
+ @db.sqls.must_equal ["UPDATE employees SET kind = 'Manager' WHERE (id = 1)", "UPDATE managers SET num_staff = 2 WHERE (id = 1)"]
60
+ end
61
+
54
62
  it "#cti_base_model should be the model that loaded the plugin" do
55
63
  Executive.cti_base_model.must_equal Employee
56
64
  end
@@ -98,6 +98,14 @@ describe "Sequel::Plugins::ColumnSelect" do
98
98
  @Album.dataset.sql.must_equal 'SELECT albums.id, albums.a, albums.b, albums.c FROM albums'
99
99
  end
100
100
 
101
+ it "should handle case where schema parsing and columns does not produce results" do
102
+ def @db.supports_schema_parsing?() true end
103
+ def @db.schema_parse_table(t, *) [] end
104
+ @db.extend_datasets{def columns; raise Sequel::DatabaseError; end}
105
+ @Album.plugin :column_select
106
+ @Album.dataset.sql.must_equal 'SELECT * FROM albums'
107
+ end
108
+
101
109
  it "works correctly when loaded on model without a dataset" do
102
110
  c = Class.new(Sequel::Model)
103
111
  c.plugin :column_select
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
- if RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby'
3
+ if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') # || (RUBY_VERSION >= '2.3.0' && RUBY_ENGINE == 'jruby')
4
4
  Sequel.extension :core_refinements, :pg_array, :pg_hstore, :pg_row, :pg_range, :pg_row_ops, :pg_range_ops, :pg_array_ops, :pg_hstore_ops, :pg_json, :pg_json_ops
5
5
  using Sequel::CoreRefinements
6
6
 
@@ -26,6 +26,7 @@ describe "Sequel::Plugins::DatasetAssociations" do
26
26
  @Album.columns :id, :name, :artist_id
27
27
  @Tag.columns :id, :name
28
28
 
29
+ @Album.plugin :many_through_many
29
30
  @Artist.plugin :many_through_many
30
31
  @Artist.plugin :pg_array_associations
31
32
  @Tag.plugin :pg_array_associations
@@ -33,6 +34,7 @@ describe "Sequel::Plugins::DatasetAssociations" do
33
34
  @Artist.one_to_one :first_album, :class=>@Album
34
35
  @Album.many_to_one :artist, :class=>@Artist
35
36
  @Album.many_to_many :tags, :class=>@Tag
37
+ @Album.many_through_many :mthm_tags, [[:albums_tags, :album_id, :tag_id]], :class=>@Tag
36
38
  @Album.one_through_one :first_tag, :class=>@Tag, :right_key=>:tag_id
37
39
  @Tag.many_to_many :albums, :class=>@Album
38
40
  @Artist.pg_array_to_many :artist_tags, :class=>@Tag, :key=>:tag_ids
@@ -83,6 +85,13 @@ describe "Sequel::Plugins::DatasetAssociations" do
83
85
  ds.sql.must_equal "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM artists INNER JOIN albums ON (albums.artist_id = artists.id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) INNER JOIN tags ON (tags.id = albums_tags.tag_id) WHERE (albums.artist_id IN (SELECT artists.id FROM artists))))"
84
86
  end
85
87
 
88
+ it "should work for many_through_many associations with a single join table" do
89
+ ds = @Album.mthm_tags
90
+ ds.must_be_kind_of(Sequel::Dataset)
91
+ ds.model.must_equal @Tag
92
+ ds.sql.must_equal "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE (albums_tags.album_id IN (SELECT albums.id FROM albums))))"
93
+ end
94
+
86
95
  it "should work for one_through_many associations" do
87
96
  ds = @Artist.otags
88
97
  ds.must_be_kind_of(Sequel::Dataset)
@@ -12,6 +12,26 @@ describe "Sequel::Plugins::InsertReturningSelect" do
12
12
  @db.sqls
13
13
  end
14
14
 
15
+ it "should work if loaded into a model without a dataset that also uses the lazy_attributes or dataset associations plugins" do
16
+ c = Sequel::Model(@db)
17
+ c.plugin :insert_returning_select
18
+ c.columns :id, :x
19
+ c.plugin :lazy_attributes
20
+ c.plugin :dataset_associations
21
+
22
+ c.set_dataset @db[:albums].select(:id, :x)
23
+ c.plugin :lazy_attributes, :x
24
+ c.many_to_one :c, :key=>:id, :class=>c
25
+ @db.sqls
26
+
27
+ c.dataset.sql.must_equal 'SELECT id FROM albums'
28
+ c.create(:x=>2)
29
+ @db.sqls.must_equal ['INSERT INTO albums (x) VALUES (2) RETURNING id']
30
+ c.load(:id=>2).x
31
+ @db.sqls.must_equal ['SELECT albums.x FROM albums WHERE (id = 2) LIMIT 1']
32
+ c.dataset.cs.sql.must_equal "SELECT id FROM albums WHERE (albums.id IN (SELECT albums.id FROM albums))"
33
+ end
34
+
15
35
  it "should add a returning clause when inserting using selected columns" do
16
36
  @Album.plugin :insert_returning_select
17
37
  @Album.create(:x=>2).must_equal @Album.load(:id=>1, :x=>2)
@@ -17,6 +17,13 @@ describe "prepared_statements plugin" do
17
17
  @db.sqls.must_equal ["SELECT id, name, i FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
18
18
  end
19
19
 
20
+ it "should correctly lookup by primary key for joined dataset" do
21
+ @c.dataset = @c.dataset.from(:people, :people2)
22
+ @db.sqls
23
+ @c[1].must_equal @p
24
+ @db.sqls.must_equal ["SELECT * FROM people, people2 WHERE (people.id = 1) LIMIT 1 -- read_only"]
25
+ end
26
+
20
27
  prepared_statements_spec = shared_description do
21
28
  it "should correctly delete instance" do
22
29
  @p.destroy.must_equal @p
@@ -0,0 +1,60 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ Sequel.extension :s
4
+
5
+ describe "s extension as refinement" do
6
+ include Sequel::S
7
+
8
+ before do
9
+ @db = Sequel.mock
10
+ end
11
+
12
+ it "S should be callable with different arguments" do
13
+ @db.literal(S(:s) + 1).must_equal "(s + 1)"
14
+ @db.literal(S('s') + '1').must_equal "('s' || '1')"
15
+ @db.literal(~S([[:s, 1], [:z, 2]])).must_equal "((s != 1) OR (z != 2))"
16
+ end
17
+
18
+ it "S should be callable with blocks" do
19
+ @db.literal(S{x + 1}).must_equal "(x + 1)"
20
+ end
21
+
22
+ it "S should raise an error if called with multiple objects" do
23
+ proc{S(:x, 1)}.must_raise ArgumentError
24
+ end
25
+
26
+ it "S should raise an error if called with objects and block" do
27
+ proc{S(:x){}}.must_raise Sequel::Error
28
+ end
29
+ end
30
+
31
+
32
+ if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') # || (RUBY_VERSION >= '2.3.0' && RUBY_ENGINE == 'jruby')
33
+ using Sequel::S
34
+
35
+ describe "s extension as refinement" do
36
+ before do
37
+ @db = Sequel.mock
38
+ end
39
+
40
+ it "S should be callable with different arguments" do
41
+ @db.literal(S(:s) + 1).must_equal "(s + 1)"
42
+ @db.literal(S('s') + '1').must_equal "('s' || '1')"
43
+ @db.literal(~S([[:s, 1], [:z, 2]])).must_equal "((s != 1) OR (z != 2))"
44
+ end
45
+
46
+ it "S should be callable with blocks" do
47
+ @db.literal(S{x + 1}).must_equal "(x + 1)"
48
+ end
49
+
50
+ it "S should raise an error if called with multiple objects" do
51
+ proc{S(:x, 1)}.must_raise ArgumentError
52
+ end
53
+
54
+ it "S should raise an error if called with objects and block" do
55
+ proc{S(:x){}}.must_raise Sequel::Error
56
+ end
57
+ end
58
+ end
59
+
60
+
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') || (RUBY_VERSION >= '2.3.0' && RUBY_ENGINE == 'jruby')
4
+ Sequel.extension :symbol_aref_refinement
5
+ using Sequel::SymbolAref
6
+
7
+ describe "symbol_aref_refinement extension" do
8
+ before do
9
+ @db = Sequel.mock
10
+ end
11
+
12
+ it "Symbol#[] should create qualified identifier if given a symbol" do
13
+ @db.literal(:x[:y]).must_equal "x.y"
14
+ end
15
+
16
+ it "Symbol#[] should create qualified identifier if given an identifier" do
17
+ @db.literal(:x[Sequel[:y]]).must_equal "x.y"
18
+ end
19
+
20
+ it "Symbol#[] should create qualified identifier if given a qualified identifier" do
21
+ @db.literal(:x[:y[:z]]).must_equal "x.y.z"
22
+ end
23
+
24
+ it "should not affect other arguments to Symbol#[]" do
25
+ :x[0].must_equal "x"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') || (RUBY_VERSION >= '2.3.0' && RUBY_ENGINE == 'jruby')
4
+ Sequel.extension :symbol_as_refinement
5
+ using Sequel::SymbolAs
6
+
7
+ describe "symbol_as_refinement extension" do
8
+ before do
9
+ @db = Sequel.mock
10
+ end
11
+
12
+ it "Symbol#as should create aliased expression" do
13
+ @db.literal(:x.as(:y)).must_equal "x AS y"
14
+ end
15
+
16
+ it "Symbol#as should create aliased expression with columns" do
17
+ @db.literal(:x.as(:y, [:c1, :c2])).must_equal "x AS y(c1, c2)"
18
+ end
19
+ end
20
+ end
21
+