monetdb 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.rdoc +5 -0
- data/VERSION +1 -1
- data/lib/monetdb/connection.rb +2 -39
- data/lib/monetdb/connection/io.rb +47 -0
- data/lib/monetdb/connection/query.rb +2 -2
- data/lib/monetdb/version.rb +1 -1
- data/test/test_helper/simple_connection.rb +10 -0
- data/test/unit/connection/test_io.rb +86 -0
- data/test/unit/connection/test_query.rb +74 -0
- data/test/unit/test_connection.rb +0 -66
- data/test/unit/test_monetdb.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5ec545e31663df97597447cdbd33b25e2d88c86
|
4
|
+
data.tar.gz: f3bc08654b1fac1b7cc99988e269aa8d3707c412
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab6e208b3f0c3a93de085f7ee71d15277b1615e7cd3b77f722d7cf35f96abb9fcf463083cffa724ec691497cfaf6dd7f91a3553b74bbe3260ca848e876e62781
|
7
|
+
data.tar.gz: e10a8e18b1a99d5fdaff880af3ab7b358a4962a6ffdbc9a179c454901f5b6df9f77cb4327db2756e1daa9cee3848d2fa9e3918f6e9e41085d373ce8ce360acd4
|
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
= MonetDB CHANGELOG
|
2
2
|
|
3
|
+
== Version 0.2.1 (October 13, 2014)
|
4
|
+
|
5
|
+
* Extracted IO related methods to MonetDB::Connection::IO
|
6
|
+
* Fixed bug when parsing rows (excluding "\t]" at end of string)
|
7
|
+
|
3
8
|
== Version 0.2.0 (October 13, 2014)
|
4
9
|
|
5
10
|
* Complete rewrite of the gem (only focussed on querying data using SQL)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/lib/monetdb/connection.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "socket"
|
2
|
+
require "monetdb/connection/io"
|
2
3
|
require "monetdb/connection/messages"
|
3
4
|
require "monetdb/connection/setup"
|
4
5
|
require "monetdb/connection/query"
|
@@ -6,6 +7,7 @@ require "monetdb/connection/query"
|
|
6
7
|
module MonetDB
|
7
8
|
class Connection
|
8
9
|
|
10
|
+
include IO
|
9
11
|
include Messages
|
10
12
|
include Setup
|
11
13
|
include Query
|
@@ -82,44 +84,5 @@ module MonetDB
|
|
82
84
|
MonetDB.logger.send(type, msg) if MonetDB.logger
|
83
85
|
end
|
84
86
|
|
85
|
-
def read
|
86
|
-
raise ConnectionError, "Not connected to server" unless connected?
|
87
|
-
|
88
|
-
length, last_chunk = read_length
|
89
|
-
data, iterations = "", 0
|
90
|
-
|
91
|
-
while (length > 0) && (iterations < 1000) do
|
92
|
-
received = socket.recv(length)
|
93
|
-
data << received
|
94
|
-
length -= received.bytesize
|
95
|
-
iterations += 1
|
96
|
-
end
|
97
|
-
data << read unless last_chunk
|
98
|
-
|
99
|
-
data
|
100
|
-
end
|
101
|
-
|
102
|
-
def read_length
|
103
|
-
bytes = socket.recv(2).unpack("v")[0]
|
104
|
-
[(bytes >> 1), (bytes & 1) == 1]
|
105
|
-
end
|
106
|
-
|
107
|
-
def write(message)
|
108
|
-
raise ConnectionError, "Not connected to server" unless connected?
|
109
|
-
pack(message).each do |chunk|
|
110
|
-
socket.write(chunk)
|
111
|
-
end
|
112
|
-
true
|
113
|
-
end
|
114
|
-
|
115
|
-
def pack(message)
|
116
|
-
chunks = message.scan(/.{1,#{MAX_MSG_SIZE}}/m)
|
117
|
-
chunks.each_with_index.to_a.collect do |chunk, index|
|
118
|
-
last_bit = (index == chunks.size - 1) ? 1 : 0
|
119
|
-
length = [(chunk.size << 1) | last_bit].pack("v")
|
120
|
-
"#{length}#{chunk}"
|
121
|
-
end.freeze
|
122
|
-
end
|
123
|
-
|
124
87
|
end
|
125
88
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module MonetDB
|
2
|
+
class Connection
|
3
|
+
module IO
|
4
|
+
private
|
5
|
+
|
6
|
+
def read
|
7
|
+
raise ConnectionError, "Not connected to server" unless connected?
|
8
|
+
|
9
|
+
length, last_chunk = read_length
|
10
|
+
data, iterations = "", 0
|
11
|
+
|
12
|
+
while (length > 0) && (iterations < 1000) do
|
13
|
+
received = socket.recv(length)
|
14
|
+
data << received
|
15
|
+
length -= received.bytesize
|
16
|
+
iterations += 1
|
17
|
+
end
|
18
|
+
data << read unless last_chunk
|
19
|
+
|
20
|
+
data
|
21
|
+
end
|
22
|
+
|
23
|
+
def read_length
|
24
|
+
bytes = socket.recv(2).unpack("v")[0]
|
25
|
+
[(bytes >> 1), (bytes & 1) == 1]
|
26
|
+
end
|
27
|
+
|
28
|
+
def write(message)
|
29
|
+
raise ConnectionError, "Not connected to server" unless connected?
|
30
|
+
pack(message).each do |chunk|
|
31
|
+
socket.write(chunk)
|
32
|
+
end
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def pack(message)
|
37
|
+
chunks = message.scan(/.{1,#{MAX_MSG_SIZE}}/m)
|
38
|
+
chunks.each_with_index.to_a.collect do |chunk, index|
|
39
|
+
last_bit = (index == chunks.size - 1) ? 1 : 0
|
40
|
+
length = [(chunk.size << 1) | last_bit].pack("v")
|
41
|
+
"#{length}#{chunk}"
|
42
|
+
end.freeze
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -76,7 +76,7 @@ module MonetDB
|
|
76
76
|
|
77
77
|
def parse_rows(table_header, response)
|
78
78
|
column_types = table_header[:column_types]
|
79
|
-
response.split("\t]\n").collect do |row|
|
79
|
+
response.slice(0..-3).split("\t]\n").collect do |row|
|
80
80
|
parsed, values = [], row.slice(1..-1).split(",\t")
|
81
81
|
values.each_with_index do |value, index|
|
82
82
|
parsed << parse_value(column_types[index], value.strip)
|
@@ -101,7 +101,7 @@ module MonetDB
|
|
101
101
|
when :tinyint
|
102
102
|
parse_boolean_value value
|
103
103
|
else
|
104
|
-
raise NotImplementedError, "Cannot parse value of type #{type}"
|
104
|
+
raise NotImplementedError, "Cannot parse value of type #{type.inspect}"
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
data/lib/monetdb/version.rb
CHANGED
@@ -0,0 +1,86 @@
|
|
1
|
+
require_relative "../../test_helper"
|
2
|
+
|
3
|
+
module Unit
|
4
|
+
module Connection
|
5
|
+
class TestIO < MiniTest::Test
|
6
|
+
|
7
|
+
class Connection < SimpleConnection
|
8
|
+
include MonetDB::Connection::Messages
|
9
|
+
include MonetDB::Connection::IO
|
10
|
+
end
|
11
|
+
|
12
|
+
describe MonetDB::Connection::IO do
|
13
|
+
before do
|
14
|
+
@connection = Connection.new
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#read" do
|
18
|
+
describe "when disconnected" do
|
19
|
+
it "raises a connection error" do
|
20
|
+
assert_raises MonetDB::ConnectionError do
|
21
|
+
@connection.send(:read)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "when connected" do
|
27
|
+
it "obtains the block size and reads the server response" do
|
28
|
+
socket = mock
|
29
|
+
@connection.instance_variable_set(:@socket, socket)
|
30
|
+
|
31
|
+
first_chunk = " " * 44
|
32
|
+
last_chunk = " " * 22
|
33
|
+
|
34
|
+
socket.expects(:recv).with(2).returns("\x85\x00")
|
35
|
+
socket.expects(:recv).with(66).returns(first_chunk)
|
36
|
+
socket.expects(:recv).with(22).returns(last_chunk)
|
37
|
+
|
38
|
+
assert_equal first_chunk + last_chunk, @connection.send(:read)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#write" do
|
44
|
+
describe "when disconnected" do
|
45
|
+
it "raises a connection error" do
|
46
|
+
assert_raises MonetDB::ConnectionError do
|
47
|
+
@connection.send(:write, "")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "when connected" do
|
53
|
+
it "writes chunks to the active socket provided with the length header" do
|
54
|
+
socket = mock
|
55
|
+
socket.expects(:write).with("\f\x00Hello")
|
56
|
+
socket.expects(:write).with("\t\x00World!")
|
57
|
+
|
58
|
+
@connection.instance_variable_set(:@socket, socket)
|
59
|
+
@connection.expects(:pack).with("foo bar").returns(["\f\x00Hello", "\t\x00World!"])
|
60
|
+
|
61
|
+
assert_equal true, @connection.send(:write, "foo bar")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#pack" do
|
67
|
+
it "returns chunks provided with a length header" do
|
68
|
+
message = "BIG:monetdb:{MD5}6432e841c9943d524b9b922ee1e5924a:sql:test_drive:"
|
69
|
+
assert_equal ["#{[131].pack("v")}#{message}"], @connection.send(:pack, message)
|
70
|
+
|
71
|
+
message = "hKszBZEmQ1uOPYrpVFEc:merovingian:9:RIPEMD160,SHA256,SHA1,MD5:LIT:SHA512:"
|
72
|
+
assert_equal ["#{[145].pack("v")}#{message}"], @connection.send(:pack, message)
|
73
|
+
|
74
|
+
message.expects(:scan).with(/.{1,#{MonetDB::Connection::MAX_MSG_SIZE}}/m).returns(%w(foobar bazqux paul))
|
75
|
+
assert_equal [
|
76
|
+
"#{[12].pack("v")}foobar",
|
77
|
+
"#{[12].pack("v")}bazqux",
|
78
|
+
"#{[9].pack("v")}paul"
|
79
|
+
], @connection.send(:pack, message)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -14,6 +14,80 @@ module Unit
|
|
14
14
|
@connection = Connection.new
|
15
15
|
end
|
16
16
|
|
17
|
+
describe "#query" do
|
18
|
+
describe "when disconnected" do
|
19
|
+
it "raises a connection error" do
|
20
|
+
assert_raises MonetDB::ConnectionError do
|
21
|
+
@connection.query("")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "when connected" do
|
27
|
+
before do
|
28
|
+
@connection.instance_variable_set(:@socket, mock)
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "when doing a select query" do
|
32
|
+
describe "when returning the correct amount of records" do
|
33
|
+
it "returns the result set" do
|
34
|
+
query = "SELECT * FROM foo_bars"
|
35
|
+
response = <<-RESPONSE
|
36
|
+
&1 0 2 2 2
|
37
|
+
% sys.foo_bars,\tsys.foo_bars # table_name
|
38
|
+
% id,\tname # name
|
39
|
+
% int,\tvarchar # type
|
40
|
+
% 2,\t17 # length
|
41
|
+
[ 1,\t"Paul Engel"\t]
|
42
|
+
[ 2,\t"Ken Adams"\t]
|
43
|
+
RESPONSE
|
44
|
+
|
45
|
+
@connection.expects(:write).with("s#{query};")
|
46
|
+
@connection.expects(:read).returns(response.strip)
|
47
|
+
|
48
|
+
assert_equal [
|
49
|
+
[1, "Paul Engel"],
|
50
|
+
[2, "Ken Adams"]
|
51
|
+
], @connection.query(query)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "when not returning the correct amount of records" do
|
56
|
+
it "raises a query error" do
|
57
|
+
query = "SELECT * FROM foo_bars"
|
58
|
+
response = <<-RESPONSE
|
59
|
+
&1 0 3 2 2
|
60
|
+
% sys.foo_bars,\tsys.foo_bars # table_name
|
61
|
+
% id,\tname # name
|
62
|
+
% int,\tvarchar # type
|
63
|
+
% 2,\t17 # length
|
64
|
+
[ 1,\t"Paul Engel"\t]
|
65
|
+
[ 2,\t"Ken Adams"\t]
|
66
|
+
RESPONSE
|
67
|
+
|
68
|
+
@connection.expects(:write).with("s#{query};")
|
69
|
+
@connection.expects(:read).returns(response.strip)
|
70
|
+
|
71
|
+
assert_raises MonetDB::QueryError do
|
72
|
+
@connection.query(query)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "when doing another query" do
|
79
|
+
it "returns true" do
|
80
|
+
query = "UPDATE foo_bars SET updated_at = NOW()"
|
81
|
+
|
82
|
+
@connection.expects(:write).with("s#{query};")
|
83
|
+
@connection.expects(:read).returns("&2 23 -1")
|
84
|
+
|
85
|
+
assert_equal true, @connection.query(query)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
17
91
|
describe "#extract_headers!" do
|
18
92
|
it "returns an array with delegated return values" do
|
19
93
|
response, foo, bar = mock, mock, mock
|
@@ -106,72 +106,6 @@ module Unit
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
109
|
-
|
110
|
-
describe "#read" do
|
111
|
-
describe "when disconnected" do
|
112
|
-
it "raises a connection error" do
|
113
|
-
assert_raises MonetDB::ConnectionError do
|
114
|
-
@connection.send(:read)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
describe "when connected" do
|
120
|
-
it "obtains the block size and reads the server response" do
|
121
|
-
socket = mock
|
122
|
-
@connection.instance_variable_set(:@socket, socket)
|
123
|
-
|
124
|
-
first_chunk = " " * 44
|
125
|
-
last_chunk = " " * 22
|
126
|
-
|
127
|
-
socket.expects(:recv).with(2).returns("\x85\x00")
|
128
|
-
socket.expects(:recv).with(66).returns(first_chunk)
|
129
|
-
socket.expects(:recv).with(22).returns(last_chunk)
|
130
|
-
|
131
|
-
assert_equal first_chunk + last_chunk, @connection.send(:read)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
describe "#write" do
|
137
|
-
describe "when disconnected" do
|
138
|
-
it "raises a connection error" do
|
139
|
-
assert_raises MonetDB::ConnectionError do
|
140
|
-
@connection.send(:write, "")
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
describe "when connected" do
|
146
|
-
it "writes chunks to the active socket provided with the length header" do
|
147
|
-
socket = mock
|
148
|
-
socket.expects(:write).with("\f\x00Hello")
|
149
|
-
socket.expects(:write).with("\t\x00World!")
|
150
|
-
|
151
|
-
@connection.instance_variable_set(:@socket, socket)
|
152
|
-
@connection.expects(:pack).with("foo bar").returns(["\f\x00Hello", "\t\x00World!"])
|
153
|
-
|
154
|
-
assert_equal true, @connection.send(:write, "foo bar")
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
describe "#pack" do
|
160
|
-
it "returns chunks provided with a length header" do
|
161
|
-
message = "BIG:monetdb:{MD5}6432e841c9943d524b9b922ee1e5924a:sql:test_drive:"
|
162
|
-
assert_equal ["#{[131].pack("v")}#{message}"], @connection.send(:pack, message)
|
163
|
-
|
164
|
-
message = "hKszBZEmQ1uOPYrpVFEc:merovingian:9:RIPEMD160,SHA256,SHA1,MD5:LIT:SHA512:"
|
165
|
-
assert_equal ["#{[145].pack("v")}#{message}"], @connection.send(:pack, message)
|
166
|
-
|
167
|
-
message.expects(:scan).with(/.{1,#{MonetDB::Connection::MAX_MSG_SIZE}}/m).returns(%w(foobar bazqux paul))
|
168
|
-
assert_equal [
|
169
|
-
"#{[12].pack("v")}foobar",
|
170
|
-
"#{[12].pack("v")}bazqux",
|
171
|
-
"#{[9].pack("v")}paul"
|
172
|
-
], @connection.send(:pack, message)
|
173
|
-
end
|
174
|
-
end
|
175
109
|
end
|
176
110
|
|
177
111
|
end
|
data/test/unit/test_monetdb.rb
CHANGED
@@ -7,7 +7,7 @@ module Unit
|
|
7
7
|
it "has the current version" do
|
8
8
|
version = File.read(path("VERSION")).strip
|
9
9
|
assert_equal version, MonetDB::VERSION
|
10
|
-
assert File.read(path "CHANGELOG.rdoc").include?("Version #{version}")
|
10
|
+
assert File.read(path "CHANGELOG.rdoc").include?("Version #{version} ")
|
11
11
|
end
|
12
12
|
|
13
13
|
describe ".logger" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monetdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Engel
|
@@ -125,6 +125,7 @@ files:
|
|
125
125
|
- VERSION
|
126
126
|
- lib/monetdb.rb
|
127
127
|
- lib/monetdb/connection.rb
|
128
|
+
- lib/monetdb/connection/io.rb
|
128
129
|
- lib/monetdb/connection/messages.rb
|
129
130
|
- lib/monetdb/connection/query.rb
|
130
131
|
- lib/monetdb/connection/setup.rb
|
@@ -136,6 +137,7 @@ files:
|
|
136
137
|
- test/test_helper/coverage.rb
|
137
138
|
- test/test_helper/minitest.rb
|
138
139
|
- test/test_helper/simple_connection.rb
|
140
|
+
- test/unit/connection/test_io.rb
|
139
141
|
- test/unit/connection/test_messages.rb
|
140
142
|
- test/unit/connection/test_query.rb
|
141
143
|
- test/unit/connection/test_setup.rb
|
@@ -169,6 +171,7 @@ test_files:
|
|
169
171
|
- test/test_helper/coverage.rb
|
170
172
|
- test/test_helper/minitest.rb
|
171
173
|
- test/test_helper/simple_connection.rb
|
174
|
+
- test/unit/connection/test_io.rb
|
172
175
|
- test/unit/connection/test_messages.rb
|
173
176
|
- test/unit/connection/test_query.rb
|
174
177
|
- test/unit/connection/test_setup.rb
|