sequel 3.24.0 → 3.25.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.
@@ -326,9 +326,9 @@ module Sequel
326
326
  unless @plugins.include?(m)
327
327
  @plugins << m
328
328
  m.apply(self, *args, &blk) if m.respond_to?(:apply)
329
- include(m::InstanceMethods) if m.const_defined?("InstanceMethods")
330
- extend(m::ClassMethods)if m.const_defined?("ClassMethods")
331
- if m.const_defined?("DatasetMethods")
329
+ include(m::InstanceMethods) if plugin_module_defined?(m, :InstanceMethods)
330
+ extend(m::ClassMethods)if plugin_module_defined?(m, :ClassMethods)
331
+ if plugin_module_defined?(m, :DatasetMethods)
332
332
  dataset.extend(m::DatasetMethods) if @dataset
333
333
  dataset_method_modules << m::DatasetMethods
334
334
  meths = m::DatasetMethods.public_instance_methods.reject{|x| NORMAL_METHOD_NAME_REGEXP !~ x.to_s}
@@ -337,7 +337,7 @@ module Sequel
337
337
  end
338
338
  m.configure(self, *args, &blk) if m.respond_to?(:configure)
339
339
  end
340
-
340
+
341
341
  # Returns primary key attribute hash. If using a composite primary key
342
342
  # value such be an array with values for each primary key in the correct
343
343
  # order. For a standard primary key, value should be an object with a
@@ -419,7 +419,7 @@ module Sequel
419
419
  def set_dataset(ds, opts={})
420
420
  inherited = opts[:inherited]
421
421
  @dataset = case ds
422
- when Symbol
422
+ when Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression
423
423
  @simple_table = db.literal(ds)
424
424
  db[ds]
425
425
  when Dataset
@@ -427,7 +427,7 @@ module Sequel
427
427
  @db = ds.db
428
428
  ds
429
429
  else
430
- raise(Error, "Model.set_dataset takes a Symbol or a Sequel::Dataset")
430
+ raise(Error, "Model.set_dataset takes one of the following classes as an argument: Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, Dataset")
431
431
  end
432
432
  @dataset.row_proc = Proc.new{|r| load(r)}
433
433
  @require_modification = Sequel::Model.require_modification.nil? ? @dataset.provides_accurate_rows_matched? : Sequel::Model.require_modification
@@ -658,6 +658,15 @@ module Sequel
658
658
  Sequel::Plugins.const_get(module_name)
659
659
  end
660
660
 
661
+ # Check if the plugin module +plugin+ defines the constant named by +submod+.
662
+ def plugin_module_defined?(plugin, submod)
663
+ if RUBY_VERSION >= '1.9'
664
+ plugin.const_defined?(submod, false)
665
+ else
666
+ plugin.const_defined?(submod)
667
+ end
668
+ end
669
+
661
670
  # Find the row in the dataset that matches the primary key. Uses
662
671
  # a static SQL optimization if the table and primary key are simple.
663
672
  def primary_key_lookup(pk)
@@ -40,7 +40,7 @@ module Sequel
40
40
  def full_messages
41
41
  inject([]) do |m, kv|
42
42
  att, errors = *kv
43
- errors.each {|e| m << "#{Array(att).join(ATTRIBUTE_JOINER)} #{e}"}
43
+ errors.each {|e| m << (e.is_a?(LiteralString) ? e : "#{Array(att).join(ATTRIBUTE_JOINER)} #{e}")}
44
44
  m
45
45
  end
46
46
  end
@@ -56,6 +56,7 @@ module Sequel
56
56
  _join_table_dataset(opts).filter(opts[:left_key]=>send(opts[:left_primary_key])).select_map(opts[:right_key])
57
57
  end
58
58
  def_association_pks_setter(opts) do |pks|
59
+ pks = convert_pk_array(opts, pks)
59
60
  checked_transaction do
60
61
  ds = _join_table_dataset(opts).filter(opts[:left_key]=>send(opts[:left_primary_key]))
61
62
  ds.exclude(opts[:right_key]=>pks).delete
@@ -74,6 +75,7 @@ module Sequel
74
75
  send(opts.dataset_method).select_map(opts.associated_class.primary_key)
75
76
  end
76
77
  def_association_pks_setter(opts) do |pks|
78
+ pks = convert_pk_array(opts, pks)
77
79
  checked_transaction do
78
80
  ds = send(opts.dataset_method)
79
81
  primary_key = opts.associated_class.primary_key
@@ -84,6 +86,20 @@ module Sequel
84
86
  end
85
87
  end
86
88
  end
89
+
90
+ module InstanceMethods
91
+ private
92
+
93
+ # If the associated class's primary key column type is integer,
94
+ # typecast all provided values to integer before using them.
95
+ def convert_pk_array(opts, pks)
96
+ if klass = opts.associated_class and sch = klass.db_schema and col = sch[klass.primary_key] and col[:type] == :integer
97
+ pks.map{|pk| model.db.typecast_value(:integer, pk)}
98
+ else
99
+ pks
100
+ end
101
+ end
102
+ end
87
103
  end
88
104
  end
89
105
  end
@@ -1,6 +1,6 @@
1
1
  module Sequel
2
2
  module Plugins
3
- # The update_primary_key plugin allows you to modify an objects
3
+ # The update_primary_key plugin allows you to modify an object's
4
4
  # primary key and then save the record. Sequel does not work
5
5
  # correctly with primary key modifications by default. Sequel
6
6
  # is designed to work with surrogate primary keys that never need to be
@@ -3,7 +3,7 @@ module Sequel
3
3
  MAJOR = 3
4
4
  # The minor version of Sequel. Bumped for every non-patch level
5
5
  # release, generally around once a month.
6
- MINOR = 24
6
+ MINOR = 25
7
7
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
8
8
  # releases that fix regressions from previous versions.
9
9
  TINY = 0
@@ -998,6 +998,13 @@ if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc
998
998
  @d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
999
999
  @d.call_sproc(:select, :test_sproc, 3, 4).should == [{:id=>nil, :value=>2, :b=>6, :d => 8}]
1000
1000
  end
1001
+
1002
+ specify "should deal with nil values" do
1003
+ MYSQL_DB.execute_ddl('CREATE PROCEDURE test_sproc(i INTEGER, v INTEGER) BEGIN INSERT INTO items VALUES (i, v); END')
1004
+ MYSQL_DB[:items].delete
1005
+ MYSQL_DB.call_sproc(:test_sproc, :args=>[1, nil])
1006
+ MYSQL_DB[:items].all.should == [{:id=>1, :value=>nil}]
1007
+ end
1001
1008
  end
1002
1009
  end
1003
1010
 
@@ -478,233 +478,6 @@ describe "Database#test_connection" do
478
478
  end
479
479
  end
480
480
 
481
- class DummyDataset < Sequel::Dataset
482
- def first
483
- raise if @opts[:from] == [:a]
484
- true
485
- end
486
- end
487
-
488
- class DummyDatabase < Sequel::Database
489
- attr_reader :sqls
490
-
491
- def execute(sql, opts={})
492
- @sqls ||= []
493
- @sqls << sql
494
- end
495
-
496
- def transaction; yield; end
497
-
498
- def dataset
499
- DummyDataset.new(self)
500
- end
501
- end
502
-
503
- describe "Database#create_table" do
504
- before do
505
- @db = DummyDatabase.new
506
- end
507
-
508
- specify "should construct proper SQL" do
509
- @db.create_table :test do
510
- primary_key :id, :integer, :null => false
511
- column :name, :text
512
- index :name, :unique => true
513
- end
514
- @db.sqls.should == [
515
- 'CREATE TABLE test (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
516
- 'CREATE UNIQUE INDEX test_name_index ON test (name)'
517
- ]
518
- end
519
-
520
- specify "should create a temporary table" do
521
- @db.create_table :test_tmp, :temp => true do
522
- primary_key :id, :integer, :null => false
523
- column :name, :text
524
- index :name, :unique => true
525
- end
526
-
527
- @db.sqls.should == [
528
- 'CREATE TEMPORARY TABLE test_tmp (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
529
- 'CREATE UNIQUE INDEX test_tmp_name_index ON test_tmp (name)'
530
- ]
531
- end
532
-
533
- specify "should not use default schema when creating a temporary table" do
534
- @db.default_schema = :foo
535
- @db.create_table :test_tmp, :temp => true do
536
- column :name, :text
537
- end
538
- @db.sqls.should == ['CREATE TEMPORARY TABLE test_tmp (name text)']
539
- end
540
- end
541
-
542
- describe "Database#alter_table" do
543
- before do
544
- @db = DummyDatabase.new
545
- end
546
-
547
- specify "should construct proper SQL" do
548
- @db.alter_table :xyz do
549
- add_column :aaa, :text, :null => false, :unique => true
550
- drop_column :bbb
551
- rename_column :ccc, :ddd
552
- set_column_type :eee, :integer
553
- set_column_default :hhh, 'abcd'
554
-
555
- add_index :fff, :unique => true
556
- drop_index :ggg
557
- end
558
-
559
- @db.sqls.should == [
560
- 'ALTER TABLE xyz ADD COLUMN aaa text NOT NULL UNIQUE',
561
- 'ALTER TABLE xyz DROP COLUMN bbb',
562
- 'ALTER TABLE xyz RENAME COLUMN ccc TO ddd',
563
- 'ALTER TABLE xyz ALTER COLUMN eee TYPE integer',
564
- "ALTER TABLE xyz ALTER COLUMN hhh SET DEFAULT 'abcd'",
565
-
566
- 'CREATE UNIQUE INDEX xyz_fff_index ON xyz (fff)',
567
- 'DROP INDEX xyz_ggg_index'
568
- ]
569
- end
570
- end
571
-
572
- describe "Database#add_column" do
573
- before do
574
- @db = DummyDatabase.new
575
- end
576
-
577
- specify "should construct proper SQL" do
578
- @db.add_column :test, :name, :text, :unique => true
579
- @db.sqls.should == [
580
- 'ALTER TABLE test ADD COLUMN name text UNIQUE'
581
- ]
582
- end
583
- end
584
-
585
- describe "Database#drop_column" do
586
- before do
587
- @db = DummyDatabase.new
588
- end
589
-
590
- specify "should construct proper SQL" do
591
- @db.drop_column :test, :name
592
- @db.sqls.should == [
593
- 'ALTER TABLE test DROP COLUMN name'
594
- ]
595
- end
596
- end
597
-
598
- describe "Database#rename_column" do
599
- before do
600
- @db = DummyDatabase.new
601
- end
602
-
603
- specify "should construct proper SQL" do
604
- @db.rename_column :test, :abc, :def
605
- @db.sqls.should == [
606
- 'ALTER TABLE test RENAME COLUMN abc TO def'
607
- ]
608
- end
609
- end
610
-
611
- describe "Database#set_column_type" do
612
- before do
613
- @db = DummyDatabase.new
614
- end
615
-
616
- specify "should construct proper SQL" do
617
- @db.set_column_type :test, :name, :integer
618
- @db.sqls.should == [
619
- 'ALTER TABLE test ALTER COLUMN name TYPE integer'
620
- ]
621
- end
622
- end
623
-
624
- describe "Database#set_column_default" do
625
- before do
626
- @db = DummyDatabase.new
627
- end
628
-
629
- specify "should construct proper SQL" do
630
- @db.set_column_default :test, :name, 'zyx'
631
- @db.sqls.should == [
632
- "ALTER TABLE test ALTER COLUMN name SET DEFAULT 'zyx'"
633
- ]
634
- end
635
- end
636
-
637
- describe "Database#add_index" do
638
- before do
639
- @db = DummyDatabase.new
640
- end
641
-
642
- specify "should construct proper SQL" do
643
- @db.add_index :test, :name, :unique => true
644
- @db.sqls.should == [
645
- 'CREATE UNIQUE INDEX test_name_index ON test (name)'
646
- ]
647
- end
648
-
649
- specify "should accept multiple columns" do
650
- @db.add_index :test, [:one, :two]
651
- @db.sqls.should == [
652
- 'CREATE INDEX test_one_two_index ON test (one, two)'
653
- ]
654
- end
655
- end
656
-
657
- describe "Database#drop_index" do
658
- before do
659
- @db = DummyDatabase.new
660
- end
661
-
662
- specify "should construct proper SQL" do
663
- @db.drop_index :test, :name
664
- @db.sqls.should == [
665
- 'DROP INDEX test_name_index'
666
- ]
667
- end
668
-
669
- end
670
-
671
- class Dummy2Database < Sequel::Database
672
- attr_reader :sql
673
- def execute(sql); @sql = sql; end
674
- def transaction; yield; end
675
- end
676
-
677
- describe "Database#drop_table" do
678
- before do
679
- @db = DummyDatabase.new
680
- end
681
-
682
- specify "should construct proper SQL" do
683
- @db.drop_table :test
684
- @db.sqls.should == ['DROP TABLE test']
685
- end
686
-
687
- specify "should accept multiple table names" do
688
- @db.drop_table :a, :bb, :ccc
689
- @db.sqls.should == [
690
- 'DROP TABLE a',
691
- 'DROP TABLE bb',
692
- 'DROP TABLE ccc'
693
- ]
694
- end
695
- end
696
-
697
- describe "Database#rename_table" do
698
- before do
699
- @db = DummyDatabase.new
700
- end
701
-
702
- specify "should construct proper SQL" do
703
- @db.rename_table :abc, :xyz
704
- @db.sqls.should == ['ALTER TABLE abc RENAME TO xyz']
705
- end
706
- end
707
-
708
481
  describe "Database#table_exists?" do
709
482
  specify "should try to select the first record from the table's dataset" do
710
483
  db2 = DummyDatabase.new
@@ -1282,74 +1055,6 @@ describe "Database#[]" do
1282
1055
  end
1283
1056
  end
1284
1057
 
1285
- describe "Database#create_view" do
1286
- before do
1287
- @db = DummyDatabase.new
1288
- end
1289
-
1290
- specify "should construct proper SQL with raw SQL" do
1291
- @db.create_view :test, "SELECT * FROM xyz"
1292
- @db.sqls.should == ['CREATE VIEW test AS SELECT * FROM xyz']
1293
- @db.sqls.clear
1294
- @db.create_view :test.identifier, "SELECT * FROM xyz"
1295
- @db.sqls.should == ['CREATE VIEW test AS SELECT * FROM xyz']
1296
- end
1297
-
1298
- specify "should construct proper SQL with dataset" do
1299
- @db.create_view :test, @db[:items].select(:a, :b).order(:c)
1300
- @db.sqls.should == ['CREATE VIEW test AS SELECT a, b FROM items ORDER BY c']
1301
- @db.sqls.clear
1302
- @db.create_view :test.qualify(:sch), @db[:items].select(:a, :b).order(:c)
1303
- @db.sqls.should == ['CREATE VIEW sch.test AS SELECT a, b FROM items ORDER BY c']
1304
- end
1305
- end
1306
-
1307
- describe "Database#create_or_replace_view" do
1308
- before do
1309
- @db = DummyDatabase.new
1310
- end
1311
-
1312
- specify "should construct proper SQL with raw SQL" do
1313
- @db.create_or_replace_view :test, "SELECT * FROM xyz"
1314
- @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT * FROM xyz']
1315
- @db.sqls.clear
1316
- @db.create_or_replace_view :sch__test, "SELECT * FROM xyz"
1317
- @db.sqls.should == ['CREATE OR REPLACE VIEW sch.test AS SELECT * FROM xyz']
1318
- end
1319
-
1320
- specify "should construct proper SQL with dataset" do
1321
- @db.create_or_replace_view :test, @db[:items].select(:a, :b).order(:c)
1322
- @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT a, b FROM items ORDER BY c']
1323
- @db.sqls.clear
1324
- @db.create_or_replace_view :test.identifier, @db[:items].select(:a, :b).order(:c)
1325
- @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT a, b FROM items ORDER BY c']
1326
- end
1327
- end
1328
-
1329
- describe "Database#drop_view" do
1330
- before do
1331
- @db = DummyDatabase.new
1332
- end
1333
-
1334
- specify "should construct proper SQL" do
1335
- @db.drop_view :test
1336
- @db.drop_view :test.identifier
1337
- @db.drop_view :sch__test
1338
- @db.drop_view :test.qualify(:sch)
1339
- @db.sqls.should == ['DROP VIEW test', 'DROP VIEW test', 'DROP VIEW sch.test', 'DROP VIEW sch.test']
1340
- end
1341
- end
1342
-
1343
- describe "Database#alter_table_sql" do
1344
- before do
1345
- @db = DummyDatabase.new
1346
- end
1347
-
1348
- specify "should raise error for an invalid op" do
1349
- proc {@db.send(:alter_table_sql, :mau, :op => :blah)}.should raise_error(Sequel::Error)
1350
- end
1351
- end
1352
-
1353
1058
  describe "Database#inspect" do
1354
1059
  before do
1355
1060
  @db = DummyDatabase.new
@@ -759,6 +759,11 @@ describe "Dataset#exclude" do
759
759
  "SELECT * FROM test WHERE (region != 'Asia')"
760
760
  end
761
761
 
762
+ specify "should affect the having clause if having clause is already used" do
763
+ @dataset.group_and_count(:name).having{count > 2}.exclude{count > 5}.sql.should ==
764
+ "SELECT name, count(*) AS count FROM test GROUP BY name HAVING ((count > 2) AND (count <= 5))"
765
+ end
766
+
762
767
  specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
763
768
  @dataset.exclude(:region => 'Asia', :name => 'Japan').select_sql.
764
769
  should match(Regexp.union(/WHERE \(\(region != 'Asia'\) OR \(name != 'Japan'\)\)/,
@@ -793,6 +798,28 @@ describe "Dataset#exclude" do
793
798
  end
794
799
  end
795
800
 
801
+ describe "Dataset#exclude_where" do
802
+ before do
803
+ @dataset = Sequel::Dataset.new(nil).from(:test)
804
+ end
805
+
806
+ specify "should correctly negate the expression and add it to the where clause" do
807
+ @dataset.exclude_where(:region=>'Asia').sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
808
+ @dataset.exclude_where(:region=>'Asia').exclude_where(:region=>'NA').sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (region != 'NA'))"
809
+ end
810
+
811
+ specify "should affect the where clause even if having clause is already used" do
812
+ @dataset.group_and_count(:name).having{count > 2}.exclude_where(:region=>'Asia').sql.should ==
813
+ "SELECT name, count(*) AS count FROM test WHERE (region != 'Asia') GROUP BY name HAVING (count > 2)"
814
+ end
815
+ end
816
+
817
+ describe "Dataset#exclude_having" do
818
+ specify "should correctly negate the expression and add it to the having clause" do
819
+ Sequel::Dataset.new(nil).from(:test).exclude_having{count > 2}.exclude_having{count < 0}.sql.should == "SELECT * FROM test HAVING ((count <= 2) AND (count >= 0))"
820
+ end
821
+ end
822
+
796
823
  describe "Dataset#invert" do
797
824
  before do
798
825
  @d = Sequel::Dataset.new(nil).from(:test)
@@ -897,7 +924,7 @@ describe "Dataset#group_by" do
897
924
  "SELECT * FROM test GROUP BY (type_id IS NULL)"
898
925
  end
899
926
 
900
- specify "should ungroup when passed nil, empty, or no arguments" do
927
+ specify "should ungroup when passed nil or no arguments" do
901
928
  @dataset.group_by.select_sql.should ==
902
929
  "SELECT * FROM test"
903
930
  @dataset.group_by(nil).select_sql.should ==
@@ -915,6 +942,13 @@ describe "Dataset#group_by" do
915
942
  @dataset.group(:type_id=>nil).select_sql.should ==
916
943
  "SELECT * FROM test GROUP BY (type_id IS NULL)"
917
944
  end
945
+
946
+ specify "should take a virtual row block" do
947
+ @dataset.group{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
948
+ @dataset.group_by{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
949
+ @dataset.group{[type_id > 1, type_id < 2]}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1), (type_id < 2)"
950
+ @dataset.group(:foo){type_id > 1}.sql.should == "SELECT * FROM test GROUP BY foo, (type_id > 1)"
951
+ end
918
952
  end
919
953
 
920
954
  describe "Dataset#as" do
@@ -1219,6 +1253,27 @@ describe "Dataset#select" do
1219
1253
  end
1220
1254
  end
1221
1255
 
1256
+ describe "Dataset#select_group" do
1257
+ before do
1258
+ @d = Sequel::Dataset.new(nil).from(:test)
1259
+ end
1260
+
1261
+ specify "should set both SELECT and GROUP" do
1262
+ @d.select_group(:name).sql.should == 'SELECT name FROM test GROUP BY name'
1263
+ @d.select_group(:a, :b__c, :d___e).sql.should == 'SELECT a, b.c, d AS e FROM test GROUP BY a, b.c, d'
1264
+ end
1265
+
1266
+ specify "should remove from both SELECT and GROUP if no arguments" do
1267
+ @d.select_group(:name).select_group.sql.should == 'SELECT * FROM test'
1268
+ end
1269
+
1270
+ specify "should accept virtual row blocks" do
1271
+ @d.select_group{name}.sql.should == 'SELECT name FROM test GROUP BY name'
1272
+ @d.select_group{[name, f(v).as(a)]}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
1273
+ @d.select_group(:name){f(v).as(a)}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
1274
+ end
1275
+ end
1276
+
1222
1277
  describe "Dataset#select_all" do
1223
1278
  before do
1224
1279
  @d = Sequel::Dataset.new(nil).from(:test)
@@ -1231,6 +1286,14 @@ describe "Dataset#select_all" do
1231
1286
  specify "should overrun the previous select option" do
1232
1287
  @d.select!(:a, :b, :c).select_all.sql.should == 'SELECT * FROM test'
1233
1288
  end
1289
+
1290
+ specify "should select all columns in a table if given an argument" do
1291
+ @d.select_all(:test).sql.should == 'SELECT test.* FROM test'
1292
+ end
1293
+
1294
+ specify "should select all columns all tables if given a multiple arguments" do
1295
+ @d.select_all(:test, :foo).sql.should == 'SELECT test.*, foo.* FROM test'
1296
+ end
1234
1297
  end
1235
1298
 
1236
1299
  describe "Dataset#select_more" do
@@ -1774,6 +1837,12 @@ describe "Dataset#group_and_count" do
1774
1837
  @ds.group_and_count(:name.identifier.as(:n)).sql.should ==
1775
1838
  "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
1776
1839
  end
1840
+
1841
+ specify "should take a virtual row block" do
1842
+ @ds.group_and_count{(type_id > 1).as(t)}.sql.should == "SELECT (type_id > 1) AS t, count(*) AS count FROM test GROUP BY (type_id > 1)"
1843
+ @ds.group_and_count{[(type_id > 1).as(t), type_id < 2]}.sql.should == "SELECT (type_id > 1) AS t, (type_id < 2), count(*) AS count FROM test GROUP BY (type_id > 1), (type_id < 2)"
1844
+ @ds.group_and_count(:foo){type_id > 1}.sql.should == "SELECT foo, (type_id > 1), count(*) AS count FROM test GROUP BY foo, (type_id > 1)"
1845
+ end
1777
1846
  end
1778
1847
 
1779
1848
  describe "Dataset#empty?" do
@@ -452,6 +452,45 @@ describe "Blockless Ruby Filters" do
452
452
  e2 = ~:comment.like('%:hidden:%')
453
453
  e1.should == e2
454
454
  end
455
+
456
+ it "should support expression filter methods on Datasets" do
457
+ d = @d.select(:a)
458
+
459
+ @d.lit(d + 1).should == '((SELECT a FROM items) + 1)'
460
+ @d.lit(d - 1).should == '((SELECT a FROM items) - 1)'
461
+ @d.lit(d * 1).should == '((SELECT a FROM items) * 1)'
462
+ @d.lit(d / 1).should == '((SELECT a FROM items) / 1)'
463
+
464
+ @d.lit(d => 1).should == '((SELECT a FROM items) = 1)'
465
+ @d.lit(~{d => 1}).should == '((SELECT a FROM items) != 1)'
466
+ @d.lit(d > 1).should == '((SELECT a FROM items) > 1)'
467
+ @d.lit(d < 1).should == '((SELECT a FROM items) < 1)'
468
+ @d.lit(d >= 1).should == '((SELECT a FROM items) >= 1)'
469
+ @d.lit(d <= 1).should == '((SELECT a FROM items) <= 1)'
470
+
471
+ @d.lit(d.as(:b)).should == '(SELECT a FROM items) AS b'
472
+
473
+ @d.lit(d & :b).should == '((SELECT a FROM items) AND b)'
474
+ @d.lit(d | :b).should == '((SELECT a FROM items) OR b)'
475
+ @d.lit(~d).should == 'NOT (SELECT a FROM items)'
476
+
477
+ @d.lit(d.cast(Integer)).should == 'CAST((SELECT a FROM items) AS integer)'
478
+ @d.lit(d.cast_numeric).should == 'CAST((SELECT a FROM items) AS integer)'
479
+ @d.lit(d.cast_string).should == 'CAST((SELECT a FROM items) AS varchar(255))'
480
+ @d.lit(d.cast_numeric << :b).should == '(CAST((SELECT a FROM items) AS integer) << b)'
481
+ @d.lit(d.cast_string + :b).should == '(CAST((SELECT a FROM items) AS varchar(255)) || b)'
482
+
483
+ @d.lit(d.extract(:year)).should == 'extract(year FROM (SELECT a FROM items))'
484
+ @d.lit(d.sql_boolean & :b).should == '((SELECT a FROM items) AND b)'
485
+ @d.lit(d.sql_number << :b).should == '((SELECT a FROM items) << b)'
486
+ @d.lit(d.sql_string + :b).should == '((SELECT a FROM items) || b)'
487
+
488
+ @d.lit(d.asc).should == '(SELECT a FROM items) ASC'
489
+ @d.lit(d.desc).should == '(SELECT a FROM items) DESC'
490
+
491
+ @d.lit(d.like(:b)).should == '((SELECT a FROM items) LIKE b)'
492
+ @d.lit(d.ilike(:b)).should == '((SELECT a FROM items) ILIKE b)'
493
+ end
455
494
 
456
495
  if RUBY_VERSION < '1.9.0'
457
496
  it "should not allow inequality operations on true, false, or nil" do