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.
@@ -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 nil if rows.size == 0
58
- row = rows[0]
59
- row[row.keys[0]]
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(sql)
63
- rows = execute(sql).each
64
- rows.size == 1 ? rows[0] : rows
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
- print "#{e.to_s}\n"
75
- throw unless @params[:mirror_host]
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
- begin
93
- sql = "select name from sys.syscolumns where id = object_id('#{name}')"
94
- @connection.execute(sql).each.map{|row| row["name"]}
95
- end
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
@@ -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: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.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-31 00:00:00 +02:00
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