sequel 3.33.0 → 3.34.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +140 -0
- data/Rakefile +7 -0
- data/bin/sequel +22 -2
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/mass_assignment.rdoc +3 -1
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +23 -3
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/schema_modification.rdoc +18 -2
- data/doc/virtual_rows.rdoc +49 -0
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/ibmdb.rb +9 -4
- data/lib/sequel/adapters/jdbc.rb +9 -4
- data/lib/sequel/adapters/jdbc/h2.rb +8 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
- data/lib/sequel/adapters/mock.rb +24 -3
- data/lib/sequel/adapters/mysql.rb +29 -50
- data/lib/sequel/adapters/mysql2.rb +13 -28
- data/lib/sequel/adapters/oracle.rb +8 -2
- data/lib/sequel/adapters/postgres.rb +115 -20
- data/lib/sequel/adapters/shared/db2.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +14 -3
- data/lib/sequel/adapters/shared/mysql.rb +59 -11
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +127 -30
- data/lib/sequel/adapters/shared/sqlite.rb +55 -38
- data/lib/sequel/adapters/sqlite.rb +9 -3
- data/lib/sequel/adapters/swift.rb +2 -2
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +10 -0
- data/lib/sequel/ast_transformer.rb +4 -0
- data/lib/sequel/connection_pool.rb +8 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +14 -0
- data/lib/sequel/core.rb +24 -3
- data/lib/sequel/database/connecting.rb +24 -14
- data/lib/sequel/database/dataset_defaults.rb +1 -0
- data/lib/sequel/database/misc.rb +16 -25
- data/lib/sequel/database/query.rb +20 -2
- data/lib/sequel/database/schema_generator.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +120 -23
- data/lib/sequel/dataset/actions.rb +91 -18
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -2
- data/lib/sequel/dataset/sql.rb +68 -51
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +227 -31
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model.rb +11 -2
- data/lib/sequel/model/associations.rb +35 -7
- data/lib/sequel/model/base.rb +159 -36
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +11 -3
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +4 -3
- data/lib/sequel/plugins/prepared_statements.rb +3 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
- data/lib/sequel/plugins/schema.rb +7 -2
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +417 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +12 -15
- data/spec/adapters/mysql_spec.rb +81 -23
- data/spec/adapters/postgres_spec.rb +444 -77
- data/spec/adapters/spec_helper.rb +2 -0
- data/spec/adapters/sqlite_spec.rb +8 -8
- data/spec/core/connection_pool_spec.rb +85 -0
- data/spec/core/database_spec.rb +29 -5
- data/spec/core/dataset_spec.rb +171 -3
- data/spec/core/expression_filters_spec.rb +364 -0
- data/spec/core/mock_adapter_spec.rb +17 -3
- data/spec/core/schema_spec.rb +133 -0
- data/spec/extensions/association_dependencies_spec.rb +13 -13
- data/spec/extensions/caching_spec.rb +26 -3
- data/spec/extensions/class_table_inheritance_spec.rb +2 -2
- data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +5 -2
- data/spec/extensions/identity_map_spec.rb +17 -0
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/lazy_attributes_spec.rb +2 -2
- data/spec/extensions/list_spec.rb +4 -4
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +6 -2
- data/spec/extensions/nested_attributes_spec.rb +20 -0
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +2 -2
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- data/spec/extensions/prepared_statements_spec.rb +4 -0
- data/spec/extensions/pretty_table_spec.rb +6 -0
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +231 -11
- data/spec/extensions/schema_spec.rb +14 -2
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/sharding_spec.rb +6 -6
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +2 -1
- data/spec/extensions/sql_expr_spec.rb +28 -19
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +9 -1
- data/spec/integration/associations_test.rb +6 -6
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +89 -26
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +3 -3
- data/spec/integration/plugin_test.rb +85 -22
- data/spec/integration/prepared_statement_test.rb +28 -8
- data/spec/integration/schema_test.rb +78 -7
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +4 -6
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/associations_spec.rb +94 -8
- data/spec/model/base_spec.rb +4 -4
- data/spec/model/hooks_spec.rb +2 -2
- data/spec/model/model_spec.rb +19 -7
- data/spec/model/record_spec.rb +135 -58
- data/spec/model/spec_helper.rb +1 -0
- metadata +35 -7
@@ -713,4 +713,368 @@ describe Sequel::SQL::VirtualRow do
|
|
713
713
|
Sequel::BasicObject.remove_methods!
|
714
714
|
@d.l{a > adsoiwemlsdaf2}.should == '("a" > "adsoiwemlsdaf2")'
|
715
715
|
end
|
716
|
+
|
717
|
+
it "should have operator methods defined that produce Sequel expression objects" do
|
718
|
+
@d.l{|o| o.&({:a=>1}, :b)}.should == '(("a" = 1) AND "b")'
|
719
|
+
@d.l{|o| o.|({:a=>1}, :b)}.should == '(("a" = 1) OR "b")'
|
720
|
+
@d.l{|o| o.+(1, :b) > 2}.should == '((1 + "b") > 2)'
|
721
|
+
@d.l{|o| o.-(1, :b) < 2}.should == '((1 - "b") < 2)'
|
722
|
+
@d.l{|o| o.*(1, :b) >= 2}.should == '((1 * "b") >= 2)'
|
723
|
+
@d.l{|o| o./(1, :b) <= 2}.should == '((1 / "b") <= 2)'
|
724
|
+
@d.l{|o| o.~(:a=>1)}.should == '("a" != 1)'
|
725
|
+
@d.l{|o| o.~([[:a, 1], [:b, 2]])}.should == '(("a" != 1) OR ("b" != 2))'
|
726
|
+
@d.l{|o| o.<(1, :b)}.should == '(1 < "b")'
|
727
|
+
@d.l{|o| o.>(1, :b)}.should == '(1 > "b")'
|
728
|
+
@d.l{|o| o.<=(1, :b)}.should == '(1 <= "b")'
|
729
|
+
@d.l{|o| o.>=(1, :b)}.should == '(1 >= "b")'
|
730
|
+
end
|
731
|
+
|
732
|
+
it "should have have ` produce literal strings" do
|
733
|
+
@d.l{a > `some SQL`}.should == '("a" > some SQL)'
|
734
|
+
@d.l{|o| o.a > o.`('some SQL')}.should == '("a" > some SQL)' #`
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
describe "Sequel core extension replacements" do
|
739
|
+
before do
|
740
|
+
@db = Sequel::Database.new
|
741
|
+
@o = Object.new
|
742
|
+
def @o.sql_literal(ds) 'foo' end
|
743
|
+
end
|
744
|
+
|
745
|
+
def l(arg, should)
|
746
|
+
@db.literal(arg).should == should
|
747
|
+
end
|
748
|
+
|
749
|
+
it "Sequel.expr should return an appropriate wrapped object" do
|
750
|
+
l(Sequel.expr(1) + 1, "(1 + 1)")
|
751
|
+
l(Sequel.expr('a') + 'b', "('a' || 'b')")
|
752
|
+
l(Sequel.expr(:b) & nil, "(b AND NULL)")
|
753
|
+
l(Sequel.expr(nil) & true, "(NULL AND 't')")
|
754
|
+
l(Sequel.expr(false) & true, "('f' AND 't')")
|
755
|
+
l(Sequel.expr(true) | false, "('t' OR 'f')")
|
756
|
+
l(Sequel.expr(@o) + 1, "(foo + 1)")
|
757
|
+
end
|
758
|
+
|
759
|
+
it "Sequel.expr should handle condition specifiers" do
|
760
|
+
l(Sequel.expr(:a=>1) & nil, "((a = 1) AND NULL)")
|
761
|
+
l(Sequel.expr([[:a, 1]]) & nil, "((a = 1) AND NULL)")
|
762
|
+
l(Sequel.expr([[:a, 1], [:b, 2]]) & nil, "((a = 1) AND (b = 2) AND NULL)")
|
763
|
+
end
|
764
|
+
|
765
|
+
it "Sequel.expr should treat blocks/procs as virtual rows and wrap the output" do
|
766
|
+
l(Sequel.expr{1} + 1, "(1 + 1)")
|
767
|
+
l(Sequel.expr{o__a} + 1, "(o.a + 1)")
|
768
|
+
l(Sequel.expr{[[:a, 1]]} & nil, "((a = 1) AND NULL)")
|
769
|
+
l(Sequel.expr{|v| @o} + 1, "(foo + 1)")
|
770
|
+
|
771
|
+
l(Sequel.expr(proc{1}) + 1, "(1 + 1)")
|
772
|
+
l(Sequel.expr(proc{o__a}) + 1, "(o.a + 1)")
|
773
|
+
l(Sequel.expr(proc{[[:a, 1]]}) & nil, "((a = 1) AND NULL)")
|
774
|
+
l(Sequel.expr(proc{|v| @o}) + 1, "(foo + 1)")
|
775
|
+
end
|
776
|
+
|
777
|
+
it "Sequel.expr should raise an error if given an argument and a block" do
|
778
|
+
proc{Sequel.expr(nil){}}.should raise_error(Sequel::Error)
|
779
|
+
end
|
780
|
+
|
781
|
+
it "Sequel.expr should raise an error if given neither an argument nor a block" do
|
782
|
+
proc{Sequel.expr}.should raise_error(Sequel::Error)
|
783
|
+
end
|
784
|
+
|
785
|
+
it "Sequel.expr should return existing Sequel expressions directly" do
|
786
|
+
o = Sequel.expr(1)
|
787
|
+
Sequel.expr(o).should equal(o)
|
788
|
+
o = Sequel.lit('1')
|
789
|
+
Sequel.expr(o).should equal(o)
|
790
|
+
end
|
791
|
+
|
792
|
+
it "Sequel.~ should invert the given object" do
|
793
|
+
l(Sequel.~(nil), 'NOT NULL')
|
794
|
+
l(Sequel.~(:a=>1), "(a != 1)")
|
795
|
+
l(Sequel.~([[:a, 1]]), "(a != 1)")
|
796
|
+
l(Sequel.~([[:a, 1], [:b, 2]]), "((a != 1) OR (b != 2))")
|
797
|
+
l(Sequel.~(Sequel.expr([[:a, 1], [:b, 2]]) & nil), "((a != 1) OR (b != 2) OR NOT NULL)")
|
798
|
+
end
|
799
|
+
|
800
|
+
it "Sequel.case should use a CASE expression" do
|
801
|
+
l(Sequel.case({:a=>1}, 2), "(CASE WHEN a THEN 1 ELSE 2 END)")
|
802
|
+
l(Sequel.case({:a=>1}, 2, :b), "(CASE b WHEN a THEN 1 ELSE 2 END)")
|
803
|
+
l(Sequel.case([[:a, 1]], 2), "(CASE WHEN a THEN 1 ELSE 2 END)")
|
804
|
+
l(Sequel.case([[:a, 1]], 2, :b), "(CASE b WHEN a THEN 1 ELSE 2 END)")
|
805
|
+
l(Sequel.case([[:a, 1], [:c, 3]], 2), "(CASE WHEN a THEN 1 WHEN c THEN 3 ELSE 2 END)")
|
806
|
+
l(Sequel.case([[:a, 1], [:c, 3]], 2, :b), "(CASE b WHEN a THEN 1 WHEN c THEN 3 ELSE 2 END)")
|
807
|
+
end
|
808
|
+
|
809
|
+
it "Sequel.case should raise an error if not given a condition specifier" do
|
810
|
+
proc{Sequel.case(1, 2)}.should raise_error(Sequel::Error)
|
811
|
+
end
|
812
|
+
|
813
|
+
it "Sequel.value_list should use an SQL value list" do
|
814
|
+
l(Sequel.value_list([[1, 2]]), "((1, 2))")
|
815
|
+
end
|
816
|
+
|
817
|
+
it "Sequel.value_list raise an error if not given an array" do
|
818
|
+
proc{Sequel.value_list(1)}.should raise_error(Sequel::Error)
|
819
|
+
end
|
820
|
+
|
821
|
+
it "Sequel.negate should negate all entries in conditions specifier and join with AND" do
|
822
|
+
l(Sequel.negate(:a=>1), "(a != 1)")
|
823
|
+
l(Sequel.negate([[:a, 1]]), "(a != 1)")
|
824
|
+
l(Sequel.negate([[:a, 1], [:b, 2]]), "((a != 1) AND (b != 2))")
|
825
|
+
end
|
826
|
+
|
827
|
+
it "Sequel.negate should raise an error if not given a conditions specifier" do
|
828
|
+
proc{Sequel.negate(1)}.should raise_error(Sequel::Error)
|
829
|
+
end
|
830
|
+
|
831
|
+
it "Sequel.or should join all entries in conditions specifier with OR" do
|
832
|
+
l(Sequel.or(:a=>1), "(a = 1)")
|
833
|
+
l(Sequel.or([[:a, 1]]), "(a = 1)")
|
834
|
+
l(Sequel.or([[:a, 1], [:b, 2]]), "((a = 1) OR (b = 2))")
|
835
|
+
end
|
836
|
+
|
837
|
+
it "Sequel.or should raise an error if not given a conditions specifier" do
|
838
|
+
proc{Sequel.or(1)}.should raise_error(Sequel::Error)
|
839
|
+
end
|
840
|
+
|
841
|
+
it "Sequel.join should should use SQL string concatenation to join array" do
|
842
|
+
l(Sequel.join([]), "''")
|
843
|
+
l(Sequel.join(['a']), "('a')")
|
844
|
+
l(Sequel.join(['a', 'b']), "('a' || 'b')")
|
845
|
+
l(Sequel.join(['a', 'b'], 'c'), "('a' || 'c' || 'b')")
|
846
|
+
l(Sequel.join([true, :b], :c), "('t' || c || b)")
|
847
|
+
l(Sequel.join([false, nil], Sequel.lit('c')), "('f' || c || NULL)")
|
848
|
+
l(Sequel.join([Sequel.expr('a'), Sequel.lit('d')], 'c'), "('a' || 'c' || d)")
|
849
|
+
end
|
850
|
+
|
851
|
+
it "Sequel.join should raise an error if not given an array" do
|
852
|
+
proc{Sequel.join(1)}.should raise_error(Sequel::Error)
|
853
|
+
end
|
854
|
+
|
855
|
+
it "Sequel.& should join all arguments given with AND" do
|
856
|
+
l(Sequel.&(:a), "(a)")
|
857
|
+
l(Sequel.&(:a, :b=>:c), "(a AND (b = c))")
|
858
|
+
l(Sequel.&(:a, {:b=>:c}, Sequel.lit('d')), "(a AND (b = c) AND d)")
|
859
|
+
end
|
860
|
+
|
861
|
+
it "Sequel.& should raise an error if given no arguments" do
|
862
|
+
proc{Sequel.&}.should raise_error(Sequel::Error)
|
863
|
+
end
|
864
|
+
|
865
|
+
it "Sequel.| should join all arguments given with OR" do
|
866
|
+
l(Sequel.|(:a), "(a)")
|
867
|
+
l(Sequel.|(:a, :b=>:c), "(a OR (b = c))")
|
868
|
+
l(Sequel.|(:a, {:b=>:c}, Sequel.lit('d')), "(a OR (b = c) OR d)")
|
869
|
+
end
|
870
|
+
|
871
|
+
it "Sequel.| should raise an error if given no arguments" do
|
872
|
+
proc{Sequel.|}.should raise_error(Sequel::Error)
|
873
|
+
end
|
874
|
+
|
875
|
+
it "Sequel.as should return an aliased expression" do
|
876
|
+
l(Sequel.as(:a, :b), "a AS b")
|
877
|
+
end
|
878
|
+
|
879
|
+
it "Sequel.cast should return a CAST expression" do
|
880
|
+
l(Sequel.cast(:a, :int), "CAST(a AS int)")
|
881
|
+
l(Sequel.cast(:a, Integer), "CAST(a AS integer)")
|
882
|
+
end
|
883
|
+
|
884
|
+
it "Sequel.cast_numeric should return a CAST expression treated as a number" do
|
885
|
+
l(Sequel.cast_numeric(:a), "CAST(a AS integer)")
|
886
|
+
l(Sequel.cast_numeric(:a, :int), "CAST(a AS int)")
|
887
|
+
l(Sequel.cast_numeric(:a) << 2, "(CAST(a AS integer) << 2)")
|
888
|
+
end
|
889
|
+
|
890
|
+
it "Sequel.cast_string should return a CAST expression treated as a string" do
|
891
|
+
l(Sequel.cast_string(:a), "CAST(a AS varchar(255))")
|
892
|
+
l(Sequel.cast_string(:a, :text), "CAST(a AS text)")
|
893
|
+
l(Sequel.cast_string(:a) + 'a', "(CAST(a AS varchar(255)) || 'a')")
|
894
|
+
end
|
895
|
+
|
896
|
+
it "Sequel.lit should return a literal string" do
|
897
|
+
l(Sequel.lit('a'), "a")
|
898
|
+
end
|
899
|
+
|
900
|
+
it "Sequel.lit should return the argument if given a single literal string" do
|
901
|
+
o = Sequel.lit('a')
|
902
|
+
Sequel.lit(o).should equal(o)
|
903
|
+
end
|
904
|
+
|
905
|
+
it "Sequel.lit should accept multiple arguments for a placeholder literal string" do
|
906
|
+
l(Sequel.lit('a = ?', 1), "a = 1")
|
907
|
+
l(Sequel.lit('? = ?', :a, 1), "a = 1")
|
908
|
+
l(Sequel.lit('a = :a', :a=>1), "a = 1")
|
909
|
+
end
|
910
|
+
|
911
|
+
it "Sequel.lit should work with an array for the placeholder string" do
|
912
|
+
l(Sequel.lit(['a = '], 1), "a = 1")
|
913
|
+
l(Sequel.lit(['', ' = '], :a, 1), "a = 1")
|
914
|
+
end
|
915
|
+
|
916
|
+
it "Sequel.blob should return an SQL::Blob" do
|
917
|
+
l(Sequel.blob('a'), "'a'")
|
918
|
+
Sequel.blob('a').should be_a_kind_of(Sequel::SQL::Blob)
|
919
|
+
end
|
920
|
+
|
921
|
+
it "Sequel.blob should return the given argument if given a blob" do
|
922
|
+
o = Sequel.blob('a')
|
923
|
+
Sequel.blob(o).should equal(o)
|
924
|
+
end
|
925
|
+
|
926
|
+
it "Sequel.qualify should return a qualified identifier" do
|
927
|
+
l(Sequel.qualify(:t, :c), "t.c")
|
928
|
+
end
|
929
|
+
|
930
|
+
it "Sequel.identifier should return an identifier" do
|
931
|
+
l(Sequel.identifier(:t__c), "t__c")
|
932
|
+
end
|
933
|
+
|
934
|
+
it "Sequel.asc should return an ASC ordered expression" do
|
935
|
+
l(Sequel.asc(:a), "a ASC")
|
936
|
+
l(Sequel.asc(:a, :nulls=>:first), "a ASC NULLS FIRST")
|
937
|
+
end
|
938
|
+
|
939
|
+
it "Sequel.desc should return a DESC ordered expression " do
|
940
|
+
l(Sequel.desc(:a), "a DESC")
|
941
|
+
l(Sequel.desc(:a, :nulls=>:last), "a DESC NULLS LAST")
|
942
|
+
end
|
943
|
+
|
944
|
+
it "Sequel.{+,-,*,/} should accept arguments and use the appropriate operator" do
|
945
|
+
%w'+ - * /'.each do |op|
|
946
|
+
l(Sequel.send(op, 1), '(1)')
|
947
|
+
l(Sequel.send(op, 1, 2), "(1 #{op} 2)")
|
948
|
+
l(Sequel.send(op, 1, 2, 3), "(1 #{op} 2 #{op} 3)")
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
it "Sequel.{+,-,*,/} should raise if given no arguments" do
|
953
|
+
%w'+ - * /'.each do |op|
|
954
|
+
proc{Sequel.send(op)}.should raise_error(Sequel::Error)
|
955
|
+
end
|
956
|
+
end
|
957
|
+
|
958
|
+
it "Sequel.like should use a LIKE expression" do
|
959
|
+
l(Sequel.like('a', 'b'), "('a' LIKE 'b')")
|
960
|
+
l(Sequel.like(:a, :b), "(a LIKE b)")
|
961
|
+
l(Sequel.like(:a, /b/), "(a ~ 'b')")
|
962
|
+
l(Sequel.like(:a, 'c', /b/), "((a LIKE 'c') OR (a ~ 'b'))")
|
963
|
+
end
|
964
|
+
|
965
|
+
it "Sequel.ilike should use an ILIKE expression" do
|
966
|
+
l(Sequel.ilike('a', 'b'), "('a' ILIKE 'b')")
|
967
|
+
l(Sequel.ilike(:a, :b), "(a ILIKE b)")
|
968
|
+
l(Sequel.ilike(:a, /b/), "(a ~* 'b')")
|
969
|
+
l(Sequel.ilike(:a, 'c', /b/), "((a ILIKE 'c') OR (a ~* 'b'))")
|
970
|
+
end
|
971
|
+
|
972
|
+
it "Sequel.subscript should use an SQL subscript" do
|
973
|
+
l(Sequel.subscript(:a, 1), 'a[1]')
|
974
|
+
l(Sequel.subscript(:a, 1, 2), 'a[1, 2]')
|
975
|
+
l(Sequel.subscript(:a, [1, 2]), 'a[1, 2]')
|
976
|
+
end
|
977
|
+
|
978
|
+
it "Sequel.function should return an SQL function" do
|
979
|
+
l(Sequel.function(:a), 'a()')
|
980
|
+
l(Sequel.function(:a, 1), 'a(1)')
|
981
|
+
l(Sequel.function(:a, :b, 2), 'a(b, 2)')
|
982
|
+
end
|
983
|
+
|
984
|
+
it "Sequel.extract should use a date/time extraction" do
|
985
|
+
l(Sequel.extract(:year, :a), 'extract(year FROM a)')
|
986
|
+
end
|
987
|
+
end
|
988
|
+
|
989
|
+
describe "Sequel::SQL::Function#==" do
|
990
|
+
specify "should be true for functions with the same name and arguments, false otherwise" do
|
991
|
+
a = :date.sql_function(:t)
|
992
|
+
b = :date.sql_function(:t)
|
993
|
+
a.should == b
|
994
|
+
(a == b).should == true
|
995
|
+
c = :date.sql_function(:c)
|
996
|
+
a.should_not == c
|
997
|
+
(a == c).should == false
|
998
|
+
d = :time.sql_function(:c)
|
999
|
+
a.should_not == d
|
1000
|
+
c.should_not == d
|
1001
|
+
(a == d).should == false
|
1002
|
+
(c == d).should == false
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
describe "Sequel::SQL::OrderedExpression" do
|
1007
|
+
specify "should #desc" do
|
1008
|
+
@oe = Sequel.asc(:column)
|
1009
|
+
@oe.descending.should == false
|
1010
|
+
@oe.desc.descending.should == true
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
specify "should #asc" do
|
1014
|
+
@oe = Sequel.desc(:column)
|
1015
|
+
@oe.descending.should == true
|
1016
|
+
@oe.asc.descending.should == false
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
specify "should #invert" do
|
1020
|
+
@oe = Sequel.desc(:column)
|
1021
|
+
@oe.invert.descending.should == false
|
1022
|
+
@oe.invert.invert.descending.should == true
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
describe "Expression" do
|
1027
|
+
specify "should consider objects == only if they have the same attributes" do
|
1028
|
+
:column.qualify(:table).cast(:type).*(:numeric_column).asc.should == :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
1029
|
+
:other_column.qualify(:table).cast(:type).*(:numeric_column).asc.should_not == :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
1030
|
+
|
1031
|
+
:column.qualify(:table).cast(:type).*(:numeric_column).asc.should eql(:column.qualify(:table).cast(:type).*(:numeric_column).asc)
|
1032
|
+
:other_column.qualify(:table).cast(:type).*(:numeric_column).asc.should_not eql(:column.qualify(:table).cast(:type).*(:numeric_column).asc)
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
specify "should use the same hash value for objects that have the same attributes" do
|
1036
|
+
:column.qualify(:table).cast(:type).*(:numeric_column).asc.hash.should == :column.qualify(:table).cast(:type).*(:numeric_column).asc.hash
|
1037
|
+
:other_column.qualify(:table).cast(:type).*(:numeric_column).asc.hash.should_not == :column.qualify(:table).cast(:type).*(:numeric_column).asc.hash
|
1038
|
+
|
1039
|
+
h = {}
|
1040
|
+
a = :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
1041
|
+
b = :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
1042
|
+
h[a] = 1
|
1043
|
+
h[b] = 2
|
1044
|
+
h[a].should == 2
|
1045
|
+
h[b].should == 2
|
1046
|
+
end
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
describe "Sequel::SQLTime" do
|
1050
|
+
before do
|
1051
|
+
@db = Sequel.mock
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
specify ".create should create from hour, minutes, seconds and optional microseconds" do
|
1055
|
+
@db.literal(Sequel::SQLTime.create(1, 2, 3)).should == "'01:02:03.000000'"
|
1056
|
+
@db.literal(Sequel::SQLTime.create(1, 2, 3, 500000)).should == "'01:02:03.500000'"
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
describe "Sequel::SQL::Wrapper" do
|
1061
|
+
before do
|
1062
|
+
@ds = Sequel.mock.dataset
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
specify "should wrap objects so they can be used by the Sequel DSL" do
|
1066
|
+
o = Object.new
|
1067
|
+
def o.sql_literal(ds) 'foo' end
|
1068
|
+
s = Sequel::SQL::Wrapper.new(o)
|
1069
|
+
@ds.literal(s).should == "foo"
|
1070
|
+
@ds.literal(s+1).should == "(foo + 1)"
|
1071
|
+
@ds.literal(s & true).should == "(foo AND 't')"
|
1072
|
+
@ds.literal(s < 1).should == "(foo < 1)"
|
1073
|
+
@ds.literal(s.sql_subscript(1)).should == "foo[1]"
|
1074
|
+
@ds.literal(s.like('a')).should == "(foo LIKE 'a')"
|
1075
|
+
@ds.literal(s.as(:a)).should == "foo AS a"
|
1076
|
+
@ds.literal(s.cast(Integer)).should == "CAST(foo AS integer)"
|
1077
|
+
@ds.literal(s.desc).should == "foo DESC"
|
1078
|
+
@ds.literal(s.sql_string + '1').should == "(foo || '1')"
|
1079
|
+
end
|
716
1080
|
end
|
@@ -17,13 +17,16 @@ describe "Sequel Mock Adapter" do
|
|
17
17
|
called.should be_false
|
18
18
|
end
|
19
19
|
|
20
|
-
specify "should return 0 for update
|
20
|
+
specify "should return 0 for update/delete/with_sql_delete/execute_dui by default" do
|
21
21
|
Sequel.mock[:t].update(:a=>1).should == 0
|
22
22
|
Sequel.mock[:t].delete.should == 0
|
23
|
+
Sequel.mock[:t].with_sql_delete('DELETE FROM t').should == 0
|
24
|
+
Sequel.mock.execute_dui('DELETE FROM t').should == 0
|
23
25
|
end
|
24
26
|
|
25
|
-
specify "should return nil for insert by default" do
|
27
|
+
specify "should return nil for insert/execute_insert by default" do
|
26
28
|
Sequel.mock[:t].insert(:a=>1).should be_nil
|
29
|
+
Sequel.mock.execute_insert('INSERT INTO a () DEFAULT VALUES').should be_nil
|
27
30
|
end
|
28
31
|
|
29
32
|
specify "should be able to set the rows returned by each using :fetch option with a single hash" do
|
@@ -299,6 +302,13 @@ describe "Sequel Mock Adapter" do
|
|
299
302
|
Sequel.mock.send(:quote_identifiers_default).should be_false
|
300
303
|
end
|
301
304
|
|
305
|
+
specify "should allow overriding of server_version" do
|
306
|
+
db = Sequel.mock
|
307
|
+
db.server_version.should == nil
|
308
|
+
db.server_version = 80102
|
309
|
+
db.server_version.should == 80102
|
310
|
+
end
|
311
|
+
|
302
312
|
specify "should not have identifier input/output methods by default" do
|
303
313
|
Sequel.mock.send(:identifier_input_method_default).should be_nil
|
304
314
|
Sequel.mock.send(:identifier_output_method_default).should be_nil
|
@@ -420,7 +430,7 @@ describe "Sequel Mock Adapter" do
|
|
420
430
|
Sequel.mock(:host=>'mssql')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM [A] WHERE (CONTAINS ([B], 'c'))"
|
421
431
|
Sequel.mock(:host=>'mysql')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM `a` WHERE (MATCH (`b`) AGAINST ('c'))"
|
422
432
|
Sequel.mock(:host=>'oracle')[:a].limit(1).sql.should == 'SELECT * FROM (SELECT * FROM "A") "T1" WHERE (ROWNUM <= 1)'
|
423
|
-
Sequel.mock(:host=>'postgres')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM \"a\" WHERE (to_tsvector('simple', (COALESCE(\"b\", ''))) @@ to_tsquery('simple', 'c'))"
|
433
|
+
Sequel.mock(:host=>'postgres')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM \"a\" WHERE (to_tsvector('simple'::regconfig, (COALESCE(\"b\", ''))) @@ to_tsquery('simple'::regconfig, 'c'))"
|
424
434
|
Sequel.mock(:host=>'sqlite')[:a___b].sql.should == "SELECT * FROM `a` AS 'b'"
|
425
435
|
ensure
|
426
436
|
Sequel.quote_identifiers = qi
|
@@ -428,4 +438,8 @@ describe "Sequel Mock Adapter" do
|
|
428
438
|
Sequel::Database.send(:class_variable_set, :@@identifier_output_method, io)
|
429
439
|
end
|
430
440
|
end
|
441
|
+
|
442
|
+
specify "should automatically set version for postgres" do
|
443
|
+
Sequel.mock(:host=>'postgres').server_version.should == 90103
|
444
|
+
end
|
431
445
|
end
|
data/spec/core/schema_spec.rb
CHANGED
@@ -227,6 +227,11 @@ describe "DB#create_table" do
|
|
227
227
|
foreign_key :project_id, :table => :projects, :on_delete => :set_default
|
228
228
|
end
|
229
229
|
@db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON DELETE SET DEFAULT)"]
|
230
|
+
|
231
|
+
@db.create_table(:cats) do
|
232
|
+
foreign_key :project_id, :table => :projects, :on_delete => 'NO ACTION FOO'
|
233
|
+
end
|
234
|
+
@db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON DELETE NO ACTION FOO)"]
|
230
235
|
end
|
231
236
|
|
232
237
|
specify "should accept foreign keys with ON UPDATE clause" do
|
@@ -254,6 +259,11 @@ describe "DB#create_table" do
|
|
254
259
|
foreign_key :project_id, :table => :projects, :on_update => :set_default
|
255
260
|
end
|
256
261
|
@db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON UPDATE SET DEFAULT)"]
|
262
|
+
|
263
|
+
@db.create_table(:cats) do
|
264
|
+
foreign_key :project_id, :table => :projects, :on_update => 'SET DEFAULT FOO'
|
265
|
+
end
|
266
|
+
@db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON UPDATE SET DEFAULT FOO)"]
|
257
267
|
end
|
258
268
|
|
259
269
|
specify "should accept foreign keys with deferrable option" do
|
@@ -569,6 +579,87 @@ describe "DB#create_table?" do
|
|
569
579
|
end
|
570
580
|
end
|
571
581
|
|
582
|
+
describe "DB#create_join_table" do
|
583
|
+
before do
|
584
|
+
@db = Sequel.mock
|
585
|
+
end
|
586
|
+
|
587
|
+
specify "should take a hash with foreign keys and table name values" do
|
588
|
+
@db.create_join_table(:cat_id=>:cats, :dog_id=>:dogs)
|
589
|
+
@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)']
|
590
|
+
end
|
591
|
+
|
592
|
+
specify "should be able to have values be a hash of options" do
|
593
|
+
@db.create_join_table(:cat_id=>{:table=>:cats, :null=>true}, :dog_id=>{:table=>:dogs, :default=>0})
|
594
|
+
@db.sqls.should == ['CREATE TABLE cats_dogs (cat_id integer NULL REFERENCES cats, dog_id integer DEFAULT 0 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)']
|
595
|
+
end
|
596
|
+
|
597
|
+
specify "should be able to pass a second hash of table options" do
|
598
|
+
@db.create_join_table({:cat_id=>:cats, :dog_id=>:dogs}, :temp=>true)
|
599
|
+
@db.sqls.should == ['CREATE TEMPORARY 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)']
|
600
|
+
end
|
601
|
+
|
602
|
+
specify "should recognize :name option in table options" do
|
603
|
+
@db.create_join_table({:cat_id=>:cats, :dog_id=>:dogs}, :name=>:f)
|
604
|
+
@db.sqls.should == ['CREATE TABLE f (cat_id integer NOT NULL REFERENCES cats, dog_id integer NOT NULL REFERENCES dogs, PRIMARY KEY (cat_id, dog_id))', 'CREATE INDEX f_dog_id_cat_id_index ON f (dog_id, cat_id)']
|
605
|
+
end
|
606
|
+
|
607
|
+
specify "should recognize :index_options option in table options" do
|
608
|
+
@db.create_join_table({:cat_id=>:cats, :dog_id=>:dogs}, :index_options=>{:name=>:foo_index})
|
609
|
+
@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 foo_index ON cats_dogs (dog_id, cat_id)']
|
610
|
+
end
|
611
|
+
|
612
|
+
specify "should recognize :no_index option in table options" do
|
613
|
+
@db.create_join_table({:cat_id=>:cats, :dog_id=>:dogs}, :no_index=>true)
|
614
|
+
@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))']
|
615
|
+
end
|
616
|
+
|
617
|
+
specify "should recognize :no_primary_key option in table options" do
|
618
|
+
@db.create_join_table({:cat_id=>:cats, :dog_id=>:dogs}, :no_primary_key=>true)
|
619
|
+
@db.sqls.should == ['CREATE TABLE cats_dogs (cat_id integer NOT NULL REFERENCES cats, dog_id integer NOT NULL REFERENCES dogs)', 'CREATE INDEX cats_dogs_dog_id_cat_id_index ON cats_dogs (dog_id, cat_id)']
|
620
|
+
end
|
621
|
+
|
622
|
+
specify "should raise an error if the hash doesn't have 2 entries with table names" do
|
623
|
+
proc{@db.create_join_table({})}.should raise_error(Sequel::Error)
|
624
|
+
proc{@db.create_join_table({:cat_id=>:cats})}.should raise_error(Sequel::Error)
|
625
|
+
proc{@db.create_join_table({:cat_id=>:cats, :human_id=>:humans, :dog_id=>:dog})}.should raise_error(Sequel::Error)
|
626
|
+
proc{@db.create_join_table({:cat_id=>:cats, :dog_id=>{}})}.should raise_error(Sequel::Error)
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
describe "DB#drop_join_table" do
|
631
|
+
before do
|
632
|
+
@db = Sequel.mock
|
633
|
+
end
|
634
|
+
|
635
|
+
specify "should take a hash with foreign keys and table name values and drop the table" do
|
636
|
+
@db.drop_join_table(:cat_id=>:cats, :dog_id=>:dogs)
|
637
|
+
@db.sqls.should == ['DROP TABLE cats_dogs']
|
638
|
+
end
|
639
|
+
|
640
|
+
specify "should be able to have values be a hash of options" do
|
641
|
+
@db.drop_join_table(:cat_id=>{:table=>:cats, :null=>true}, :dog_id=>{:table=>:dogs, :default=>0})
|
642
|
+
@db.sqls.should == ['DROP TABLE cats_dogs']
|
643
|
+
end
|
644
|
+
|
645
|
+
specify "should respect a second hash of table options" do
|
646
|
+
@db.drop_join_table({:cat_id=>:cats, :dog_id=>:dogs}, :cascade=>true)
|
647
|
+
@db.sqls.should == ['DROP TABLE cats_dogs CASCADE']
|
648
|
+
end
|
649
|
+
|
650
|
+
specify "should respect :name option for table name" do
|
651
|
+
@db.drop_join_table({:cat_id=>:cats, :dog_id=>:dogs}, :name=>:f)
|
652
|
+
@db.sqls.should == ['DROP TABLE f']
|
653
|
+
end
|
654
|
+
|
655
|
+
specify "should raise an error if the hash doesn't have 2 entries with table names" do
|
656
|
+
proc{@db.drop_join_table({})}.should raise_error(Sequel::Error)
|
657
|
+
proc{@db.drop_join_table({:cat_id=>:cats})}.should raise_error(Sequel::Error)
|
658
|
+
proc{@db.drop_join_table({:cat_id=>:cats, :human_id=>:humans, :dog_id=>:dog})}.should raise_error(Sequel::Error)
|
659
|
+
proc{@db.drop_join_table({:cat_id=>:cats, :dog_id=>{}})}.should raise_error(Sequel::Error)
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
572
663
|
describe "DB#drop_table" do
|
573
664
|
before do
|
574
665
|
@db = Sequel.mock
|
@@ -590,6 +681,48 @@ describe "DB#drop_table" do
|
|
590
681
|
end
|
591
682
|
end
|
592
683
|
|
684
|
+
describe "DB#drop_table?" do
|
685
|
+
before do
|
686
|
+
@db = Sequel.mock
|
687
|
+
end
|
688
|
+
|
689
|
+
specify "should drop the table if it exists" do
|
690
|
+
@db.meta_def(:table_exists?){|a| true}
|
691
|
+
@db.drop_table?(:cats)
|
692
|
+
@db.sqls.should == ["DROP TABLE cats"]
|
693
|
+
end
|
694
|
+
|
695
|
+
specify "should do nothing if the table does not exist" do
|
696
|
+
@db.meta_def(:table_exists?){|a| false}
|
697
|
+
@db.drop_table?(:cats)
|
698
|
+
@db.sqls.should == []
|
699
|
+
end
|
700
|
+
|
701
|
+
specify "should operate on multiple tables at once" do
|
702
|
+
@db.meta_def(:table_exists?){|a| a == :cats}
|
703
|
+
@db.drop_table? :cats, :dogs
|
704
|
+
@db.sqls.should == ['DROP TABLE cats']
|
705
|
+
end
|
706
|
+
|
707
|
+
specify "should take an options hash and support the :cascade option" do
|
708
|
+
@db.meta_def(:table_exists?){|a| true}
|
709
|
+
@db.drop_table? :cats, :dogs, :cascade=>true
|
710
|
+
@db.sqls.should == ['DROP TABLE cats CASCADE', 'DROP TABLE dogs CASCADE']
|
711
|
+
end
|
712
|
+
|
713
|
+
specify "should use IF NOT EXISTS if the database supports that" do
|
714
|
+
@db.meta_def(:supports_drop_table_if_exists?){true}
|
715
|
+
@db.drop_table? :cats, :dogs
|
716
|
+
@db.sqls.should == ['DROP TABLE IF EXISTS cats', 'DROP TABLE IF EXISTS dogs']
|
717
|
+
end
|
718
|
+
|
719
|
+
specify "should use IF NOT EXISTS with CASCADE if the database supports that" do
|
720
|
+
@db.meta_def(:supports_drop_table_if_exists?){true}
|
721
|
+
@db.drop_table? :cats, :dogs, :cascade=>true
|
722
|
+
@db.sqls.should == ['DROP TABLE IF EXISTS cats CASCADE', 'DROP TABLE IF EXISTS dogs CASCADE']
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
593
726
|
describe "DB#alter_table" do
|
594
727
|
before do
|
595
728
|
@db = Sequel.mock
|