sequel 3.30.0 → 3.31.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.
- data/CHANGELOG +40 -0
- data/Rakefile +12 -2
- data/doc/association_basics.rdoc +28 -0
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/opening_databases.rdoc +1 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/lib/sequel/adapters/jdbc.rb +7 -6
- data/lib/sequel/adapters/jdbc/derby.rb +5 -0
- data/lib/sequel/adapters/jdbc/h2.rb +6 -1
- data/lib/sequel/adapters/mock.rb +21 -2
- data/lib/sequel/adapters/shared/db2.rb +10 -0
- data/lib/sequel/adapters/shared/mssql.rb +40 -5
- data/lib/sequel/adapters/shared/mysql.rb +19 -2
- data/lib/sequel/adapters/shared/oracle.rb +13 -1
- data/lib/sequel/adapters/shared/postgres.rb +52 -8
- data/lib/sequel/adapters/shared/sqlite.rb +4 -3
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/database/schema_generator.rb +9 -2
- data/lib/sequel/dataset/actions.rb +37 -19
- data/lib/sequel/dataset/features.rb +10 -0
- data/lib/sequel/dataset/prepared_statements.rb +0 -10
- data/lib/sequel/dataset/query.rb +13 -1
- data/lib/sequel/dataset/sql.rb +6 -1
- data/lib/sequel/model/associations.rb +14 -4
- data/lib/sequel/model/base.rb +10 -0
- data/lib/sequel/plugins/serialization.rb +82 -43
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +46 -0
- data/spec/adapters/mysql_spec.rb +3 -0
- data/spec/adapters/postgres_spec.rb +61 -24
- data/spec/core/database_spec.rb +31 -18
- data/spec/core/dataset_spec.rb +90 -13
- data/spec/core/mock_adapter_spec.rb +37 -0
- data/spec/extensions/instance_filters_spec.rb +1 -0
- data/spec/extensions/nested_attributes_spec.rb +1 -1
- data/spec/extensions/serialization_spec.rb +49 -5
- data/spec/extensions/sharding_spec.rb +1 -1
- data/spec/integration/associations_test.rb +15 -0
- data/spec/integration/dataset_test.rb +71 -0
- data/spec/integration/prepared_statement_test.rb +8 -0
- data/spec/model/association_reflection_spec.rb +27 -0
- data/spec/model/associations_spec.rb +18 -3
- data/spec/model/base_spec.rb +20 -0
- data/spec/model/eager_loading_spec.rb +21 -0
- metadata +4 -2
data/spec/core/database_spec.rb
CHANGED
@@ -571,11 +571,7 @@ describe "Database#table_exists?" do
|
|
571
571
|
end
|
572
572
|
end
|
573
573
|
|
574
|
-
|
575
|
-
before do
|
576
|
-
@db = Sequel.mock(:servers=>{:test=>{}})
|
577
|
-
end
|
578
|
-
|
574
|
+
shared_examples_for "Database#transaction" do
|
579
575
|
specify "should wrap the supplied block with BEGIN + COMMIT statements" do
|
580
576
|
@db.transaction{@db.execute 'DROP TABLE test;'}
|
581
577
|
@db.sqls.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
@@ -699,7 +695,7 @@ describe "Database#transaction" do
|
|
699
695
|
q1.pop
|
700
696
|
cc.should be_a_kind_of(Sequel::Mock::Connection)
|
701
697
|
tr = @db.instance_variable_get(:@transactions)
|
702
|
-
tr.should ==
|
698
|
+
tr.keys.should == [cc]
|
703
699
|
q.push nil
|
704
700
|
t.join
|
705
701
|
tr.should be_empty
|
@@ -796,6 +792,26 @@ describe "Database#transaction" do
|
|
796
792
|
@db.sqls.should == ['BEGIN', 'ROLLBACK', 'foo']
|
797
793
|
end
|
798
794
|
|
795
|
+
specify "should raise an error if you attempt to use after_commit inside a prepared transaction" do
|
796
|
+
@db.meta_def(:supports_prepared_transactions?){true}
|
797
|
+
proc{@db.transaction(:prepare=>'XYZ'){@db.after_commit{@db.execute('foo')}}}.should raise_error(Sequel::Error)
|
798
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
799
|
+
end
|
800
|
+
|
801
|
+
specify "should raise an error if you attempt to use after_rollback inside a prepared transaction" do
|
802
|
+
@db.meta_def(:supports_prepared_transactions?){true}
|
803
|
+
proc{@db.transaction(:prepare=>'XYZ'){@db.after_rollback{@db.execute('foo')}}}.should raise_error(Sequel::Error)
|
804
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
808
|
+
describe "Database#transaction with savepoint support" do
|
809
|
+
before do
|
810
|
+
@db = Sequel.mock(:servers=>{:test=>{}})
|
811
|
+
end
|
812
|
+
|
813
|
+
it_should_behave_like "Database#transaction"
|
814
|
+
|
799
815
|
specify "should support after_commit inside savepoints" do
|
800
816
|
@db.meta_def(:supports_savepoints?){true}
|
801
817
|
@db.transaction do
|
@@ -817,18 +833,6 @@ describe "Database#transaction" do
|
|
817
833
|
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'RELEASE SAVEPOINT autopoint_1', 'ROLLBACK', 'foo', 'bar', 'baz']
|
818
834
|
end
|
819
835
|
|
820
|
-
specify "should raise an error if you attempt to use after_commit inside a prepared transaction" do
|
821
|
-
@db.meta_def(:supports_prepared_transactions?){true}
|
822
|
-
proc{@db.transaction(:prepare=>'XYZ'){@db.after_commit{@db.execute('foo')}}}.should raise_error(Sequel::Error)
|
823
|
-
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
824
|
-
end
|
825
|
-
|
826
|
-
specify "should raise an error if you attempt to use after_rollback inside a prepared transaction" do
|
827
|
-
@db.meta_def(:supports_prepared_transactions?){true}
|
828
|
-
proc{@db.transaction(:prepare=>'XYZ'){@db.after_rollback{@db.execute('foo')}}}.should raise_error(Sequel::Error)
|
829
|
-
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
830
|
-
end
|
831
|
-
|
832
836
|
specify "should raise an error if you attempt to use after_commit inside a savepoint in a prepared transaction" do
|
833
837
|
@db.meta_def(:supports_savepoints?){true}
|
834
838
|
@db.meta_def(:supports_prepared_transactions?){true}
|
@@ -843,7 +847,16 @@ describe "Database#transaction" do
|
|
843
847
|
@db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
|
844
848
|
end
|
845
849
|
end
|
850
|
+
|
851
|
+
describe "Database#transaction without savepoint support" do
|
852
|
+
before do
|
853
|
+
@db = Sequel.mock(:servers=>{:test=>{}})
|
854
|
+
@db.meta_def(:supports_savepoints?){false}
|
855
|
+
end
|
846
856
|
|
857
|
+
it_should_behave_like "Database#transaction"
|
858
|
+
end
|
859
|
+
|
847
860
|
describe "Sequel.transaction" do
|
848
861
|
before do
|
849
862
|
@sqls = []
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -342,12 +342,12 @@ describe "Dataset#exists" do
|
|
342
342
|
@ds1.filter(@ds2.exists).sql.should ==
|
343
343
|
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
|
344
344
|
@ds1.filter(@ds2.exists & @ds3.exists).sql.should ==
|
345
|
-
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)) AND EXISTS (SELECT * FROM test WHERE (price > 50)))'
|
345
|
+
'SELECT * FROM test WHERE ((EXISTS (SELECT * FROM test WHERE (price < 100))) AND (EXISTS (SELECT * FROM test WHERE (price > 50))))'
|
346
346
|
end
|
347
347
|
|
348
348
|
specify "should work in select" do
|
349
349
|
@ds1.select(@ds2.exists.as(:a), @ds3.exists.as(:b)).sql.should ==
|
350
|
-
'SELECT EXISTS (SELECT * FROM test WHERE (price < 100)) AS a, EXISTS (SELECT * FROM test WHERE (price > 50)) AS b FROM test'
|
350
|
+
'SELECT (EXISTS (SELECT * FROM test WHERE (price < 100))) AS a, (EXISTS (SELECT * FROM test WHERE (price > 50))) AS b FROM test'
|
351
351
|
end
|
352
352
|
end
|
353
353
|
|
@@ -844,7 +844,7 @@ end
|
|
844
844
|
|
845
845
|
describe "Dataset#group_by" do
|
846
846
|
before do
|
847
|
-
@dataset = Sequel
|
847
|
+
@dataset = Sequel.mock[:test].group_by(:type_id)
|
848
848
|
end
|
849
849
|
|
850
850
|
specify "should raise when trying to generate an update statement" do
|
@@ -881,6 +881,23 @@ describe "Dataset#group_by" do
|
|
881
881
|
@dataset.group{[type_id > 1, type_id < 2]}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1), (type_id < 2)"
|
882
882
|
@dataset.group(:foo){type_id > 1}.sql.should == "SELECT * FROM test GROUP BY foo, (type_id > 1)"
|
883
883
|
end
|
884
|
+
|
885
|
+
specify "should support a #group_rollup method if the database supports it" do
|
886
|
+
@dataset.meta_def(:supports_group_rollup?){true}
|
887
|
+
@dataset.group(:type_id).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id)"
|
888
|
+
@dataset.group(:type_id, :b).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id, b)"
|
889
|
+
end
|
890
|
+
|
891
|
+
specify "should support a #group_cube method if the database supports it" do
|
892
|
+
@dataset.meta_def(:supports_group_cube?){true}
|
893
|
+
@dataset.group(:type_id).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id)"
|
894
|
+
@dataset.group(:type_id, :b).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id, b)"
|
895
|
+
end
|
896
|
+
|
897
|
+
specify "should have #group_cube and #group_rollup methods raise an Error if not supported it" do
|
898
|
+
proc{@dataset.group(:type_id).group_rollup}.should raise_error(Sequel::Error)
|
899
|
+
proc{@dataset.group(:type_id).group_cube}.should raise_error(Sequel::Error)
|
900
|
+
end
|
884
901
|
end
|
885
902
|
|
886
903
|
describe "Dataset#as" do
|
@@ -930,6 +947,21 @@ describe "Dataset#literal" do
|
|
930
947
|
@dataset.literal(:"items__na#m$e").should == "items.na#m$e"
|
931
948
|
end
|
932
949
|
|
950
|
+
specify "should call sql_literal_append with dataset and sql on type if not natively supported and the object responds to it" do
|
951
|
+
@a = Class.new do
|
952
|
+
def sql_literal_append(ds, sql)
|
953
|
+
sql << "called #{ds.blah}"
|
954
|
+
end
|
955
|
+
def sql_literal(ds)
|
956
|
+
"not called #{ds.blah}"
|
957
|
+
end
|
958
|
+
end
|
959
|
+
def @dataset.blah
|
960
|
+
"ds"
|
961
|
+
end
|
962
|
+
@dataset.literal(@a.new).should == "called ds"
|
963
|
+
end
|
964
|
+
|
933
965
|
specify "should call sql_literal with dataset on type if not natively supported and the object responds to it" do
|
934
966
|
@a = Class.new do
|
935
967
|
def sql_literal(ds)
|
@@ -1033,10 +1065,9 @@ describe "Dataset#literal" do
|
|
1033
1065
|
end
|
1034
1066
|
|
1035
1067
|
specify "should not modify literal strings" do
|
1068
|
+
@dataset.quote_identifiers = true
|
1036
1069
|
@dataset.literal('col1 + 2'.lit).should == 'col1 + 2'
|
1037
|
-
|
1038
|
-
@dataset.update_sql(:a => 'a + 2'.lit).should ==
|
1039
|
-
'UPDATE test SET a = a + 2'
|
1070
|
+
@dataset.update_sql(Sequel::SQL::Identifier.new('a'.lit) => 'a + 2'.lit).should == 'UPDATE "test" SET a = a + 2'
|
1040
1071
|
end
|
1041
1072
|
|
1042
1073
|
specify "should literalize BigDecimal instances correctly" do
|
@@ -1103,6 +1134,10 @@ describe "Dataset#from" do
|
|
1103
1134
|
@dataset.from(:'#___#').select_sql.should == 'SELECT * FROM # AS #'
|
1104
1135
|
end
|
1105
1136
|
|
1137
|
+
specify "should not handle :foo__schema__table___alias specially" do
|
1138
|
+
@dataset.from(:foo__schema__table___alias).select_sql.should == "SELECT * FROM foo.schema__table AS alias"
|
1139
|
+
end
|
1140
|
+
|
1106
1141
|
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
1107
1142
|
@dataset.meta_def(:supports_cte?){true}
|
1108
1143
|
@dataset.meta_def(:supports_cte_in_subselect?){false}
|
@@ -1770,9 +1805,9 @@ describe "Dataset#empty?" do
|
|
1770
1805
|
specify "should return true if records exist in the dataset" do
|
1771
1806
|
db = Sequel.mock(:fetch=>proc{|sql| {1=>1} unless sql =~ /WHERE 'f'/})
|
1772
1807
|
db.from(:test).should_not be_empty
|
1773
|
-
db.sqls.should == ['SELECT 1 FROM test LIMIT 1']
|
1808
|
+
db.sqls.should == ['SELECT 1 AS one FROM test LIMIT 1']
|
1774
1809
|
db.from(:test).filter(false).should be_empty
|
1775
|
-
db.sqls.should == ["SELECT 1 FROM test WHERE 'f' LIMIT 1"]
|
1810
|
+
db.sqls.should == ["SELECT 1 AS one FROM test WHERE 'f' LIMIT 1"]
|
1776
1811
|
end
|
1777
1812
|
end
|
1778
1813
|
|
@@ -1819,9 +1854,9 @@ describe "Dataset#first_source_table" do
|
|
1819
1854
|
end
|
1820
1855
|
|
1821
1856
|
specify "should be the unaliased part if aliased" do
|
1822
|
-
@ds.from(:t___a).first_source_table.should ==
|
1823
|
-
@ds.from(:s__t___a).first_source_table.should ==
|
1824
|
-
@ds.from(:t.as(:a)).first_source_table.should ==
|
1857
|
+
@ds.literal(@ds.from(:t___a).first_source_table).should == "t"
|
1858
|
+
@ds.literal(@ds.from(:s__t___a).first_source_table).should == "s.t"
|
1859
|
+
@ds.literal(@ds.from(:t.as(:a)).first_source_table).should == "t"
|
1825
1860
|
end
|
1826
1861
|
|
1827
1862
|
specify "should raise exception if table doesn't have a source" do
|
@@ -2145,7 +2180,7 @@ end
|
|
2145
2180
|
|
2146
2181
|
describe "Dataset#insert_multiple" do
|
2147
2182
|
before do
|
2148
|
-
@db = Sequel.mock
|
2183
|
+
@db = Sequel.mock(:autoid=>2)
|
2149
2184
|
@ds = @db[:items]
|
2150
2185
|
end
|
2151
2186
|
|
@@ -2163,6 +2198,10 @@ describe "Dataset#insert_multiple" do
|
|
2163
2198
|
"INSERT INTO items VALUES ('herro')",
|
2164
2199
|
"INSERT INTO items VALUES ('the ticking crock')"]
|
2165
2200
|
end
|
2201
|
+
|
2202
|
+
specify "should return array of inserted ids" do
|
2203
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}]).should == [2, 3, 4, 5]
|
2204
|
+
end
|
2166
2205
|
end
|
2167
2206
|
|
2168
2207
|
describe "Dataset aggregate methods" do
|
@@ -2588,6 +2627,11 @@ describe "Dataset#import" do
|
|
2588
2627
|
@ds = @db[:items]
|
2589
2628
|
end
|
2590
2629
|
|
2630
|
+
specify "should return nil without a query if no values" do
|
2631
|
+
@ds.import(['x', 'y'], []).should == nil
|
2632
|
+
@db.sqls.should == []
|
2633
|
+
end
|
2634
|
+
|
2591
2635
|
specify "should accept string keys as column names" do
|
2592
2636
|
@ds.import(['x', 'y'], [[1, 2], [3, 4]])
|
2593
2637
|
@db.sqls.should == ['BEGIN',
|
@@ -2635,11 +2679,16 @@ end
|
|
2635
2679
|
|
2636
2680
|
describe "Dataset#multi_insert" do
|
2637
2681
|
before do
|
2638
|
-
@db = Sequel.mock
|
2682
|
+
@db = Sequel.mock(:servers=>{:s1=>{}})
|
2639
2683
|
@ds = @db[:items]
|
2640
2684
|
@list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
|
2641
2685
|
end
|
2642
2686
|
|
2687
|
+
specify "should return nil without a query if no values" do
|
2688
|
+
@ds.multi_insert([]).should == nil
|
2689
|
+
@db.sqls.should == []
|
2690
|
+
end
|
2691
|
+
|
2643
2692
|
specify "should issue multiple insert statements inside a transaction" do
|
2644
2693
|
@ds.multi_insert(@list)
|
2645
2694
|
@db.sqls.should == ['BEGIN',
|
@@ -2649,6 +2698,34 @@ describe "Dataset#multi_insert" do
|
|
2649
2698
|
'COMMIT']
|
2650
2699
|
end
|
2651
2700
|
|
2701
|
+
specify "should respect :server option" do
|
2702
|
+
@ds.multi_insert(@list, :server=>:s1)
|
2703
|
+
@db.sqls.should == ['BEGIN -- s1',
|
2704
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
2705
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
2706
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
2707
|
+
'COMMIT -- s1']
|
2708
|
+
end
|
2709
|
+
|
2710
|
+
specify "should respect existing :server option on dataset" do
|
2711
|
+
@ds.server(:s1).multi_insert(@list)
|
2712
|
+
@db.sqls.should == ['BEGIN -- s1',
|
2713
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
2714
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
2715
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
2716
|
+
'COMMIT -- s1']
|
2717
|
+
end
|
2718
|
+
|
2719
|
+
specify "should respect :return=>:primary_key option" do
|
2720
|
+
@db.autoid = 1
|
2721
|
+
@ds.multi_insert(@list, :return=>:primary_key).should == [1, 2, 3]
|
2722
|
+
@db.sqls.should == ['BEGIN',
|
2723
|
+
"INSERT INTO items (name) VALUES ('abc')",
|
2724
|
+
"INSERT INTO items (name) VALUES ('def')",
|
2725
|
+
"INSERT INTO items (name) VALUES ('ghi')",
|
2726
|
+
'COMMIT']
|
2727
|
+
end
|
2728
|
+
|
2652
2729
|
specify "should handle different formats for tables" do
|
2653
2730
|
@ds = @ds.from(:sch__tab)
|
2654
2731
|
@ds.multi_insert(@list)
|
@@ -126,6 +126,11 @@ describe "Sequel Mock Adapter" do
|
|
126
126
|
rs.should == [{:a=>1}, {:b=>2}]
|
127
127
|
end
|
128
128
|
|
129
|
+
specify "should raise Error if given an invalid object to fetch" do
|
130
|
+
proc{Sequel.mock(:fetch=>Class.new).get(1)}.should raise_error(Sequel::Error)
|
131
|
+
proc{Sequel.mock(:fetch=>Object.new).get(1)}.should raise_error(Sequel::Error)
|
132
|
+
end
|
133
|
+
|
129
134
|
specify "should be able to set the number of rows modified by update and delete using :numrows option as an integer" do
|
130
135
|
db = Sequel.mock(:numrows=>2)
|
131
136
|
db[:t].update(:a=>1).should == 2
|
@@ -188,6 +193,13 @@ describe "Sequel Mock Adapter" do
|
|
188
193
|
ds.delete.should == 3
|
189
194
|
end
|
190
195
|
|
196
|
+
specify "should raise Error if given an invalid object for numrows or autoid" do
|
197
|
+
proc{Sequel.mock(:numrows=>Class.new)[:a].delete}.should raise_error(Sequel::Error)
|
198
|
+
proc{Sequel.mock(:numrows=>Object.new)[:a].delete}.should raise_error(Sequel::Error)
|
199
|
+
proc{Sequel.mock(:autoid=>Class.new)[:a].insert}.should raise_error(Sequel::Error)
|
200
|
+
proc{Sequel.mock(:autoid=>Object.new)[:a].insert}.should raise_error(Sequel::Error)
|
201
|
+
end
|
202
|
+
|
191
203
|
specify "should be able to set the autogenerated primary key returned by insert using :autoid option as an integer" do
|
192
204
|
db = Sequel.mock(:autoid=>1)
|
193
205
|
db[:t].insert(:a=>1).should == 1
|
@@ -279,6 +291,19 @@ describe "Sequel Mock Adapter" do
|
|
279
291
|
db[:t].columns.should == [:c, :d]
|
280
292
|
end
|
281
293
|
|
294
|
+
specify "should raise Error if given an invalid columns" do
|
295
|
+
proc{Sequel.mock(:columns=>Object.new)[:a].columns}.should raise_error(Sequel::Error)
|
296
|
+
end
|
297
|
+
|
298
|
+
specify "should not quote identifiers by default" do
|
299
|
+
Sequel.mock.send(:quote_identifiers_default).should be_false
|
300
|
+
end
|
301
|
+
|
302
|
+
specify "should not have identifier input/output methods by default" do
|
303
|
+
Sequel.mock.send(:identifier_input_method_default).should be_nil
|
304
|
+
Sequel.mock.send(:identifier_output_method_default).should be_nil
|
305
|
+
end
|
306
|
+
|
282
307
|
specify "should keep a record of all executed SQL in #sqls" do
|
283
308
|
db = Sequel.mock
|
284
309
|
db[:t].all
|
@@ -379,4 +404,16 @@ describe "Sequel Mock Adapter" do
|
|
379
404
|
ds.should be_a_kind_of(Sequel::Mock::Dataset)
|
380
405
|
ds.columns.should == [:id, :a, :b]
|
381
406
|
end
|
407
|
+
|
408
|
+
specify "should be able to load dialects based on the database name" do
|
409
|
+
Sequel.mock(:host=>'access').select(Date.new(2011, 12, 13)).sql.should == 'SELECT #2011-12-13#'
|
410
|
+
Sequel.mock(:host=>'db2').select(1).sql.should == 'SELECT 1 FROM "SYSIBM"."SYSDUMMY1"'
|
411
|
+
Sequel.mock(:host=>'firebird')[:a].distinct.limit(1, 2).sql.should == 'SELECT DISTINCT FIRST 1 SKIP 2 * FROM a'
|
412
|
+
Sequel.mock(:host=>'informix')[:a].distinct.limit(1, 2).sql.should == 'SELECT SKIP 2 FIRST 1 DISTINCT * FROM a'
|
413
|
+
Sequel.mock(:host=>'mssql', :quote_identifiers=>true, :identifier_input_method=>:upcase)[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM [A] WHERE (CONTAINS ([B], 'c'))"
|
414
|
+
Sequel.mock(:host=>'mysql', :quote_identifiers=>true)[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM `a` WHERE (MATCH (`b`) AGAINST ('c'))"
|
415
|
+
Sequel.mock(:host=>'oracle', :quote_identifiers=>true)[:a].limit(1).sql.should == 'SELECT * FROM (SELECT * FROM "a") "t1" WHERE (ROWNUM <= 1)'
|
416
|
+
Sequel.mock(:host=>'postgres', :quote_identifiers=>true)[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM \"a\" WHERE (to_tsvector('simple', (COALESCE(\"b\", ''))) @@ to_tsquery('simple', 'c'))"
|
417
|
+
Sequel.mock(:host=>'sqlite', :quote_identifiers=>true)[:a___b].sql.should == "SELECT * FROM `a` AS 'b'"
|
418
|
+
end
|
382
419
|
end
|
@@ -148,7 +148,7 @@ describe "NestedAttributes plugin" do
|
|
148
148
|
@db.sqls.should == []
|
149
149
|
@Album.dataset._fetch = {:id=>1}
|
150
150
|
ar.save
|
151
|
-
check_sql_array("SELECT 1 FROM albums WHERE ((albums.artist_id = 20) AND (id = 10)) LIMIT 1",
|
151
|
+
check_sql_array("SELECT 1 AS one FROM albums WHERE ((albums.artist_id = 20) AND (id = 10)) LIMIT 1",
|
152
152
|
["UPDATE albums SET artist_id = NULL, name = 'Al' WHERE (id = 10)", "UPDATE albums SET name = 'Al', artist_id = NULL WHERE (id = 10)"],
|
153
153
|
"UPDATE artists SET name = 'Ar' WHERE (id = 20)")
|
154
154
|
end
|
@@ -37,11 +37,6 @@ describe "Serialization plugin" do
|
|
37
37
|
MODEL_DB.sqls.map{|s| s.sub("...\n", '')}.should == ["INSERT INTO items (abc) VALUES ('--- 1\n')", "INSERT INTO items (abc) VALUES ('--- hello\n')"]
|
38
38
|
end
|
39
39
|
|
40
|
-
it "serialization_format should be the serialization format used" do
|
41
|
-
@c.plugin :serialization, :yaml, :abc
|
42
|
-
@c.serialization_format.should == :yaml
|
43
|
-
end
|
44
|
-
|
45
40
|
it "serialized_columns should be the columns serialized" do
|
46
41
|
@c.plugin :serialization, :yaml, :abc
|
47
42
|
@c.serialized_columns.should == [:abc]
|
@@ -71,6 +66,12 @@ describe "Serialization plugin" do
|
|
71
66
|
]
|
72
67
|
end
|
73
68
|
|
69
|
+
it "should allow serializing attributes using arbitrary callable" do
|
70
|
+
@c.plugin :serialization, [proc{|s| s.reverse}, proc{}], :abc
|
71
|
+
@c.create(:abc => "hello")
|
72
|
+
MODEL_DB.sqls.should == ["INSERT INTO items (abc) VALUES ('olleh')"]
|
73
|
+
end
|
74
|
+
|
74
75
|
it "should translate values to and from yaml serialization format using accessor methods" do
|
75
76
|
@c.set_primary_key :id
|
76
77
|
@c.plugin :serialization, :yaml, :abc, :def
|
@@ -133,6 +134,49 @@ describe "Serialization plugin" do
|
|
133
134
|
"SELECT * FROM items WHERE (id = 10) LIMIT 1"]
|
134
135
|
end
|
135
136
|
|
137
|
+
it "should translate values to and from arbitrary callables using accessor methods" do
|
138
|
+
@c.set_primary_key :id
|
139
|
+
@c.plugin :serialization, [proc{|s| s.reverse}, proc{|s| s.reverse}], :abc, :def
|
140
|
+
@c.dataset._fetch = {:id => 1, :abc => 'cba', :def => 'olleh'}
|
141
|
+
|
142
|
+
o = @c.first
|
143
|
+
o.id.should == 1
|
144
|
+
o.abc.should == 'abc'
|
145
|
+
o.abc.should == 'abc'
|
146
|
+
o.def.should == "hello"
|
147
|
+
o.def.should == "hello"
|
148
|
+
|
149
|
+
o.update(:abc => 'foo')
|
150
|
+
@c.create(:abc => 'bar')
|
151
|
+
|
152
|
+
MODEL_DB.sqls.should == ["SELECT * FROM items LIMIT 1",
|
153
|
+
"UPDATE items SET abc = 'oof' WHERE (id = 1)",
|
154
|
+
"INSERT INTO items (abc) VALUES ('rab')",
|
155
|
+
"SELECT * FROM items WHERE (id = 10) LIMIT 1"]
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should handle registration of custom serializer/deserializer pairs" do
|
159
|
+
@c.set_primary_key :id
|
160
|
+
Sequel::Plugins::Serialization.register_format(:reverse, proc{|s| s.reverse}, proc{|s| s.reverse})
|
161
|
+
@c.plugin :serialization, :reverse, :abc, :def
|
162
|
+
@c.dataset._fetch = {:id => 1, :abc => 'cba', :def => 'olleh'}
|
163
|
+
|
164
|
+
o = @c.first
|
165
|
+
o.id.should == 1
|
166
|
+
o.abc.should == 'abc'
|
167
|
+
o.abc.should == 'abc'
|
168
|
+
o.def.should == "hello"
|
169
|
+
o.def.should == "hello"
|
170
|
+
|
171
|
+
o.update(:abc => 'foo')
|
172
|
+
@c.create(:abc => 'bar')
|
173
|
+
|
174
|
+
MODEL_DB.sqls.should == ["SELECT * FROM items LIMIT 1",
|
175
|
+
"UPDATE items SET abc = 'oof' WHERE (id = 1)",
|
176
|
+
"INSERT INTO items (abc) VALUES ('rab')",
|
177
|
+
"SELECT * FROM items WHERE (id = 10) LIMIT 1"]
|
178
|
+
end
|
179
|
+
|
136
180
|
it "should copy serialization formats and columns to subclasses" do
|
137
181
|
@c.set_primary_key :id
|
138
182
|
@c.plugin :serialization, :yaml, :abc, :def
|
@@ -172,7 +172,7 @@ describe "sharding plugin" do
|
|
172
172
|
# Should select from current object's shard to check existing association, but update associated object's shard
|
173
173
|
sqls = @db.sqls
|
174
174
|
["UPDATE albums SET artist_id = NULL, name = 'T' WHERE (id = 5) -- s4", "UPDATE albums SET name = 'T', artist_id = NULL WHERE (id = 5) -- s4"].should include(sqls.pop)
|
175
|
-
sqls.should == ["SELECT 1 FROM albums WHERE ((albums.artist_id = 2) AND (id = 5)) LIMIT 1 -- s2"]
|
175
|
+
sqls.should == ["SELECT 1 AS one FROM albums WHERE ((albums.artist_id = 2) AND (id = 5)) LIMIT 1 -- s2"]
|
176
176
|
end
|
177
177
|
|
178
178
|
specify "should be able to set a shard to use for any object using set_server" do
|
@@ -584,6 +584,21 @@ describe "Sequel::Model Simple Associations" do
|
|
584
584
|
it_should_behave_like "eager limit strategies"
|
585
585
|
end unless Sequel.guarded?(:mysql, :db2, :oracle)
|
586
586
|
|
587
|
+
specify "should handle many_to_one associations with same name as :key" do
|
588
|
+
Album.def_column_alias(:artist_id_id, :artist_id)
|
589
|
+
Album.many_to_one :artist_id, :key_column =>:artist_id, :class=>Artist
|
590
|
+
@album.update(:artist_id_id => @artist.id)
|
591
|
+
@album.artist_id.should == @artist
|
592
|
+
|
593
|
+
as = Album.eager(:artist_id).all
|
594
|
+
as.should == [@album]
|
595
|
+
as.map{|a| a.artist_id}.should == [@artist]
|
596
|
+
|
597
|
+
as = Album.eager_graph(:artist_id).all
|
598
|
+
as.should == [@album]
|
599
|
+
as.map{|a| a.artist_id}.should == [@artist]
|
600
|
+
end
|
601
|
+
|
587
602
|
specify "should handle aliased tables when eager_graphing" do
|
588
603
|
@album.update(:artist => @artist)
|
589
604
|
@album.add_tag(@tag)
|