minus5_mssql 0.1.0 → 0.2.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/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
|