sequel 4.8.0 → 4.9.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.
- checksums.yaml +4 -4
- data/CHANGELOG +48 -0
- data/doc/association_basics.rdoc +1 -1
- data/doc/opening_databases.rdoc +4 -0
- data/doc/postgresql.rdoc +27 -3
- data/doc/release_notes/4.9.0.txt +190 -0
- data/doc/security.rdoc +1 -1
- data/doc/testing.rdoc +2 -2
- data/doc/validations.rdoc +8 -0
- data/lib/sequel/adapters/jdbc.rb +5 -3
- data/lib/sequel/adapters/jdbc/derby.rb +2 -8
- data/lib/sequel/adapters/jdbc/h2.rb +2 -13
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -16
- data/lib/sequel/adapters/mysql2.rb +11 -1
- data/lib/sequel/adapters/postgres.rb +33 -10
- data/lib/sequel/adapters/shared/db2.rb +2 -10
- data/lib/sequel/adapters/shared/mssql.rb +10 -8
- data/lib/sequel/adapters/shared/oracle.rb +9 -24
- data/lib/sequel/adapters/shared/postgres.rb +32 -9
- data/lib/sequel/adapters/shared/sqlanywhere.rb +2 -4
- data/lib/sequel/adapters/shared/sqlite.rb +4 -7
- data/lib/sequel/database/schema_methods.rb +15 -0
- data/lib/sequel/dataset.rb +1 -1
- data/lib/sequel/dataset/actions.rb +159 -27
- data/lib/sequel/dataset/graph.rb +29 -7
- data/lib/sequel/dataset/misc.rb +6 -0
- data/lib/sequel/dataset/placeholder_literalizer.rb +164 -0
- data/lib/sequel/dataset/query.rb +2 -0
- data/lib/sequel/dataset/sql.rb +103 -91
- data/lib/sequel/extensions/current_datetime_timestamp.rb +57 -0
- data/lib/sequel/extensions/pg_array.rb +68 -106
- data/lib/sequel/extensions/pg_hstore.rb +5 -5
- data/lib/sequel/extensions/schema_dumper.rb +49 -49
- data/lib/sequel/model.rb +4 -2
- data/lib/sequel/model/associations.rb +1 -1
- data/lib/sequel/model/base.rb +136 -3
- data/lib/sequel/model/errors.rb +6 -0
- data/lib/sequel/plugins/defaults_setter.rb +1 -1
- data/lib/sequel/plugins/eager_each.rb +9 -0
- data/lib/sequel/plugins/nested_attributes.rb +2 -2
- data/lib/sequel/plugins/timestamps.rb +2 -2
- data/lib/sequel/plugins/touch.rb +2 -2
- data/lib/sequel/sql.rb +20 -15
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +70 -8
- data/spec/core/dataset_spec.rb +172 -27
- data/spec/core/expression_filters_spec.rb +3 -3
- data/spec/core/object_graph_spec.rb +17 -1
- data/spec/core/placeholder_literalizer_spec.rb +128 -0
- data/spec/core/schema_spec.rb +54 -0
- data/spec/extensions/current_datetime_timestamp_spec.rb +27 -0
- data/spec/extensions/defaults_setter_spec.rb +12 -0
- data/spec/extensions/eager_each_spec.rb +6 -0
- data/spec/extensions/nested_attributes_spec.rb +14 -2
- data/spec/extensions/pg_array_spec.rb +15 -7
- data/spec/extensions/shared_caching_spec.rb +5 -5
- data/spec/extensions/timestamps_spec.rb +9 -0
- data/spec/extensions/touch_spec.rb +9 -0
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +27 -5
- data/spec/model/eager_loading_spec.rb +32 -0
- data/spec/model/model_spec.rb +119 -9
- metadata +8 -2
data/spec/core/dataset_spec.rb
CHANGED
@@ -3254,46 +3254,30 @@ describe "Dataset#grep" do
|
|
3254
3254
|
end
|
3255
3255
|
end
|
3256
3256
|
|
3257
|
-
describe "Dataset default #fetch_rows, #insert, #update, #delete, #
|
3257
|
+
describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #execute" do
|
3258
3258
|
before do
|
3259
|
-
@db = Sequel
|
3259
|
+
@db = Sequel.mock(:servers=>{:read_only=>{}}, :autoid=>1)
|
3260
3260
|
@ds = @db[:items]
|
3261
3261
|
end
|
3262
3262
|
|
3263
3263
|
specify "#delete should execute delete SQL" do
|
3264
|
-
@
|
3265
|
-
@
|
3266
|
-
@db.should_receive(:execute_dui).once.with('DELETE FROM items', :server=>:default)
|
3267
|
-
@ds.delete
|
3268
|
-
end
|
3269
|
-
|
3270
|
-
specify "#with_sql_delete should execute delete SQL" do
|
3271
|
-
sql = 'DELETE FROM foo'
|
3272
|
-
@db.should_receive(:execute).once.with(sql, :server=>:default)
|
3273
|
-
@ds.with_sql_delete(sql)
|
3274
|
-
@db.should_receive(:execute_dui).once.with(sql, :server=>:default)
|
3275
|
-
@ds.with_sql_delete(sql)
|
3264
|
+
@ds.delete.should == 0
|
3265
|
+
@db.sqls.should == ["DELETE FROM items"]
|
3276
3266
|
end
|
3277
3267
|
|
3278
3268
|
specify "#insert should execute insert SQL" do
|
3279
|
-
@
|
3280
|
-
@
|
3281
|
-
@db.should_receive(:execute_insert).once.with('INSERT INTO items DEFAULT VALUES', :server=>:default)
|
3282
|
-
@ds.insert([])
|
3269
|
+
@ds.insert([]).should == 1
|
3270
|
+
@db.sqls.should == ["INSERT INTO items DEFAULT VALUES"]
|
3283
3271
|
end
|
3284
3272
|
|
3285
3273
|
specify "#update should execute update SQL" do
|
3286
|
-
@
|
3287
|
-
@
|
3288
|
-
@db.should_receive(:execute_dui).once.with('UPDATE items SET number = 1', :server=>:default)
|
3289
|
-
@ds.update(:number=>1)
|
3274
|
+
@ds.update(:number=>1).should == 0
|
3275
|
+
@db.sqls.should == ["UPDATE items SET number = 1"]
|
3290
3276
|
end
|
3291
3277
|
|
3292
3278
|
specify "#truncate should execute truncate SQL" do
|
3293
|
-
@db.should_receive(:execute).once.with('TRUNCATE TABLE items', :server=>:default)
|
3294
|
-
@ds.truncate.should == nil
|
3295
|
-
@db.should_receive(:execute_ddl).once.with('TRUNCATE TABLE items', :server=>:default)
|
3296
3279
|
@ds.truncate.should == nil
|
3280
|
+
@db.sqls.should == ["TRUNCATE TABLE items"]
|
3297
3281
|
end
|
3298
3282
|
|
3299
3283
|
specify "#truncate should raise an InvalidOperation exception if the dataset is filtered" do
|
@@ -3302,8 +3286,71 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #with_sql_dele
|
|
3302
3286
|
end
|
3303
3287
|
|
3304
3288
|
specify "#execute should execute the SQL on the database" do
|
3305
|
-
@db.should_receive(:execute).once.with('SELECT 1', :server=>:read_only)
|
3306
3289
|
@ds.send(:execute, 'SELECT 1')
|
3290
|
+
@db.sqls.should == ["SELECT 1 -- read_only"]
|
3291
|
+
end
|
3292
|
+
end
|
3293
|
+
|
3294
|
+
describe "Dataset#with_sql_*" do
|
3295
|
+
before do
|
3296
|
+
@db = Sequel.mock(:servers=>{:read_only=>{}}, :autoid=>1, :fetch=>{:id=>1})
|
3297
|
+
@ds = @db[:items]
|
3298
|
+
end
|
3299
|
+
|
3300
|
+
specify "#with_sql_insert should execute given insert SQL" do
|
3301
|
+
@ds.with_sql_insert('INSERT INTO foo (1)').should == 1
|
3302
|
+
@db.sqls.should == ["INSERT INTO foo (1)"]
|
3303
|
+
end
|
3304
|
+
|
3305
|
+
specify "#with_sql_delete should execute given delete SQL" do
|
3306
|
+
@ds.with_sql_delete('DELETE FROM foo').should == 0
|
3307
|
+
@db.sqls.should == ["DELETE FROM foo"]
|
3308
|
+
end
|
3309
|
+
|
3310
|
+
specify "#with_sql_update should execute given update SQL" do
|
3311
|
+
@ds.with_sql_update('UPDATE foo SET a = 1').should == 0
|
3312
|
+
@db.sqls.should == ["UPDATE foo SET a = 1"]
|
3313
|
+
end
|
3314
|
+
|
3315
|
+
specify "#with_sql_all should return all rows from running the SQL" do
|
3316
|
+
@ds.with_sql_all('SELECT * FROM foo').should == [{:id=>1}]
|
3317
|
+
@db.sqls.should == ["SELECT * FROM foo -- read_only"]
|
3318
|
+
end
|
3319
|
+
|
3320
|
+
specify "#with_sql_all should yield each row to the block" do
|
3321
|
+
a = []
|
3322
|
+
@ds.with_sql_all('SELECT * FROM foo'){|r| a << r}
|
3323
|
+
a.should == [{:id=>1}]
|
3324
|
+
@db.sqls.should == ["SELECT * FROM foo -- read_only"]
|
3325
|
+
end
|
3326
|
+
|
3327
|
+
specify "#with_sql_each should yield each row to the block" do
|
3328
|
+
a = []
|
3329
|
+
@ds.with_sql_each('SELECT * FROM foo'){|r| a << r}
|
3330
|
+
a.should == [{:id=>1}]
|
3331
|
+
@db.sqls.should == ["SELECT * FROM foo -- read_only"]
|
3332
|
+
end
|
3333
|
+
|
3334
|
+
specify "#with_sql_first should return first row" do
|
3335
|
+
@ds.with_sql_first('SELECT * FROM foo').should == {:id=>1}
|
3336
|
+
@db.sqls.should == ["SELECT * FROM foo -- read_only"]
|
3337
|
+
end
|
3338
|
+
|
3339
|
+
specify "#with_sql_first should return nil if no rows returned" do
|
3340
|
+
@db.fetch = []
|
3341
|
+
@ds.with_sql_first('SELECT * FROM foo').should == nil
|
3342
|
+
@db.sqls.should == ["SELECT * FROM foo -- read_only"]
|
3343
|
+
end
|
3344
|
+
|
3345
|
+
specify "#with_sql_single_value should return first value from first row" do
|
3346
|
+
@ds.with_sql_single_value('SELECT * FROM foo').should == 1
|
3347
|
+
@db.sqls.should == ["SELECT * FROM foo -- read_only"]
|
3348
|
+
end
|
3349
|
+
|
3350
|
+
specify "#with_sql_single_value should return nil if no rows returned" do
|
3351
|
+
@db.fetch = []
|
3352
|
+
@ds.with_sql_single_value('SELECT * FROM foo').should == nil
|
3353
|
+
@db.sqls.should == ["SELECT * FROM foo -- read_only"]
|
3307
3354
|
end
|
3308
3355
|
end
|
3309
3356
|
|
@@ -4314,7 +4361,7 @@ describe "Dataset emulating bitwise operator support" do
|
|
4314
4361
|
@ds = Sequel::Database.new.dataset
|
4315
4362
|
@ds.quote_identifiers = true
|
4316
4363
|
def @ds.complex_expression_sql_append(sql, op, args)
|
4317
|
-
sql
|
4364
|
+
complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.function(:bitand, a, b)}
|
4318
4365
|
end
|
4319
4366
|
end
|
4320
4367
|
|
@@ -4562,6 +4609,49 @@ describe "Dataset#paged_each" do
|
|
4562
4609
|
@ds.limit(nil, 2).paged_each(:rows_per_fetch=>3, &@proc)
|
4563
4610
|
@ds.db.sqls[1...-1].should == ["SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 2", "SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 5", "SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 8", "SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 11"]
|
4564
4611
|
end
|
4612
|
+
|
4613
|
+
it "should support :strategy=>:filter" do
|
4614
|
+
@ds._fetch = @db.each_slice(5).to_a
|
4615
|
+
@ds.paged_each(:rows_per_fetch=>5, :strategy=>:filter, &@proc)
|
4616
|
+
@ds.db.sqls[1...-1].should == ["SELECT * FROM test ORDER BY x LIMIT 5", "SELECT * FROM test WHERE (x > 4) ORDER BY x LIMIT 5", "SELECT * FROM test WHERE (x > 9) ORDER BY x LIMIT 5"]
|
4617
|
+
@rows.should == @db
|
4618
|
+
|
4619
|
+
@rows = []
|
4620
|
+
db = @db.map{|h| h[:y] = h[:x] % 5; h[:z] = h[:x] % 9; h}.sort_by{|h| [h[:z], -h[:y], h[:x]]}
|
4621
|
+
@ds._fetch = db.each_slice(5).to_a
|
4622
|
+
@ds.order(Sequel.identifier(:z), Sequel.desc(Sequel.qualify(:test, :y)), Sequel.asc(:x)).paged_each(:rows_per_fetch=>5, :strategy=>:filter, &@proc)
|
4623
|
+
@ds.db.sqls[1...-1].should == ["SELECT * FROM test ORDER BY z, test.y DESC, x ASC LIMIT 5",
|
4624
|
+
"SELECT * FROM test WHERE ((z > 3) OR ((z = 3) AND (test.y < 3)) OR ((z = 3) AND (test.y = 3) AND (x > 3))) ORDER BY z, test.y DESC, x ASC LIMIT 5",
|
4625
|
+
"SELECT * FROM test WHERE ((z > 8) OR ((z = 8) AND (test.y < 3)) OR ((z = 8) AND (test.y = 3) AND (x > 8))) ORDER BY z, test.y DESC, x ASC LIMIT 5"]
|
4626
|
+
@rows.should == db
|
4627
|
+
end
|
4628
|
+
|
4629
|
+
it "should support :strategy=>:filter with :filter_values option" do
|
4630
|
+
db = @db.map{|h| h[:y] = h[:x] % 5; h[:z] = h[:x] % 9; h}.sort_by{|h| [h[:z], -h[:y], h[:x]]}
|
4631
|
+
@ds._fetch = db.each_slice(5).to_a
|
4632
|
+
@ds.order(Sequel.identifier(:z), Sequel.desc(Sequel.qualify(:test, :y) * 2), Sequel.asc(:x)).paged_each(:rows_per_fetch=>5, :strategy=>:filter, :filter_values=>proc{|row, expr| [row[expr[0].value], row[expr[1].args.first.column] * expr[1].args.last, row[expr[2]]]}, &@proc)
|
4633
|
+
@ds.db.sqls[1...-1].should == ["SELECT * FROM test ORDER BY z, (test.y * 2) DESC, x ASC LIMIT 5",
|
4634
|
+
"SELECT * FROM test WHERE ((z > 3) OR ((z = 3) AND ((test.y * 2) < 6)) OR ((z = 3) AND ((test.y * 2) = 6) AND (x > 3))) ORDER BY z, (test.y * 2) DESC, x ASC LIMIT 5",
|
4635
|
+
"SELECT * FROM test WHERE ((z > 8) OR ((z = 8) AND ((test.y * 2) < 6)) OR ((z = 8) AND ((test.y * 2) = 6) AND (x > 8))) ORDER BY z, (test.y * 2) DESC, x ASC LIMIT 5"]
|
4636
|
+
@rows.should == db
|
4637
|
+
end
|
4638
|
+
end
|
4639
|
+
|
4640
|
+
describe "Dataset#current_datetime" do
|
4641
|
+
after do
|
4642
|
+
Sequel.datetime_class = Time
|
4643
|
+
end
|
4644
|
+
|
4645
|
+
it "should return an instance of Sequel.datetime_class for the current datetime" do
|
4646
|
+
t = Sequel::Dataset.new(nil).current_datetime
|
4647
|
+
t.should be_a_kind_of(Time)
|
4648
|
+
(Time.now - t < 0.1).should == true
|
4649
|
+
|
4650
|
+
Sequel.datetime_class = DateTime
|
4651
|
+
t = Sequel::Dataset.new(nil).current_datetime
|
4652
|
+
t.should be_a_kind_of(DateTime)
|
4653
|
+
(DateTime.now - t < (0.1/86400)).should == true
|
4654
|
+
end
|
4565
4655
|
end
|
4566
4656
|
|
4567
4657
|
describe "Dataset#escape_like" do
|
@@ -4693,3 +4783,58 @@ describe "Dataset mutation methods" do
|
|
4693
4783
|
dsc.graph!(dsc, {:b=>:c}, :table_alias=>:foo).ungraphed!.opts[:graph].should be_nil
|
4694
4784
|
end
|
4695
4785
|
end
|
4786
|
+
|
4787
|
+
describe "Dataset emulated complex expression operators" do
|
4788
|
+
before do
|
4789
|
+
@ds = Sequel.mock[:test]
|
4790
|
+
def @ds.complex_expression_sql_append(sql, op, args)
|
4791
|
+
case op
|
4792
|
+
when :&, :|, :^, :%, :<<, :>>, :'B~'
|
4793
|
+
complex_expression_emulate_append(sql, op, args)
|
4794
|
+
else
|
4795
|
+
super
|
4796
|
+
end
|
4797
|
+
end
|
4798
|
+
@n = Sequel.expr(:x).sql_number
|
4799
|
+
end
|
4800
|
+
|
4801
|
+
it "should emulate &" do
|
4802
|
+
@ds.literal(Sequel::SQL::NumericExpression.new(:&, @n)).should == "x"
|
4803
|
+
@ds.literal(@n & 1).should == "BITAND(x, 1)"
|
4804
|
+
@ds.literal(@n & 1 & 2).should == "BITAND(BITAND(x, 1), 2)"
|
4805
|
+
end
|
4806
|
+
|
4807
|
+
it "should emulate |" do
|
4808
|
+
@ds.literal(Sequel::SQL::NumericExpression.new(:|, @n)).should == "x"
|
4809
|
+
@ds.literal(@n | 1).should == "BITOR(x, 1)"
|
4810
|
+
@ds.literal(@n | 1 | 2).should == "BITOR(BITOR(x, 1), 2)"
|
4811
|
+
end
|
4812
|
+
|
4813
|
+
it "should emulate ^" do
|
4814
|
+
@ds.literal(Sequel::SQL::NumericExpression.new(:^, @n)).should == "x"
|
4815
|
+
@ds.literal(@n ^ 1).should == "BITXOR(x, 1)"
|
4816
|
+
@ds.literal(@n ^ 1 ^ 2).should == "BITXOR(BITXOR(x, 1), 2)"
|
4817
|
+
end
|
4818
|
+
|
4819
|
+
it "should emulate %" do
|
4820
|
+
@ds.literal(Sequel::SQL::NumericExpression.new(:%, @n)).should == "x"
|
4821
|
+
@ds.literal(@n % 1).should == "MOD(x, 1)"
|
4822
|
+
@ds.literal(@n % 1 % 2).should == "MOD(MOD(x, 1), 2)"
|
4823
|
+
end
|
4824
|
+
|
4825
|
+
it "should emulate >>" do
|
4826
|
+
@ds.literal(Sequel::SQL::NumericExpression.new(:>>, @n)).should == "x"
|
4827
|
+
@ds.literal(@n >> 1).should == "(x / power(2, 1))"
|
4828
|
+
@ds.literal(@n >> 1 >> 2).should == "(x / power(2, 1) / power(2, 2))"
|
4829
|
+
end
|
4830
|
+
|
4831
|
+
it "should emulate <<" do
|
4832
|
+
@ds.literal(Sequel::SQL::NumericExpression.new(:<<, @n)).should == "x"
|
4833
|
+
@ds.literal(@n << 1).should == "(x * power(2, 1))"
|
4834
|
+
@ds.literal(@n << 1 << 2).should == "(x * power(2, 1) * power(2, 2))"
|
4835
|
+
end
|
4836
|
+
|
4837
|
+
it "should emulate B~" do
|
4838
|
+
@ds.literal(~@n).should == "((0 - x) - 1)"
|
4839
|
+
end
|
4840
|
+
end
|
@@ -714,7 +714,7 @@ describe "Sequel core extension replacements" do
|
|
714
714
|
end
|
715
715
|
|
716
716
|
it "Sequel.& should join all arguments given with AND" do
|
717
|
-
l(Sequel.&(:a), "
|
717
|
+
l(Sequel.&(:a), "a")
|
718
718
|
l(Sequel.&(:a, :b=>:c), "(a AND (b = c))")
|
719
719
|
l(Sequel.&(:a, {:b=>:c}, Sequel.lit('d')), "(a AND (b = c) AND d)")
|
720
720
|
end
|
@@ -724,7 +724,7 @@ describe "Sequel core extension replacements" do
|
|
724
724
|
end
|
725
725
|
|
726
726
|
it "Sequel.| should join all arguments given with OR" do
|
727
|
-
l(Sequel.|(:a), "
|
727
|
+
l(Sequel.|(:a), "a")
|
728
728
|
l(Sequel.|(:a, :b=>:c), "(a OR (b = c))")
|
729
729
|
l(Sequel.|(:a, {:b=>:c}, Sequel.lit('d')), "(a OR (b = c) OR d)")
|
730
730
|
end
|
@@ -808,7 +808,7 @@ describe "Sequel core extension replacements" do
|
|
808
808
|
|
809
809
|
it "Sequel.{+,-,*,/} should accept arguments and use the appropriate operator" do
|
810
810
|
%w'+ - * /'.each do |op|
|
811
|
-
l(Sequel.send(op, 1), '
|
811
|
+
l(Sequel.send(op, 1), '1')
|
812
812
|
l(Sequel.send(op, 1, 2), "(1 #{op} 2)")
|
813
813
|
l(Sequel.send(op, 1, 2, 3), "(1 #{op} 2 #{op} 3)")
|
814
814
|
end
|
@@ -104,11 +104,20 @@ describe Sequel::Dataset, "graphing" do
|
|
104
104
|
|
105
105
|
it "should accept a SQL::Identifier as the dataset" do
|
106
106
|
ds = @ds1.graph(Sequel.identifier(:lines), :x=>:id)
|
107
|
-
ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines
|
107
|
+
ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
|
108
108
|
ds = @ds1.graph(Sequel.identifier('lines'), :x=>:id)
|
109
109
|
ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines AS lines ON (lines.x = points.id)'
|
110
110
|
end
|
111
111
|
|
112
|
+
it "should handle a SQL::Identifier with double underscores correctly" do
|
113
|
+
ds = @ds1.graph(Sequel.identifier(:lin__es), :x=>:id)
|
114
|
+
ds.sql.should == 'SELECT points.id, points.x, points.y, lin__es.id AS lin__es_id, lin__es.name, lin__es.x AS lin__es_x, lin__es.y AS lin__es_y, lin__es.lines_x FROM points LEFT OUTER JOIN lin__es ON (lin__es.x = points.id)'
|
115
|
+
ds = @ds1.from(Sequel.identifier(:poi__nts)).graph(Sequel.identifier(:lin__es), :x=>:id)
|
116
|
+
ds.sql.should == 'SELECT poi__nts.id, poi__nts.name, poi__nts.x, poi__nts.y, poi__nts.lines_x, lin__es.id AS lin__es_id, lin__es.name AS lin__es_name, lin__es.x AS lin__es_x, lin__es.y AS lin__es_y, lin__es.lines_x AS lin__es_lines_x FROM poi__nts LEFT OUTER JOIN lin__es ON (lin__es.x = poi__nts.id)'
|
117
|
+
ds = @ds1.from(Sequel.identifier(:poi__nts).qualify(:foo)).graph(Sequel.identifier(:lin__es).qualify(:bar), :x=>:id)
|
118
|
+
ds.sql.should == 'SELECT foo.poi__nts.id, foo.poi__nts.x, foo.poi__nts.y, foo.poi__nts.graph_id, lin__es.id AS lin__es_id, lin__es.name, lin__es.x AS lin__es_x, lin__es.y AS lin__es_y, lin__es.lines_x FROM foo.poi__nts LEFT OUTER JOIN bar.lin__es AS lin__es ON (lin__es.x = foo.poi__nts.id)'
|
119
|
+
end
|
120
|
+
|
112
121
|
it "should accept a SQL::QualifiedIdentifier as the dataset" do
|
113
122
|
ds = @ds1.graph(Sequel.qualify(:schema, :lines), :x=>:id)
|
114
123
|
ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN schema.lines AS lines ON (lines.x = points.id)'
|
@@ -120,6 +129,13 @@ describe Sequel::Dataset, "graphing" do
|
|
120
129
|
ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN schema.lines AS lines ON (lines.x = points.id)'
|
121
130
|
end
|
122
131
|
|
132
|
+
it "should handle a qualified identifier as the source" do
|
133
|
+
ds = @ds1.from(:schema__points).graph(:lines, :x=>:id)
|
134
|
+
ds.sql.should == 'SELECT schema.points.id, schema.points.x, schema.points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM schema.points LEFT OUTER JOIN lines ON (lines.x = schema.points.id)'
|
135
|
+
ds = @ds1.from(Sequel.qualify(:schema, :points)).graph(:lines, :x=>:id)
|
136
|
+
ds.sql.should == 'SELECT schema.points.id, schema.points.x, schema.points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM schema.points LEFT OUTER JOIN lines ON (lines.x = schema.points.id)'
|
137
|
+
end
|
138
|
+
|
123
139
|
it "should accept a SQL::AliasedExpression as the dataset" do
|
124
140
|
ds = @ds1.graph(Sequel.as(:lines, :foo), :x=>:id)
|
125
141
|
ds.sql.should == 'SELECT points.id, points.x, points.y, foo.id AS foo_id, foo.x AS foo_x, foo.y AS foo_y, foo.graph_id FROM points LEFT OUTER JOIN lines AS foo ON (foo.x = points.id)'
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Dataset::PlaceholderLiteralizer" do
|
4
|
+
before do
|
5
|
+
@c = Sequel::Dataset::PlaceholderLiteralizer
|
6
|
+
@db = Sequel.mock
|
7
|
+
@ds = @db[:items]
|
8
|
+
@h = {:id=>1}
|
9
|
+
@ds.db.fetch = @h
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "should handle calls with no placeholders" do
|
13
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>1)}
|
14
|
+
loader.first.should == @h
|
15
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (a = 1)"]
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "should handle calls with a single placeholder" do
|
19
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg)}
|
20
|
+
loader.first(1).should == @h
|
21
|
+
loader.first(2).should == @h
|
22
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (a = 1)", "SELECT * FROM items WHERE (a = 2)"]
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "should handle calls with multiple placeholders" do
|
26
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg).where(:b=>Sequel.+(pl.arg, 1)).where(pl.arg)}
|
27
|
+
loader.first(1, :c, :id=>1).should == @h
|
28
|
+
loader.first(2, :d, :id=>2).should == @h
|
29
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((a = 1) AND (b = (c + 1)) AND (id = 1))", "SELECT * FROM items WHERE ((a = 2) AND (b = (d + 1)) AND (id = 2))"]
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "should handle calls with a placeholders used as filter arguments" do
|
33
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(pl.arg)}
|
34
|
+
loader.first(:id=>1).should == @h
|
35
|
+
loader.first(proc{a(b)}).should == @h
|
36
|
+
loader.first("a = 1").should == @h
|
37
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (id = 1)", "SELECT * FROM items WHERE a(b)", "SELECT * FROM items WHERE (a = 1)"]
|
38
|
+
end
|
39
|
+
|
40
|
+
specify "should handle calls with a placeholders used as right hand side of condition specifiers" do
|
41
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg)}
|
42
|
+
loader.first(1).should == @h
|
43
|
+
loader.first([1, 2]).should == @h
|
44
|
+
loader.first(nil).should == @h
|
45
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (a = 1)", "SELECT * FROM items WHERE (a IN (1, 2))", "SELECT * FROM items WHERE (a IS NULL)"]
|
46
|
+
end
|
47
|
+
|
48
|
+
specify "should handle calls with a placeholder used multiple times" do
|
49
|
+
loader = @c.loader(@ds){|pl, ds| a = pl.arg; ds.where(:a=>a).where(:b=>a)}
|
50
|
+
loader.first(1).should == @h
|
51
|
+
loader.first(2).should == @h
|
52
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((a = 1) AND (b = 1))", "SELECT * FROM items WHERE ((a = 2) AND (b = 2))"]
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "should handle calls with a placeholder used multiple times in different capacities" do
|
56
|
+
loader = @c.loader(@ds){|pl, ds| a = pl.arg; ds.where(a).where(:b=>a)}
|
57
|
+
loader.first("a = 1").should == @h
|
58
|
+
loader.first(["a = ?", 2]).should == @h
|
59
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((a = 1) AND (b = 'a = 1'))", "SELECT * FROM items WHERE ((a = 2) AND (b IN ('a = ?', 2)))"]
|
60
|
+
end
|
61
|
+
|
62
|
+
specify "should handle calls with manually specified argument positions" do
|
63
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg(1)).where(:b=>pl.arg(0))}
|
64
|
+
loader.first(1, 2).should == @h
|
65
|
+
loader.first(2, 1).should == @h
|
66
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((a = 2) AND (b = 1))", "SELECT * FROM items WHERE ((a = 1) AND (b = 2))"]
|
67
|
+
end
|
68
|
+
|
69
|
+
specify "should handle dataset with row procs" do
|
70
|
+
@ds.row_proc = proc{|r| {:foo=>r[:id]+1}}
|
71
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg)}
|
72
|
+
loader.first(1).should == {:foo=>2}
|
73
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (a = 1)"]
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "should return all rows for #all" do
|
77
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg)}
|
78
|
+
loader.all(1).should == [@h]
|
79
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (a = 1)"]
|
80
|
+
end
|
81
|
+
|
82
|
+
specify "should iterate over block for #all" do
|
83
|
+
a = []
|
84
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg)}
|
85
|
+
loader.all(1){|r| a << r}.should == [@h]
|
86
|
+
a.should == [@h]
|
87
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (a = 1)"]
|
88
|
+
end
|
89
|
+
|
90
|
+
specify "should iterate over block for #each" do
|
91
|
+
a = []
|
92
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg)}
|
93
|
+
loader.each(1){|r| a << r}
|
94
|
+
a.should == [@h]
|
95
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (a = 1)"]
|
96
|
+
end
|
97
|
+
|
98
|
+
specify "should return first value for #get" do
|
99
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg)}
|
100
|
+
loader.get(2).should == 1
|
101
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (a = 2)"]
|
102
|
+
end
|
103
|
+
|
104
|
+
specify "should raise an error if called with an incorrect number of arguments" do
|
105
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg)}
|
106
|
+
proc{loader.first}.should raise_error(Sequel::Error)
|
107
|
+
proc{loader.first(1, 2)}.should raise_error(Sequel::Error)
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "should raise an error if called with an incorrect number of arguments when manually providing argument positions" do
|
111
|
+
loader = @c.loader(@ds){|pl, ds| ds.where(:a=>pl.arg(1))}
|
112
|
+
proc{loader.first}.should raise_error(Sequel::Error)
|
113
|
+
proc{loader.first(1)}.should raise_error(Sequel::Error)
|
114
|
+
proc{loader.first(1, 2, 3)}.should raise_error(Sequel::Error)
|
115
|
+
end
|
116
|
+
|
117
|
+
specify "should raise an error if argument literalized into a different string than returned by query" do
|
118
|
+
o = Object.new
|
119
|
+
def o.wrap(v)
|
120
|
+
@v = v
|
121
|
+
self
|
122
|
+
end
|
123
|
+
def o.sql_literal(ds)
|
124
|
+
ds.literal(@v)
|
125
|
+
end
|
126
|
+
proc{@c.loader(@ds){|pl, ds| ds.where(o.wrap(pl.arg))}}.should raise_error(Sequel::Error)
|
127
|
+
end
|
128
|
+
end
|
data/spec/core/schema_spec.rb
CHANGED
@@ -701,6 +701,12 @@ describe "DB#create_table!" do
|
|
701
701
|
@db.create_table!(:cats){|*a|}
|
702
702
|
@db.sqls.should == ['DROP TABLE cats', 'CREATE TABLE cats ()']
|
703
703
|
end
|
704
|
+
|
705
|
+
specify "should use IF EXISTS if the database supports it" do
|
706
|
+
meta_def(@db, :supports_drop_table_if_exists?){true}
|
707
|
+
@db.create_table!(:cats){|*a|}
|
708
|
+
@db.sqls.should == ['DROP TABLE IF EXISTS cats', 'CREATE TABLE cats ()']
|
709
|
+
end
|
704
710
|
end
|
705
711
|
|
706
712
|
describe "DB#create_table?" do
|
@@ -775,6 +781,54 @@ describe "DB#create_join_table" do
|
|
775
781
|
end
|
776
782
|
end
|
777
783
|
|
784
|
+
describe "DB#create_join_table?" do
|
785
|
+
before do
|
786
|
+
@db = Sequel.mock
|
787
|
+
end
|
788
|
+
|
789
|
+
specify "should create the table if it does not already exist" do
|
790
|
+
meta_def(@db, :table_exists?){|a| false}
|
791
|
+
@db.create_join_table?(:cat_id=>:cats, :dog_id=>:dogs)
|
792
|
+
@db.sqls.should == ['CREATE TABLE cats_dogs (cat_id integer NOT NULL REFERENCES cats, dog_id integer NOT NULL REFERENCES dogs, PRIMARY KEY (cat_id, dog_id))', 'CREATE INDEX cats_dogs_dog_id_cat_id_index ON cats_dogs (dog_id, cat_id)']
|
793
|
+
end
|
794
|
+
|
795
|
+
specify "should not create the table if it already exists" do
|
796
|
+
meta_def(@db, :table_exists?){|a| true}
|
797
|
+
@db.create_join_table?(:cat_id=>:cats, :dog_id=>:dogs)
|
798
|
+
@db.sqls.should == []
|
799
|
+
end
|
800
|
+
|
801
|
+
specify "should use IF NOT EXISTS if the database supports it" do
|
802
|
+
meta_def(@db, :supports_create_table_if_not_exists?){true}
|
803
|
+
@db.create_join_table?(:cat_id=>:cats, :dog_id=>:dogs)
|
804
|
+
@db.sqls.should == ['CREATE TABLE IF NOT EXISTS cats_dogs (cat_id integer NOT NULL REFERENCES cats, dog_id integer NOT NULL REFERENCES dogs, PRIMARY KEY (cat_id, dog_id))', 'CREATE INDEX cats_dogs_dog_id_cat_id_index ON cats_dogs (dog_id, cat_id)']
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
808
|
+
describe "DB#create_join_table!" do
|
809
|
+
before do
|
810
|
+
@db = Sequel.mock
|
811
|
+
end
|
812
|
+
|
813
|
+
specify "should drop the table first if it already exists" do
|
814
|
+
meta_def(@db, :table_exists?){|a| true}
|
815
|
+
@db.create_join_table!(:cat_id=>:cats, :dog_id=>:dogs)
|
816
|
+
@db.sqls.should == ['DROP TABLE cats_dogs', 'CREATE TABLE cats_dogs (cat_id integer NOT NULL REFERENCES cats, dog_id integer NOT NULL REFERENCES dogs, PRIMARY KEY (cat_id, dog_id))', 'CREATE INDEX cats_dogs_dog_id_cat_id_index ON cats_dogs (dog_id, cat_id)']
|
817
|
+
end
|
818
|
+
|
819
|
+
specify "should not drop the table if it doesn't exists" do
|
820
|
+
meta_def(@db, :table_exists?){|a| false}
|
821
|
+
@db.create_join_table!(:cat_id=>:cats, :dog_id=>:dogs)
|
822
|
+
@db.sqls.should == ['CREATE TABLE cats_dogs (cat_id integer NOT NULL REFERENCES cats, dog_id integer NOT NULL REFERENCES dogs, PRIMARY KEY (cat_id, dog_id))', 'CREATE INDEX cats_dogs_dog_id_cat_id_index ON cats_dogs (dog_id, cat_id)']
|
823
|
+
end
|
824
|
+
|
825
|
+
specify "should use IF EXISTS if the database supports it" do
|
826
|
+
meta_def(@db, :supports_drop_table_if_exists?){true}
|
827
|
+
@db.create_join_table!(:cat_id=>:cats, :dog_id=>:dogs)
|
828
|
+
@db.sqls.should == ['DROP TABLE IF EXISTS cats_dogs', 'CREATE TABLE cats_dogs (cat_id integer NOT NULL REFERENCES cats, dog_id integer NOT NULL REFERENCES dogs, PRIMARY KEY (cat_id, dog_id))', 'CREATE INDEX cats_dogs_dog_id_cat_id_index ON cats_dogs (dog_id, cat_id)']
|
829
|
+
end
|
830
|
+
end
|
831
|
+
|
778
832
|
describe "DB#drop_join_table" do
|
779
833
|
before do
|
780
834
|
@db = Sequel.mock
|