sequel 3.30.0 → 3.31.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|