minus5_mssql 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/minus5_mssql/adapter.rb +61 -16
- data/test/helper.rb +29 -0
- data/test/test_select.rb +120 -0
- metadata +6 -4
data/lib/minus5_mssql/adapter.rb
CHANGED
@@ -53,26 +53,71 @@ module Minus5
|
|
53
53
|
|
54
54
|
# Returns results first column of the first row.
|
55
55
|
def select_value(sql)
|
56
|
-
rows = execute(sql).each
|
57
|
-
return
|
58
|
-
|
59
|
-
|
56
|
+
rows = execute(sql).each(:as=>:array)
|
57
|
+
return if rows.size == 0
|
58
|
+
rows[0][0].kind_of?(Array) ? rows[0][0][0] : rows[0][0]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns array of the values from the first column of all returned rows
|
62
|
+
def select_values(sql)
|
63
|
+
rows = execute(sql).each(:as=>:array)
|
64
|
+
return [] if rows.size == 0
|
65
|
+
(rows[0][0].kind_of?(Array) ? rows[0] : rows).map{|row| row[0] }
|
60
66
|
end
|
61
67
|
|
62
|
-
def select(
|
63
|
-
|
64
|
-
|
68
|
+
def select(options)
|
69
|
+
if options.kind_of?(String)
|
70
|
+
execute(options).each(:symbolize_keys=>true)
|
71
|
+
else
|
72
|
+
options = {:primary_key=>:id}.merge(options)
|
73
|
+
results = execute(options[:sql]).each(:symbolize_keys=>true)
|
74
|
+
return [] if results.size == 0
|
75
|
+
return results if results[0].kind_of?(Hash)
|
76
|
+
data = {} #parent indexed by primary_key
|
77
|
+
results[0].each{ |row| data[row[options[:primary_key]]] = row }
|
78
|
+
options[:relations].each_with_index do |relation, index|index
|
79
|
+
result = results[index+1] #child result
|
80
|
+
result.each do |row|
|
81
|
+
#find parent row by foreign key and insert child row in collection
|
82
|
+
data_row = data[row[relation[:foreign_key]]]
|
83
|
+
next unless data_row
|
84
|
+
if relation[:type] == :one_to_many
|
85
|
+
data_row[relation[:name]] = [] unless data_row[relation[:name]]
|
86
|
+
data_row[relation[:name]] << row
|
87
|
+
elsif relation[:type] == :one_to_one
|
88
|
+
#merge child row with parent
|
89
|
+
if relation[:name]
|
90
|
+
data_row[relation[:name]] = row
|
91
|
+
else
|
92
|
+
data_row.merge!(row.reject{|key, value| key == relation[:foreign_key]})
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
options[:return_hash] ? data : results[0]
|
98
|
+
end
|
65
99
|
end
|
66
100
|
|
101
|
+
def create_table(schema, table, columns_def)
|
102
|
+
execute <<-SQL
|
103
|
+
if not exists(select *
|
104
|
+
from sys.tables
|
105
|
+
inner join sys.schemas on tables.schema_id = schemas.schema_id
|
106
|
+
where
|
107
|
+
tables.name = '#{table}'
|
108
|
+
and schemas.name = '#{schema}')
|
109
|
+
create table #{schema}.#{table} (#{columns_def})
|
110
|
+
SQL
|
111
|
+
end
|
67
112
|
private
|
68
113
|
|
69
114
|
def connect
|
70
|
-
print "connecting to #{@params[:host]} "
|
115
|
+
#print "connecting to #{@params[:host]} "
|
71
116
|
@connection = TinyTds::Client.new(@params)
|
72
|
-
print "successful\n"
|
117
|
+
#print "successful\n"
|
73
118
|
rescue TinyTds::Error => e
|
74
|
-
|
75
|
-
|
119
|
+
raise unless @params[:mirror_host]
|
120
|
+
#print "#{e.to_s}\n"
|
76
121
|
to_mirror
|
77
122
|
connect
|
78
123
|
end
|
@@ -89,10 +134,10 @@ module Minus5
|
|
89
134
|
# Returns array of table column names or stored procedure param
|
90
135
|
def get_params(name)
|
91
136
|
@params_cache[name] ||=
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
137
|
+
begin
|
138
|
+
sql = "select name from sys.syscolumns where id = object_id('#{name}')"
|
139
|
+
@connection.execute(sql).each.map{|row| row["name"]}
|
140
|
+
end
|
96
141
|
end
|
97
142
|
|
98
143
|
def hash_to_values(columns, data)
|
@@ -129,4 +174,4 @@ module Minus5
|
|
129
174
|
|
130
175
|
end
|
131
176
|
|
132
|
-
end
|
177
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
|
6
|
+
require 'minus5_mssql.rb'
|
7
|
+
|
8
|
+
module Helper
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def setup_table(adapter)
|
13
|
+
adapter.execute "
|
14
|
+
if not exists(select * from sys.objects where name = 'people')
|
15
|
+
create table people (id int identity, first_name varchar(255), last_name varchar(255))
|
16
|
+
"
|
17
|
+
adapter.execute "truncate table people"
|
18
|
+
adapter.execute "insert into people (first_name, last_name) values ('Sasa', 'Juric')"
|
19
|
+
adapter.execute "insert into people (first_name, last_name) values ('Goran', 'Pizent')"
|
20
|
+
end
|
21
|
+
|
22
|
+
def rollback_transaction(client)
|
23
|
+
client.execute("BEGIN TRANSACTION").do
|
24
|
+
yield
|
25
|
+
ensure
|
26
|
+
client.execute("ROLLBACK TRANSACTION").do
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/test/test_select.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
require 'helper.rb'
|
3
|
+
|
4
|
+
class Select < Test::Unit::TestCase
|
5
|
+
include Helper
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@reader = Minus5::Mssql::Adapter.new({:username => "rails",
|
9
|
+
:password => "",
|
10
|
+
:host => "mssql",
|
11
|
+
:database => "minus5_mssql_tests"})
|
12
|
+
create_tables
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_select_value
|
16
|
+
assert_equal 1, @reader.select_value("select 1")
|
17
|
+
assert_equal 1, @reader.select_value("select 1, 2")
|
18
|
+
assert_equal 1, @reader.select_value("select 1\nunion\nselect 2")
|
19
|
+
assert_equal 1, @reader.select_value("select 1; select 2")
|
20
|
+
assert_nil @reader.select_value("set nocount on")
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_select_values
|
24
|
+
assert_equal [1,2], @reader.select_values("select 1, 11\nunion\nselect 2, 22")
|
25
|
+
assert_equal [1,2], @reader.select_values("select 1, 11\nunion\nselect 2, 22; select 3, 3")
|
26
|
+
assert_equal [], @reader.select_values("set nocount on")
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_select_simple
|
30
|
+
assert_equal([{:first => 1, :second => 2}], @reader.select("select 1 first, 2 second"))
|
31
|
+
assert_equal([{:first => 1, :second => 2}], @reader.select(:sql=>"select 1 first, 2 second"))
|
32
|
+
assert_equal [], @reader.select("set nocount on")
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_get_params
|
36
|
+
columns = @reader.send(:get_params, 'people')
|
37
|
+
assert_equal 3, columns.size
|
38
|
+
assert columns.include?("id")
|
39
|
+
assert columns.include?("first_name")
|
40
|
+
assert columns.include?("last_name")
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_insert_delete
|
44
|
+
id = @reader.insert('people', {:first_name => "Igor", :last_name => "Anic"})
|
45
|
+
assert_equal 3, @reader.select_value("select count(*) from people")
|
46
|
+
@reader.delete('people', {:id => id})
|
47
|
+
assert_equal 2, @reader.select_value("select count(*) from people")
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def test_simple_select
|
52
|
+
result = @reader.select("select * from orders")
|
53
|
+
assert result.kind_of?(Array)
|
54
|
+
assert_equal 3, result.size
|
55
|
+
assert_equal 3, result[0].keys.size
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_parent_child_one_to_many_and_one_to_one
|
59
|
+
result = @reader.select(
|
60
|
+
:sql=>"select * from orders; select * from order_details order by no; select order_id, sum(no) sum_no from order_details group by order_id",
|
61
|
+
:primary_key=>:id,
|
62
|
+
:relations=>[{:type=>:one_to_many, :name=>:order_details, :foreign_key=>:order_id},
|
63
|
+
{:type=>:one_to_one, :foreign_key=>:order_id}]
|
64
|
+
)
|
65
|
+
assert result.kind_of?(Array)
|
66
|
+
assert_equal 3, result.size
|
67
|
+
assert_equal 5, result[0].keys.size
|
68
|
+
3.times do |i|
|
69
|
+
parent = result[i]
|
70
|
+
childs = parent[:order_details]
|
71
|
+
assert childs.kind_of?(Array)
|
72
|
+
assert_equal 5, childs.size
|
73
|
+
childs.each_with_index do |child, j|
|
74
|
+
assert_equal i+1, child[:order_id]
|
75
|
+
assert_equal j, child[:no]
|
76
|
+
end
|
77
|
+
assert_not_nil parent[:sum_no]
|
78
|
+
end
|
79
|
+
#pp result
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_one_to_one
|
83
|
+
result = @reader.select(
|
84
|
+
:sql=>"select * from orders; select order_id, sum(no) sum_no from order_details group by order_id",
|
85
|
+
:primary_key=>:id,
|
86
|
+
:relations=>[{:type=>:one_to_one, :name=>:sum, :foreign_key=>:order_id}]
|
87
|
+
)
|
88
|
+
#pp result
|
89
|
+
assert_equal 4, result[0].keys.size
|
90
|
+
assert result[0][:sum].kind_of?(Hash)
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def create_tables
|
96
|
+
@reader.create_table "dbo", "people",
|
97
|
+
"id int identity, first_name varchar(255), last_name varchar(255)"
|
98
|
+
@reader.execute "truncate table dbo.people"
|
99
|
+
@reader.insert "dbo.people", {:first_name=>"Sasa", :last_name=>"Juric"}
|
100
|
+
@reader.insert "dbo.people", {:first_name=>"Goran", :last_name=>"Pizent"}
|
101
|
+
|
102
|
+
@reader.create_table "dbo", "orders",
|
103
|
+
"id int identity, created datetime, amount money"
|
104
|
+
@reader.create_table "dbo", "order_details",
|
105
|
+
"id int identity, order_id int, no int"
|
106
|
+
@reader.execute "truncate table dbo.orders"
|
107
|
+
@reader.execute "truncate table dbo.order_details"
|
108
|
+
3.times do |o|
|
109
|
+
id = @reader.insert "orders", {:created=>Time.now, :amount=>1234.5 * (o + 1)}
|
110
|
+
5.times{|no| @reader.insert "order_details", {:order_id=>id, :no=>no}}
|
111
|
+
end
|
112
|
+
@reader.execute "drop procedure all_orders"
|
113
|
+
@reader.execute <<-SQL
|
114
|
+
create procedure all_orders as
|
115
|
+
select * from orders
|
116
|
+
select order_id parent_id, * from order_details
|
117
|
+
SQL
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minus5_mssql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Igor Anic
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05
|
18
|
+
date: 2011-07-05 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -45,7 +45,9 @@ extra_rdoc_files: []
|
|
45
45
|
files:
|
46
46
|
- lib/minus5_mssql.rb
|
47
47
|
- lib/minus5_mssql/adapter.rb
|
48
|
+
- test/helper.rb
|
48
49
|
- test/test_db_mirroring.rb
|
50
|
+
- test/test_select.rb
|
49
51
|
- Rakefile
|
50
52
|
has_rdoc: true
|
51
53
|
homepage: http://www.minus5.hr
|