viking-sequel 3.10.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 +3134 -0
- data/COPYING +19 -0
- data/README.rdoc +723 -0
- data/Rakefile +193 -0
- data/bin/sequel +196 -0
- data/doc/advanced_associations.rdoc +644 -0
- data/doc/cheat_sheet.rdoc +218 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/dataset_filtering.rdoc +158 -0
- data/doc/opening_databases.rdoc +296 -0
- data/doc/prepared_statements.rdoc +104 -0
- data/doc/reflection.rdoc +84 -0
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.12.0.txt +534 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/doc/release_notes/3.1.0.txt +406 -0
- data/doc/release_notes/3.10.0.txt +286 -0
- data/doc/release_notes/3.2.0.txt +268 -0
- data/doc/release_notes/3.3.0.txt +192 -0
- data/doc/release_notes/3.4.0.txt +325 -0
- data/doc/release_notes/3.5.0.txt +510 -0
- data/doc/release_notes/3.6.0.txt +366 -0
- data/doc/release_notes/3.7.0.txt +179 -0
- data/doc/release_notes/3.8.0.txt +151 -0
- data/doc/release_notes/3.9.0.txt +233 -0
- data/doc/schema.rdoc +36 -0
- data/doc/sharding.rdoc +113 -0
- data/doc/virtual_rows.rdoc +205 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel/adapters/ado.rb +90 -0
- data/lib/sequel/adapters/ado/mssql.rb +30 -0
- data/lib/sequel/adapters/amalgalite.rb +176 -0
- data/lib/sequel/adapters/db2.rb +139 -0
- data/lib/sequel/adapters/dbi.rb +113 -0
- data/lib/sequel/adapters/do.rb +188 -0
- data/lib/sequel/adapters/do/mysql.rb +49 -0
- data/lib/sequel/adapters/do/postgres.rb +91 -0
- data/lib/sequel/adapters/do/sqlite.rb +40 -0
- data/lib/sequel/adapters/firebird.rb +283 -0
- data/lib/sequel/adapters/informix.rb +77 -0
- data/lib/sequel/adapters/jdbc.rb +587 -0
- data/lib/sequel/adapters/jdbc/as400.rb +58 -0
- data/lib/sequel/adapters/jdbc/h2.rb +133 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
- data/lib/sequel/adapters/mysql.rb +421 -0
- data/lib/sequel/adapters/odbc.rb +143 -0
- data/lib/sequel/adapters/odbc/mssql.rb +42 -0
- data/lib/sequel/adapters/openbase.rb +64 -0
- data/lib/sequel/adapters/oracle.rb +131 -0
- data/lib/sequel/adapters/postgres.rb +504 -0
- data/lib/sequel/adapters/shared/mssql.rb +490 -0
- data/lib/sequel/adapters/shared/mysql.rb +498 -0
- data/lib/sequel/adapters/shared/oracle.rb +195 -0
- data/lib/sequel/adapters/shared/postgres.rb +830 -0
- data/lib/sequel/adapters/shared/progress.rb +44 -0
- data/lib/sequel/adapters/shared/sqlite.rb +389 -0
- data/lib/sequel/adapters/sqlite.rb +224 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
- data/lib/sequel/connection_pool.rb +99 -0
- data/lib/sequel/connection_pool/sharded_single.rb +84 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
- data/lib/sequel/connection_pool/single.rb +29 -0
- data/lib/sequel/connection_pool/threaded.rb +150 -0
- data/lib/sequel/core.rb +293 -0
- data/lib/sequel/core_sql.rb +241 -0
- data/lib/sequel/database.rb +1079 -0
- data/lib/sequel/database/schema_generator.rb +327 -0
- data/lib/sequel/database/schema_methods.rb +203 -0
- data/lib/sequel/database/schema_sql.rb +320 -0
- data/lib/sequel/dataset.rb +32 -0
- data/lib/sequel/dataset/actions.rb +441 -0
- data/lib/sequel/dataset/features.rb +86 -0
- data/lib/sequel/dataset/graph.rb +254 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +227 -0
- data/lib/sequel/dataset/query.rb +709 -0
- data/lib/sequel/dataset/sql.rb +996 -0
- data/lib/sequel/exceptions.rb +51 -0
- data/lib/sequel/extensions/blank.rb +43 -0
- data/lib/sequel/extensions/inflector.rb +242 -0
- data/lib/sequel/extensions/looser_typecasting.rb +21 -0
- data/lib/sequel/extensions/migration.rb +239 -0
- data/lib/sequel/extensions/named_timezones.rb +61 -0
- data/lib/sequel/extensions/pagination.rb +100 -0
- data/lib/sequel/extensions/pretty_table.rb +82 -0
- data/lib/sequel/extensions/query.rb +52 -0
- data/lib/sequel/extensions/schema_dumper.rb +271 -0
- data/lib/sequel/extensions/sql_expr.rb +122 -0
- data/lib/sequel/extensions/string_date_time.rb +46 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
- data/lib/sequel/metaprogramming.rb +9 -0
- data/lib/sequel/model.rb +120 -0
- data/lib/sequel/model/associations.rb +1514 -0
- data/lib/sequel/model/base.rb +1069 -0
- data/lib/sequel/model/default_inflections.rb +45 -0
- data/lib/sequel/model/errors.rb +39 -0
- data/lib/sequel/model/exceptions.rb +21 -0
- data/lib/sequel/model/inflections.rb +162 -0
- data/lib/sequel/model/plugins.rb +70 -0
- data/lib/sequel/plugins/active_model.rb +59 -0
- data/lib/sequel/plugins/association_dependencies.rb +103 -0
- data/lib/sequel/plugins/association_proxies.rb +41 -0
- data/lib/sequel/plugins/boolean_readers.rb +53 -0
- data/lib/sequel/plugins/caching.rb +141 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
- data/lib/sequel/plugins/composition.rb +138 -0
- data/lib/sequel/plugins/force_encoding.rb +72 -0
- data/lib/sequel/plugins/hook_class_methods.rb +126 -0
- data/lib/sequel/plugins/identity_map.rb +116 -0
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/instance_hooks.rb +57 -0
- data/lib/sequel/plugins/lazy_attributes.rb +77 -0
- data/lib/sequel/plugins/many_through_many.rb +208 -0
- data/lib/sequel/plugins/nested_attributes.rb +206 -0
- data/lib/sequel/plugins/optimistic_locking.rb +81 -0
- data/lib/sequel/plugins/rcte_tree.rb +281 -0
- data/lib/sequel/plugins/schema.rb +66 -0
- data/lib/sequel/plugins/serialization.rb +166 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
- data/lib/sequel/plugins/subclasses.rb +45 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
- data/lib/sequel/plugins/timestamps.rb +87 -0
- data/lib/sequel/plugins/touch.rb +118 -0
- data/lib/sequel/plugins/typecast_on_load.rb +72 -0
- data/lib/sequel/plugins/validation_class_methods.rb +405 -0
- data/lib/sequel/plugins/validation_helpers.rb +223 -0
- data/lib/sequel/sql.rb +1020 -0
- data/lib/sequel/timezones.rb +161 -0
- data/lib/sequel/version.rb +12 -0
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/firebird_spec.rb +407 -0
- data/spec/adapters/informix_spec.rb +97 -0
- data/spec/adapters/mssql_spec.rb +403 -0
- data/spec/adapters/mysql_spec.rb +1019 -0
- data/spec/adapters/oracle_spec.rb +286 -0
- data/spec/adapters/postgres_spec.rb +969 -0
- data/spec/adapters/spec_helper.rb +51 -0
- data/spec/adapters/sqlite_spec.rb +432 -0
- data/spec/core/connection_pool_spec.rb +808 -0
- data/spec/core/core_sql_spec.rb +417 -0
- data/spec/core/database_spec.rb +1662 -0
- data/spec/core/dataset_spec.rb +3827 -0
- data/spec/core/expression_filters_spec.rb +595 -0
- data/spec/core/object_graph_spec.rb +296 -0
- data/spec/core/schema_generator_spec.rb +159 -0
- data/spec/core/schema_spec.rb +830 -0
- data/spec/core/spec_helper.rb +56 -0
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/active_model_spec.rb +76 -0
- data/spec/extensions/association_dependencies_spec.rb +127 -0
- data/spec/extensions/association_proxies_spec.rb +50 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/boolean_readers_spec.rb +92 -0
- data/spec/extensions/caching_spec.rb +250 -0
- data/spec/extensions/class_table_inheritance_spec.rb +252 -0
- data/spec/extensions/composition_spec.rb +194 -0
- data/spec/extensions/force_encoding_spec.rb +117 -0
- data/spec/extensions/hook_class_methods_spec.rb +470 -0
- data/spec/extensions/identity_map_spec.rb +202 -0
- data/spec/extensions/inflector_spec.rb +181 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/instance_hooks_spec.rb +133 -0
- data/spec/extensions/lazy_attributes_spec.rb +153 -0
- data/spec/extensions/looser_typecasting_spec.rb +39 -0
- data/spec/extensions/many_through_many_spec.rb +884 -0
- data/spec/extensions/migration_spec.rb +332 -0
- data/spec/extensions/named_timezones_spec.rb +72 -0
- data/spec/extensions/nested_attributes_spec.rb +396 -0
- data/spec/extensions/optimistic_locking_spec.rb +100 -0
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/extensions/rcte_tree_spec.rb +205 -0
- data/spec/extensions/schema_dumper_spec.rb +357 -0
- data/spec/extensions/schema_spec.rb +127 -0
- data/spec/extensions/serialization_spec.rb +209 -0
- data/spec/extensions/single_table_inheritance_spec.rb +96 -0
- data/spec/extensions/spec_helper.rb +91 -0
- data/spec/extensions/sql_expr_spec.rb +89 -0
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/extensions/subclasses_spec.rb +52 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
- data/spec/extensions/thread_local_timezones_spec.rb +45 -0
- data/spec/extensions/timestamps_spec.rb +150 -0
- data/spec/extensions/touch_spec.rb +155 -0
- data/spec/extensions/typecast_on_load_spec.rb +69 -0
- data/spec/extensions/validation_class_methods_spec.rb +984 -0
- data/spec/extensions/validation_helpers_spec.rb +438 -0
- data/spec/integration/associations_test.rb +281 -0
- data/spec/integration/database_test.rb +26 -0
- data/spec/integration/dataset_test.rb +963 -0
- data/spec/integration/eager_loader_test.rb +734 -0
- data/spec/integration/model_test.rb +130 -0
- data/spec/integration/plugin_test.rb +814 -0
- data/spec/integration/prepared_statement_test.rb +213 -0
- data/spec/integration/schema_test.rb +361 -0
- data/spec/integration/spec_helper.rb +73 -0
- data/spec/integration/timezone_test.rb +55 -0
- data/spec/integration/transaction_test.rb +122 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/model/association_reflection_spec.rb +175 -0
- data/spec/model/associations_spec.rb +2633 -0
- data/spec/model/base_spec.rb +418 -0
- data/spec/model/dataset_methods_spec.rb +78 -0
- data/spec/model/eager_loading_spec.rb +1391 -0
- data/spec/model/hooks_spec.rb +240 -0
- data/spec/model/inflector_spec.rb +26 -0
- data/spec/model/model_spec.rb +593 -0
- data/spec/model/plugins_spec.rb +236 -0
- data/spec/model/record_spec.rb +1500 -0
- data/spec/model/spec_helper.rb +97 -0
- data/spec/model/validations_spec.rb +153 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +346 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
unless defined?(INFORMIX_DB)
|
4
|
+
INFORMIX_DB = Sequel.connect('informix://localhost/mydb')
|
5
|
+
end
|
6
|
+
INTEGRATION_DB = INFORMIX_DB unless defined?(INTEGRATION_DB)
|
7
|
+
|
8
|
+
if INFORMIX_DB.table_exists?(:test)
|
9
|
+
INFORMIX_DB.drop_table :test
|
10
|
+
end
|
11
|
+
INFORMIX_DB.create_table :test do
|
12
|
+
text :name
|
13
|
+
integer :value
|
14
|
+
|
15
|
+
index :value
|
16
|
+
end
|
17
|
+
|
18
|
+
context "A Informix database" do
|
19
|
+
specify "should provide disconnect functionality" do
|
20
|
+
INFORMIX_DB.execute("select user from dual")
|
21
|
+
INFORMIX_DB.pool.size.should == 1
|
22
|
+
INFORMIX_DB.disconnect
|
23
|
+
INFORMIX_DB.pool.size.should == 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "A Informix dataset" do
|
28
|
+
before do
|
29
|
+
@d = INFORMIX_DB[:test]
|
30
|
+
@d.delete # remove all records
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "should return the correct record count" do
|
34
|
+
@d.count.should == 0
|
35
|
+
@d << {:name => 'abc', :value => 123}
|
36
|
+
@d << {:name => 'abc', :value => 456}
|
37
|
+
@d << {:name => 'def', :value => 789}
|
38
|
+
@d.count.should == 3
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should return the correct records" do
|
42
|
+
@d.to_a.should == []
|
43
|
+
@d << {:name => 'abc', :value => 123}
|
44
|
+
@d << {:name => 'abc', :value => 456}
|
45
|
+
@d << {:name => 'def', :value => 789}
|
46
|
+
|
47
|
+
@d.order(:value).to_a.should == [
|
48
|
+
{:name => 'abc', :value => 123},
|
49
|
+
{:name => 'abc', :value => 456},
|
50
|
+
{:name => 'def', :value => 789}
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
specify "should update records correctly" do
|
55
|
+
@d << {:name => 'abc', :value => 123}
|
56
|
+
@d << {:name => 'abc', :value => 456}
|
57
|
+
@d << {:name => 'def', :value => 789}
|
58
|
+
@d.filter(:name => 'abc').update(:value => 530)
|
59
|
+
|
60
|
+
# the third record should stay the same
|
61
|
+
# floating-point precision bullshit
|
62
|
+
@d[:name => 'def'][:value].should == 789
|
63
|
+
@d.filter(:value => 530).count.should == 2
|
64
|
+
end
|
65
|
+
|
66
|
+
specify "should delete records correctly" do
|
67
|
+
@d << {:name => 'abc', :value => 123}
|
68
|
+
@d << {:name => 'abc', :value => 456}
|
69
|
+
@d << {:name => 'def', :value => 789}
|
70
|
+
@d.filter(:name => 'abc').delete
|
71
|
+
|
72
|
+
@d.count.should == 1
|
73
|
+
@d.first[:name].should == 'def'
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "should be able to literalize booleans" do
|
77
|
+
proc {@d.literal(true)}.should_not raise_error
|
78
|
+
proc {@d.literal(false)}.should_not raise_error
|
79
|
+
end
|
80
|
+
|
81
|
+
specify "should support transactions" do
|
82
|
+
INFORMIX_DB.transaction do
|
83
|
+
@d << {:name => 'abc', :value => 1}
|
84
|
+
end
|
85
|
+
|
86
|
+
@d.count.should == 1
|
87
|
+
end
|
88
|
+
|
89
|
+
specify "should support #first and #last" do
|
90
|
+
@d << {:name => 'abc', :value => 123}
|
91
|
+
@d << {:name => 'abc', :value => 456}
|
92
|
+
@d << {:name => 'def', :value => 789}
|
93
|
+
|
94
|
+
@d.order(:value).first.should == {:name => 'abc', :value => 123}
|
95
|
+
@d.order(:value).last.should == {:name => 'def', :value => 789}
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,403 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
require ENV['SEQUEL_MSSQL_SPEC_REQUIRE'] if ENV['SEQUEL_MSSQL_SPEC_REQUIRE']
|
4
|
+
|
5
|
+
unless defined?(MSSQL_DB)
|
6
|
+
MSSQL_URL = 'jdbc:sqlserver://localhost;integratedSecurity=true;database=sandbox' unless defined? MSSQL_URL
|
7
|
+
MSSQL_DB = Sequel.connect(ENV['SEQUEL_MSSQL_SPEC_DB']||MSSQL_URL)
|
8
|
+
end
|
9
|
+
INTEGRATION_DB = MSSQL_DB unless defined?(INTEGRATION_DB)
|
10
|
+
|
11
|
+
def MSSQL_DB.sqls
|
12
|
+
(@sqls ||= [])
|
13
|
+
end
|
14
|
+
logger = Object.new
|
15
|
+
def logger.method_missing(m, msg)
|
16
|
+
MSSQL_DB.sqls << msg
|
17
|
+
end
|
18
|
+
MSSQL_DB.logger = logger
|
19
|
+
|
20
|
+
MSSQL_DB.create_table! :test do
|
21
|
+
text :name
|
22
|
+
integer :value, :index => true
|
23
|
+
end
|
24
|
+
MSSQL_DB.create_table! :test2 do
|
25
|
+
text :name
|
26
|
+
integer :value
|
27
|
+
end
|
28
|
+
MSSQL_DB.create_table! :test3 do
|
29
|
+
integer :value
|
30
|
+
timestamp :time
|
31
|
+
end
|
32
|
+
MSSQL_DB.create_table! :test4 do
|
33
|
+
varchar :name, :size => 20
|
34
|
+
varbinary :value
|
35
|
+
end
|
36
|
+
|
37
|
+
context "A MSSQL database" do
|
38
|
+
before do
|
39
|
+
@db = MSSQL_DB
|
40
|
+
end
|
41
|
+
|
42
|
+
cspecify "should be able to read fractional part of timestamp", :odbc do
|
43
|
+
rs = @db["select getutcdate() as full_date, cast(datepart(millisecond, getutcdate()) as int) as milliseconds"].first
|
44
|
+
rs[:milliseconds].should == rs[:full_date].usec/1000
|
45
|
+
end
|
46
|
+
|
47
|
+
cspecify "should be able to write fractional part of timestamp", :odbc do
|
48
|
+
t = Time.utc(2001, 12, 31, 23, 59, 59, 997000)
|
49
|
+
(t.usec/1000).should == @db["select cast(datepart(millisecond, ?) as int) as milliseconds", t].get
|
50
|
+
end
|
51
|
+
|
52
|
+
specify "should not raise an error when getting the server version" do
|
53
|
+
proc{@db.server_version}.should_not raise_error
|
54
|
+
proc{@db.dataset.server_version}.should_not raise_error
|
55
|
+
end
|
56
|
+
|
57
|
+
specify "should work with NOLOCK" do
|
58
|
+
@db.transaction{@db[:test3].nolock.all.should == []}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "MSSQL Dataset#join_table" do
|
63
|
+
specify "should emulate the USING clause with ON" do
|
64
|
+
MSSQL_DB[:items].join(:categories, [:id]).sql.should ==
|
65
|
+
'SELECT * FROM ITEMS INNER JOIN CATEGORIES ON (CATEGORIES.ID = ITEMS.ID)'
|
66
|
+
MSSQL_DB[:items].join(:categories, [:id1, :id2]).sql.should ==
|
67
|
+
'SELECT * FROM ITEMS INNER JOIN CATEGORIES ON ((CATEGORIES.ID1 = ITEMS.ID1) AND (CATEGORIES.ID2 = ITEMS.ID2))'
|
68
|
+
MSSQL_DB[:items___i].join(:categories___c, [:id]).sql.should ==
|
69
|
+
'SELECT * FROM ITEMS AS I INNER JOIN CATEGORIES AS C ON (C.ID = I.ID)'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "MSSQL Dataset#output" do
|
74
|
+
before do
|
75
|
+
@db = MSSQL_DB
|
76
|
+
@db.create_table!(:items){String :name; Integer :value}
|
77
|
+
@db.create_table!(:out){String :name; Integer :value}
|
78
|
+
@ds = @db[:items]
|
79
|
+
end
|
80
|
+
after do
|
81
|
+
@db.drop_table(:items)
|
82
|
+
@db.drop_table(:out)
|
83
|
+
end
|
84
|
+
|
85
|
+
specify "should format OUTPUT clauses without INTO for DELETE statements" do
|
86
|
+
@ds.output(nil, [:deleted__name, :deleted__value]).delete_sql.should =~
|
87
|
+
/DELETE FROM ITEMS OUTPUT DELETED.(NAME|VALUE), DELETED.(NAME|VALUE)/
|
88
|
+
@ds.output(nil, [:deleted.*]).delete_sql.should =~
|
89
|
+
/DELETE FROM ITEMS OUTPUT DELETED.*/
|
90
|
+
end
|
91
|
+
|
92
|
+
specify "should format OUTPUT clauses with INTO for DELETE statements" do
|
93
|
+
@ds.output(:out, [:deleted__name, :deleted__value]).delete_sql.should =~
|
94
|
+
/DELETE FROM ITEMS OUTPUT DELETED.(NAME|VALUE), DELETED.(NAME|VALUE) INTO OUT/
|
95
|
+
@ds.output(:out, {:name => :deleted__name, :value => :deleted__value}).delete_sql.should =~
|
96
|
+
/DELETE FROM ITEMS OUTPUT DELETED.(NAME|VALUE), DELETED.(NAME|VALUE) INTO OUT \((NAME|VALUE), (NAME|VALUE)\)/
|
97
|
+
end
|
98
|
+
|
99
|
+
specify "should format OUTPUT clauses without INTO for INSERT statements" do
|
100
|
+
@ds.output(nil, [:inserted__name, :inserted__value]).insert_sql(:name => "name", :value => 1).should =~
|
101
|
+
/INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.(NAME|VALUE), INSERTED.(NAME|VALUE) VALUES \((N'name'|1), (N'name'|1)\)/
|
102
|
+
@ds.output(nil, [:inserted.*]).insert_sql(:name => "name", :value => 1).should =~
|
103
|
+
/INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.* VALUES \((N'name'|1), (N'name'|1)\)/
|
104
|
+
end
|
105
|
+
|
106
|
+
specify "should format OUTPUT clauses with INTO for INSERT statements" do
|
107
|
+
@ds.output(:out, [:inserted__name, :inserted__value]).insert_sql(:name => "name", :value => 1).should =~
|
108
|
+
/INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.(NAME|VALUE), INSERTED.(NAME|VALUE) INTO OUT VALUES \((N'name'|1), (N'name'|1)\)/
|
109
|
+
@ds.output(:out, {:name => :inserted__name, :value => :inserted__value}).insert_sql(:name => "name", :value => 1).should =~
|
110
|
+
/INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.(NAME|VALUE), INSERTED.(NAME|VALUE) INTO OUT \((NAME|VALUE), (NAME|VALUE)\) VALUES \((N'name'|1), (N'name'|1)\)/
|
111
|
+
end
|
112
|
+
|
113
|
+
specify "should format OUTPUT clauses without INTO for UPDATE statements" do
|
114
|
+
@ds.output(nil, [:inserted__name, :deleted__value]).update_sql(:value => 2).should =~
|
115
|
+
/UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED.NAME|DELETED.VALUE), (INSERTED.NAME|DELETED.VALUE)/
|
116
|
+
@ds.output(nil, [:inserted.*]).update_sql(:value => 2).should =~
|
117
|
+
/UPDATE ITEMS SET VALUE = 2 OUTPUT INSERTED.*/
|
118
|
+
end
|
119
|
+
|
120
|
+
specify "should format OUTPUT clauses with INTO for UPDATE statements" do
|
121
|
+
@ds.output(:out, [:inserted__name, :deleted__value]).update_sql(:value => 2).should =~
|
122
|
+
/UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED.NAME|DELETED.VALUE), (INSERTED.NAME|DELETED.VALUE) INTO OUT/
|
123
|
+
@ds.output(:out, {:name => :inserted__name, :value => :deleted__value}).update_sql(:value => 2).should =~
|
124
|
+
/UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED.NAME|DELETED.VALUE), (INSERTED.NAME|DELETED.VALUE) INTO OUT \((NAME|VALUE), (NAME|VALUE)\)/
|
125
|
+
end
|
126
|
+
|
127
|
+
specify "should execute OUTPUT clauses in DELETE statements" do
|
128
|
+
@ds.insert(:name => "name", :value => 1)
|
129
|
+
@ds.output(:out, [:deleted__name, :deleted__value]).delete
|
130
|
+
@db[:out].all.should == [{:name => "name", :value => 1}]
|
131
|
+
@ds.insert(:name => "name", :value => 2)
|
132
|
+
@ds.output(:out, {:name => :deleted__name, :value => :deleted__value}).delete
|
133
|
+
@db[:out].all.should == [{:name => "name", :value => 1}, {:name => "name", :value => 2}]
|
134
|
+
end
|
135
|
+
|
136
|
+
specify "should execute OUTPUT clauses in INSERT statements" do
|
137
|
+
@ds.output(:out, [:inserted__name, :inserted__value]).insert(:name => "name", :value => 1)
|
138
|
+
@db[:out].all.should == [{:name => "name", :value => 1}]
|
139
|
+
@ds.output(:out, {:name => :inserted__name, :value => :inserted__value}).insert(:name => "name", :value => 2)
|
140
|
+
@db[:out].all.should == [{:name => "name", :value => 1}, {:name => "name", :value => 2}]
|
141
|
+
end
|
142
|
+
|
143
|
+
specify "should execute OUTPUT clauses in UPDATE statements" do
|
144
|
+
@ds.insert(:name => "name", :value => 1)
|
145
|
+
@ds.output(:out, [:inserted__name, :deleted__value]).update(:value => 2)
|
146
|
+
@db[:out].all.should == [{:name => "name", :value => 1}]
|
147
|
+
@ds.output(:out, {:name => :inserted__name, :value => :deleted__value}).update(:value => 3)
|
148
|
+
@db[:out].all.should == [{:name => "name", :value => 1}, {:name => "name", :value => 2}]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "MSSQL dataset" do
|
153
|
+
before do
|
154
|
+
@db = MSSQL_DB
|
155
|
+
@ds = MSSQL_DB[:t]
|
156
|
+
end
|
157
|
+
|
158
|
+
context "using #with and #with_recursive" do
|
159
|
+
before do
|
160
|
+
@ds1 = @ds.with(:t, @db[:x])
|
161
|
+
@ds2 = @ds.with_recursive(:t, @db[:x], @db[:t])
|
162
|
+
end
|
163
|
+
|
164
|
+
specify "should prepend UPDATE statements with WITH clause" do
|
165
|
+
@ds1.update_sql(:x => :y).should == 'WITH T AS (SELECT * FROM X) UPDATE T SET X = Y'
|
166
|
+
@ds2.update_sql(:x => :y).should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) UPDATE T SET X = Y'
|
167
|
+
end
|
168
|
+
|
169
|
+
specify "should prepend DELETE statements with WITH clause" do
|
170
|
+
@ds1.filter(:y => 1).delete_sql.should == 'WITH T AS (SELECT * FROM X) DELETE FROM T WHERE (Y = 1)'
|
171
|
+
@ds2.filter(:y => 1).delete_sql.should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) DELETE FROM T WHERE (Y = 1)'
|
172
|
+
end
|
173
|
+
|
174
|
+
specify "should prepend INSERT statements with WITH clause" do
|
175
|
+
@ds1.insert_sql(@db[:t]).should == 'WITH T AS (SELECT * FROM X) INSERT INTO T SELECT * FROM T'
|
176
|
+
@ds2.insert_sql(@db[:t]).should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) INSERT INTO T SELECT * FROM T'
|
177
|
+
end
|
178
|
+
|
179
|
+
context "on #import" do
|
180
|
+
before do
|
181
|
+
@db = @db.clone
|
182
|
+
class << @db
|
183
|
+
attr_reader :import_sqls
|
184
|
+
|
185
|
+
def execute(sql, opts={})
|
186
|
+
@import_sqls ||= []
|
187
|
+
@import_sqls << sql
|
188
|
+
end
|
189
|
+
alias execute_dui execute
|
190
|
+
|
191
|
+
def transaction(opts={})
|
192
|
+
@import_sqls ||= []
|
193
|
+
@import_sqls << 'BEGIN'
|
194
|
+
yield
|
195
|
+
@import_sqls << 'COMMIT'
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
specify "should prepend INSERT statements with WITH clause" do
|
201
|
+
@db[:items].with(:items, @db[:inventory].group(:type)).import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
202
|
+
@db.import_sqls.should == [
|
203
|
+
'BEGIN',
|
204
|
+
"WITH ITEMS AS (SELECT * FROM INVENTORY GROUP BY TYPE) INSERT INTO ITEMS (X, Y) SELECT 1, 2 UNION ALL SELECT 3, 4",
|
205
|
+
'COMMIT',
|
206
|
+
'BEGIN',
|
207
|
+
"WITH ITEMS AS (SELECT * FROM INVENTORY GROUP BY TYPE) INSERT INTO ITEMS (X, Y) SELECT 5, 6",
|
208
|
+
'COMMIT'
|
209
|
+
]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context "MSSQL joined datasets" do
|
216
|
+
before do
|
217
|
+
@db = MSSQL_DB
|
218
|
+
end
|
219
|
+
|
220
|
+
specify "should format DELETE statements" do
|
221
|
+
@db[:t1].inner_join(:t2, :t1__pk => :t2__pk).delete_sql.should ==
|
222
|
+
"DELETE FROM T1 FROM T1 INNER JOIN T2 ON (T1.PK = T2.PK)"
|
223
|
+
end
|
224
|
+
|
225
|
+
specify "should format UPDATE statements" do
|
226
|
+
@db[:t1].inner_join(:t2, :t1__pk => :t2__pk).update_sql(:pk => :t2__pk).should ==
|
227
|
+
"UPDATE T1 SET PK = T2.PK FROM T1 INNER JOIN T2 ON (T1.PK = T2.PK)"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe "Offset support" do
|
232
|
+
before do
|
233
|
+
@db = MSSQL_DB
|
234
|
+
@db.create_table!(:i){Integer :id; Integer :parent_id}
|
235
|
+
@ds = @db[:i].order(:id)
|
236
|
+
@hs = []
|
237
|
+
@ds.row_proc = proc{|r| @hs << r.dup; r[:id] *= 2; r[:parent_id] *= 3; r}
|
238
|
+
@ds.import [:id, :parent_id], [[1,nil],[2,nil],[3,1],[4,1],[5,3],[6,5]]
|
239
|
+
end
|
240
|
+
after do
|
241
|
+
@db.drop_table(:i)
|
242
|
+
end
|
243
|
+
|
244
|
+
specify "should return correct rows" do
|
245
|
+
@ds.limit(2, 2).all.should == [{:id=>6, :parent_id=>3}, {:id=>8, :parent_id=>3}]
|
246
|
+
end
|
247
|
+
|
248
|
+
specify "should not include offset column in hashes passed to row_proc" do
|
249
|
+
@ds.limit(2, 2).all
|
250
|
+
@hs.should == [{:id=>3, :parent_id=>1}, {:id=>4, :parent_id=>1}]
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "Common Table Expressions" do
|
255
|
+
before do
|
256
|
+
@db = MSSQL_DB
|
257
|
+
@db.create_table!(:i1){Integer :id; Integer :parent_id}
|
258
|
+
@db.create_table!(:i2){Integer :id; Integer :parent_id}
|
259
|
+
@ds = @db[:i1]
|
260
|
+
@ds2 = @db[:i2]
|
261
|
+
@ds.import [:id, :parent_id], [[1,nil],[2,nil],[3,1],[4,1],[5,3],[6,5]]
|
262
|
+
end
|
263
|
+
after do
|
264
|
+
@db.drop_table(:i1)
|
265
|
+
@db.drop_table(:i2)
|
266
|
+
end
|
267
|
+
|
268
|
+
specify "using #with should be able to update" do
|
269
|
+
@ds.insert(:id=>1)
|
270
|
+
@ds2.insert(:id=>2, :parent_id=>1)
|
271
|
+
@ds2.insert(:id=>3, :parent_id=>2)
|
272
|
+
@ds.with(:t, @ds2).filter(:id => @db[:t].select(:id)).update(:parent_id => @db[:t].filter(:id => :i1__id).select(:parent_id).limit(1))
|
273
|
+
@ds[:id => 1].should == {:id => 1, :parent_id => nil}
|
274
|
+
@ds[:id => 2].should == {:id => 2, :parent_id => 1}
|
275
|
+
@ds[:id => 3].should == {:id => 3, :parent_id => 2}
|
276
|
+
@ds[:id => 4].should == {:id => 4, :parent_id => 1}
|
277
|
+
end
|
278
|
+
|
279
|
+
specify "using #with_recursive should be able to update" do
|
280
|
+
ds = @ds.with_recursive(:t, @ds.filter(:parent_id=>1).or(:id => 1), @ds.join(:t, :i=>:parent_id).select(:i1__id, :i1__parent_id), :args=>[:i, :pi])
|
281
|
+
ds.filter(~{:id => @db[:t].select(:i)}).update(:parent_id => 1)
|
282
|
+
@ds[:id => 1].should == {:id => 1, :parent_id => nil}
|
283
|
+
@ds[:id => 2].should == {:id => 2, :parent_id => 1}
|
284
|
+
@ds[:id => 5].should == {:id => 5, :parent_id => 3}
|
285
|
+
end
|
286
|
+
|
287
|
+
specify "using #with should be able to insert" do
|
288
|
+
@ds2.insert(:id=>7)
|
289
|
+
@ds.with(:t, @ds2).insert(@db[:t])
|
290
|
+
@ds[:id => 7].should == {:id => 7, :parent_id => nil}
|
291
|
+
end
|
292
|
+
|
293
|
+
specify "using #with_recursive should be able to insert" do
|
294
|
+
ds = @ds2.with_recursive(:t, @ds.filter(:parent_id=>1), @ds.join(:t, :i=>:parent_id).select(:i1__id, :i1__parent_id), :args=>[:i, :pi])
|
295
|
+
ds.insert @db[:t]
|
296
|
+
@ds2.all.should == [{:id => 3, :parent_id => 1}, {:id => 4, :parent_id => 1}, {:id => 5, :parent_id => 3}, {:id => 6, :parent_id => 5}]
|
297
|
+
end
|
298
|
+
|
299
|
+
specify "using #with should be able to delete" do
|
300
|
+
@ds2.insert(:id=>6)
|
301
|
+
@ds2.insert(:id=>5)
|
302
|
+
@ds2.insert(:id=>4)
|
303
|
+
@ds.with(:t, @ds2).filter(:id => @db[:t].select(:id)).delete
|
304
|
+
@ds.all.should == [{:id => 1, :parent_id => nil}, {:id => 2, :parent_id => nil}, {:id => 3, :parent_id => 1}]
|
305
|
+
end
|
306
|
+
|
307
|
+
specify "using #with_recursive should be able to delete" do
|
308
|
+
@ds.insert(:id=>7, :parent_id=>2)
|
309
|
+
ds = @ds.with_recursive(:t, @ds.filter(:parent_id=>1), @ds.join(:t, :i=>:parent_id).select(:i1__id, :i1__parent_id), :args=>[:i, :pi])
|
310
|
+
ds.filter(:i1__id => @db[:t].select(:i)).delete
|
311
|
+
@ds.all.should == [{:id => 1, :parent_id => nil}, {:id => 2, :parent_id => nil}, {:id => 7, :parent_id => 2}]
|
312
|
+
end
|
313
|
+
|
314
|
+
specify "using #with should be able to import" do
|
315
|
+
@ds2.insert(:id=>7)
|
316
|
+
@ds.with(:t, @ds2).import [:id, :parent_id], @db[:t].select(:id, :parent_id)
|
317
|
+
@ds[:id => 7].should == {:id => 7, :parent_id => nil}
|
318
|
+
end
|
319
|
+
|
320
|
+
specify "using #with_recursive should be able to import" do
|
321
|
+
ds = @ds2.with_recursive(:t, @ds.filter(:parent_id=>1), @ds.join(:t, :i=>:parent_id).select(:i1__id, :i1__parent_id), :args=>[:i, :pi])
|
322
|
+
ds.import [:id, :parent_id], @db[:t].select(:i, :pi)
|
323
|
+
@ds2.all.should == [{:id => 3, :parent_id => 1}, {:id => 4, :parent_id => 1}, {:id => 5, :parent_id => 3}, {:id => 6, :parent_id => 5}]
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context "MSSSQL::Dataset#insert" do
|
328
|
+
before do
|
329
|
+
@db = MSSQL_DB
|
330
|
+
@db.create_table!(:test5){primary_key :xid; Integer :value}
|
331
|
+
@db.sqls.clear
|
332
|
+
@ds = @db[:test5]
|
333
|
+
end
|
334
|
+
after do
|
335
|
+
@db.drop_table(:test5) rescue nil
|
336
|
+
end
|
337
|
+
|
338
|
+
specify "should have insert_select return nil if disable_insert_output is used" do
|
339
|
+
@ds.disable_insert_output.insert_select(:value=>10).should == nil
|
340
|
+
end
|
341
|
+
|
342
|
+
specify "should have insert_select return nil if the server version is not 2005+" do
|
343
|
+
@ds.meta_def(:server_version){8000760}
|
344
|
+
@ds.insert_select(:value=>10).should == nil
|
345
|
+
end
|
346
|
+
|
347
|
+
specify "should have insert_select insert the record and return the inserted record" do
|
348
|
+
h = @ds.insert_select(:value=>10)
|
349
|
+
h[:value].should == 10
|
350
|
+
@ds.first(:xid=>h[:xid])[:value].should == 10
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
context "MSSSQL::Dataset#disable_insert_output" do
|
355
|
+
specify "should play nicely with simple_select_all?" do
|
356
|
+
MSSQL_DB[:test].disable_insert_output.send(:simple_select_all?).should == true
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
context "MSSSQL::Dataset#into" do
|
361
|
+
before do
|
362
|
+
@db = MSSQL_DB
|
363
|
+
end
|
364
|
+
|
365
|
+
specify "should format SELECT statement" do
|
366
|
+
@db[:t].into(:new).select_sql.should == "SELECT * INTO NEW FROM T"
|
367
|
+
end
|
368
|
+
|
369
|
+
specify "should select rows into a new table" do
|
370
|
+
@db.create_table!(:t) {Integer :id; String :value}
|
371
|
+
@db[:t].insert(:id => 1, :value => "test")
|
372
|
+
@db << @db[:t].into(:new).select_sql
|
373
|
+
@db[:new].all.should == [{:id => 1, :value => "test"}]
|
374
|
+
@db.drop_table(:t)
|
375
|
+
@db.drop_table(:new)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
context "A MSSQL database" do
|
380
|
+
before do
|
381
|
+
@db = MSSQL_DB
|
382
|
+
end
|
383
|
+
after do
|
384
|
+
@db.drop_table(:a)
|
385
|
+
end
|
386
|
+
|
387
|
+
specify "should handle many existing types for set_column_allow_null" do
|
388
|
+
@db.create_table!(:a){column :a, 'integer'}
|
389
|
+
@db.alter_table(:a){set_column_allow_null :a, false}
|
390
|
+
@db.create_table!(:a){column :a, 'decimal(24, 2)'}
|
391
|
+
@db.alter_table(:a){set_column_allow_null :a, false}
|
392
|
+
@db.schema(:a).first.last[:column_size].should == 24
|
393
|
+
@db.schema(:a).first.last[:scale].should == 2
|
394
|
+
@db.create_table!(:a){column :a, 'decimal(10)'}
|
395
|
+
@db.schema(:a).first.last[:column_size].should == 10
|
396
|
+
@db.schema(:a).first.last[:scale].should == 0
|
397
|
+
@db.alter_table(:a){set_column_allow_null :a, false}
|
398
|
+
@db.create_table!(:a){column :a, 'nchar(2)'}
|
399
|
+
@db.alter_table(:a){set_column_allow_null :a, false}
|
400
|
+
s = @db.schema(:a).first.last
|
401
|
+
(s[:max_chars] || s[:column_size]).should == 2
|
402
|
+
end
|
403
|
+
end
|