crate_ruby 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +21 -8
- data/lib/crate_ruby.rb +1 -1
- data/lib/crate_ruby/client.rb +42 -12
- data/lib/crate_ruby/result_set.rb +6 -2
- data/lib/crate_ruby/version.rb +1 -1
- data/spec/crate_ruby/client_spec.rb +66 -23
- data/spec/crate_ruby/result_set_spec.rb +6 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/test_server.rb +70 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a726eb5a922ba00e842ae5128897f44ebc348ed
|
4
|
+
data.tar.gz: 0d3d601ffb7c5bbecfd3c6f80a55905b434559e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a55318fc2253b2244ffe7ec3fa88496903ed9f42171b7b1b036f002ffd69e3e7781836678e5e7a1362cc2f20e79c44e3f2c6b69c5dbf5114ec26eade980c578
|
7
|
+
data.tar.gz: b09c8a6e7d4449746105721e8cc3903f7c18cd2231f2359c5e749cdc43f3af5c5c01a3197356d8e04d14c060b20ec2b6bc550ee912c32c723f8590e5650768e8
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# CrateRuby
|
2
2
|
|
3
|
-
Official
|
3
|
+
Official Ruby library to access a [Crate](http://crate.io) database.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -8,10 +8,6 @@ Add this line to your application's Gemfile:
|
|
8
8
|
|
9
9
|
gem 'crate_ruby'
|
10
10
|
|
11
|
-
And then execute:
|
12
|
-
|
13
|
-
$ bundle
|
14
|
-
|
15
11
|
Or install it yourself as:
|
16
12
|
|
17
13
|
$ gem install crate_ruby
|
@@ -21,13 +17,15 @@ Or install it yourself as:
|
|
21
17
|
### Issueing SQL statements
|
22
18
|
require 'crate_ruby'
|
23
19
|
|
24
|
-
# optional args :host, :port, :logger
|
25
20
|
client = CrateRuby::Client.new
|
21
|
+
|
26
22
|
result = client.execute("Select * from posts")
|
27
23
|
=> #<CrateRuby::ResultSet:0x00000002a9c5e8 @rowcount=1, @duration=5>
|
24
|
+
|
28
25
|
result.each do |row|
|
29
|
-
puts row.inspect
|
26
|
+
puts row.inspect
|
30
27
|
end
|
28
|
+
=> [1, "test", 5]
|
31
29
|
|
32
30
|
result.cols
|
33
31
|
=> ["id", "my_column", "my_integer_col"]
|
@@ -48,11 +46,26 @@ Or install it yourself as:
|
|
48
46
|
#deletion
|
49
47
|
client.blob_delete(table_name, digest)
|
50
48
|
|
49
|
+
## Tests
|
50
|
+
|
51
|
+
To run the tests start up the crate server first
|
52
|
+
|
53
|
+
ruby spec/test_server.rb
|
54
|
+
|
51
55
|
## Contributing
|
52
56
|
|
53
|
-
1. Fork it ( http://github.com
|
57
|
+
1. Fork it ( `http://github.com/crate /crate_ruby/fork` )
|
54
58
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
55
59
|
3. Add some tests
|
56
60
|
4. Commit your changes (`git commit -am 'Add some feature'`)
|
57
61
|
5. Push to the branch (`git push origin my-new-feature`)
|
58
62
|
6. Create new Pull Request
|
63
|
+
|
64
|
+
##Maintainer
|
65
|
+
|
66
|
+
* [Christoph Klocker](http://www.vedanova.com), [@corck](http://www.twitter.com/corck)
|
67
|
+
|
68
|
+
##License
|
69
|
+
|
70
|
+
MIT License. Copyright 2014 Vedanova. [http://vedanova.com](http://vedanova.com)
|
71
|
+
|
data/lib/crate_ruby.rb
CHANGED
data/lib/crate_ruby/client.rb
CHANGED
@@ -11,6 +11,7 @@ module CrateRuby
|
|
11
11
|
# @param [Array] servers An Array of servers including ports [127.0.0.1:4200, 10.0.0.1:4201]
|
12
12
|
# @param [opts] Optional paramters
|
13
13
|
# * logger: Custom Logger
|
14
|
+
# @return [CrateRuby::Client]
|
14
15
|
def initialize(servers = [], opts = {})
|
15
16
|
@servers = servers
|
16
17
|
@servers << "#{DEFAULT_HOST}:#{DEFAULT_PORT}" if servers.empty?
|
@@ -18,7 +19,7 @@ module CrateRuby
|
|
18
19
|
end
|
19
20
|
|
20
21
|
def inspect
|
21
|
-
%Q{#<CrateRuby::Client:#{object_id}
|
22
|
+
%Q{#<CrateRuby::Client:#{object_id}>}
|
22
23
|
end
|
23
24
|
|
24
25
|
# Creates a table
|
@@ -26,7 +27,7 @@ module CrateRuby
|
|
26
27
|
# @param [String] table_name
|
27
28
|
# @param [Hash] column_definition
|
28
29
|
# @option column_definition [String] key sets column name, value sets column type. an array passed as value can be used to set options like primary keys
|
29
|
-
# @return [
|
30
|
+
# @return [ResultSet]
|
30
31
|
#
|
31
32
|
def create_table(table_name, column_definition = {}, blob=false)
|
32
33
|
cols = column_definition.to_a.map { |a| a.join(' ') }.join(', ')
|
@@ -38,7 +39,7 @@ module CrateRuby
|
|
38
39
|
# @param [String] name Table name
|
39
40
|
# @param [Integer] shard Shard count, defaults to 5
|
40
41
|
# @param [Integer] number Number of replicas, defaults to 0
|
41
|
-
# @return [
|
42
|
+
# @return [ResultSet]
|
42
43
|
#
|
43
44
|
# client.create_blob_table("blob_table")
|
44
45
|
def create_blob_table(name, shard_count=5, replicas=0)
|
@@ -49,7 +50,7 @@ module CrateRuby
|
|
49
50
|
# Drop table
|
50
51
|
# @param [String] table_name, Name of table to drop
|
51
52
|
# @param [Boolean] blob Needs to be set to true if table is a blob table
|
52
|
-
# @return [
|
53
|
+
# @return [ResultSet]
|
53
54
|
def drop_table(table_name, blob=false)
|
54
55
|
tbl = blob ? "BLOB TABLE" : "TABLE"
|
55
56
|
stmt = %Q{DROP #{tbl} "#{table_name}"}
|
@@ -59,25 +60,30 @@ module CrateRuby
|
|
59
60
|
# List all user tables
|
60
61
|
# @return [ResultSet]
|
61
62
|
def show_tables
|
62
|
-
execute("select
|
63
|
+
execute("select table_name from information_schema.tables where schema_name = 'doc'")
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns all tables in schema 'doc'
|
67
|
+
# @return [Array] Array of table names
|
68
|
+
def tables
|
69
|
+
execute("select table_name from information_schema.tables where schema_name = 'doc'").map(&:first)
|
63
70
|
end
|
64
71
|
|
65
72
|
# Executes a SQL statement against the Crate HTTP REST endpoint.
|
66
73
|
# @param [String] sql statement to execute
|
67
|
-
# @return [ResultSet
|
74
|
+
# @return [ResultSet]
|
68
75
|
def execute(sql)
|
76
|
+
@logger.debug sql
|
69
77
|
req = Net::HTTP::Post.new("/_sql", initheader = {'Content-Type' => 'application/json'})
|
70
78
|
req.body = {"stmt" => sql}.to_json
|
71
79
|
response = request(req)
|
80
|
+
@logger.debug response.body
|
72
81
|
success = case response.code
|
73
|
-
when
|
82
|
+
when /^2\d{2}/
|
74
83
|
ResultSet.new response.body
|
75
|
-
when "400"
|
76
|
-
@logger.info(response.body)
|
77
|
-
false
|
78
84
|
else
|
79
85
|
@logger.info(response.body)
|
80
|
-
|
86
|
+
raise CrateRuby::CrateError.new(response.body)
|
81
87
|
end
|
82
88
|
success
|
83
89
|
end
|
@@ -141,6 +147,30 @@ module CrateRuby
|
|
141
147
|
success
|
142
148
|
end
|
143
149
|
|
150
|
+
|
151
|
+
# Return the table structure
|
152
|
+
# @param [String] table_name Table name to get structure
|
153
|
+
# @param [ResultSet]
|
154
|
+
def table_structure(table_name)
|
155
|
+
execute("select * from information_schema.columns where schema_name = 'doc' AND table_name = '#{table_name}'")
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
def insert(table_name, attributes)
|
160
|
+
vals = attributes.values.map { |x| x.is_a?(String) ? "'#{x}'" : x }.join(', ')
|
161
|
+
stmt = %Q{INSERT INTO "#{table_name}" (#{attributes.keys.join(', ')}) VALUES (#{vals})}
|
162
|
+
execute(stmt)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Crate is eventually consistent, If you don't query by primary key,
|
166
|
+
# it is not guaranteed that an insert record is found on the next
|
167
|
+
# query. Default refresh value is 1000ms.
|
168
|
+
# Using refresh_table you can force a refresh
|
169
|
+
# @param [String] table_name Name of table to refresh
|
170
|
+
def refresh_table(table_name)
|
171
|
+
execute "refresh table #{table_name}"
|
172
|
+
end
|
173
|
+
|
144
174
|
private
|
145
175
|
|
146
176
|
def blob_path(table, digest)
|
@@ -151,7 +181,7 @@ module CrateRuby
|
|
151
181
|
host, port = @servers.first.split(':');
|
152
182
|
Net::HTTP.new(host, port)
|
153
183
|
end
|
154
|
-
|
184
|
+
|
155
185
|
def request(req)
|
156
186
|
connection.start { |http| http.request(req) }
|
157
187
|
end
|
@@ -4,7 +4,7 @@ module CrateRuby
|
|
4
4
|
|
5
5
|
attr_reader :rowcount, :duration, :cols
|
6
6
|
|
7
|
-
# @param [String]
|
7
|
+
# @param [String] result
|
8
8
|
def initialize(result)
|
9
9
|
result = JSON.parse(result)
|
10
10
|
@cols = result['cols']
|
@@ -23,13 +23,17 @@ module CrateRuby
|
|
23
23
|
|
24
24
|
def each(&block)
|
25
25
|
@rows.each(&block)
|
26
|
-
nil
|
27
26
|
end
|
28
27
|
|
29
28
|
def [](val)
|
30
29
|
@rows[val]
|
31
30
|
end
|
32
31
|
|
32
|
+
# @return [Array] Returns all rows as Array of arrays
|
33
|
+
def values
|
34
|
+
@rows
|
35
|
+
end
|
36
|
+
|
33
37
|
# @param [Array] ary Column names to filer on
|
34
38
|
# @return [Array] Filtered rows
|
35
39
|
def select_columns(ary, &block)
|
data/lib/crate_ruby/version.rb
CHANGED
@@ -1,47 +1,46 @@
|
|
1
1
|
require_relative '../spec_helper'
|
2
2
|
|
3
3
|
describe CrateRuby::Client do
|
4
|
+
TABLE_NAME = 'blob_table'
|
4
5
|
describe '#create_table' do
|
5
|
-
let(:client) { CrateRuby::Client.new }
|
6
|
+
let(:client) { CrateRuby::Client.new(["localhost:#{TEST_PORT}"]) }
|
6
7
|
|
7
|
-
describe 'blob
|
8
|
-
let(:table_name) { 'blob_table' }
|
8
|
+
describe 'blob management' do
|
9
9
|
let(:file) { 'logo-crate.png' }
|
10
|
-
#let(:file) { 'text.txt' }
|
11
10
|
let(:path) { File.join(File.dirname(__FILE__), '../uploads/') }
|
12
11
|
let(:file_path) { File.join(path, file) }
|
13
12
|
let(:digest) { Digest::SHA1.file(file_path).hexdigest }
|
14
13
|
let(:store_location) { File.join(path, "get_#{file}") }
|
15
14
|
|
16
|
-
before do
|
17
|
-
|
15
|
+
before(:all) do
|
16
|
+
CrateRuby::Client.new(["localhost:#{TEST_PORT}"]).execute("create blob TABLE #{TABLE_NAME}")
|
18
17
|
end
|
19
18
|
|
20
|
-
after do
|
21
|
-
|
19
|
+
after(:all) do
|
20
|
+
CrateRuby::Client.new(["localhost:#{TEST_PORT}"]).execute("drop blob TABLE #{TABLE_NAME}")
|
22
21
|
end
|
23
22
|
|
24
23
|
describe '#blob_put' do
|
25
24
|
|
26
25
|
after do
|
27
|
-
client.blob_delete(
|
26
|
+
client.blob_delete(TABLE_NAME, digest)
|
28
27
|
end
|
29
28
|
|
30
29
|
context 'file' do
|
31
30
|
|
32
31
|
it 'should upload a file to the blob table' do
|
33
32
|
f = File.read(file_path)
|
34
|
-
client.blob_put(
|
33
|
+
client.blob_put(TABLE_NAME, digest, f).should be_true
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
37
|
context '#string' do
|
39
|
-
let(:string) {"my crazy"}
|
40
|
-
let(:digest) {Digest::SHA1.hexdigest(string)}
|
38
|
+
let(:string) { "my crazy" }
|
39
|
+
let(:digest) { Digest::SHA1.hexdigest(string) }
|
41
40
|
|
42
41
|
it 'should upload a string to the blob table' do
|
43
|
-
client.blob_delete(
|
44
|
-
client.blob_put
|
42
|
+
client.blob_delete(TABLE_NAME, digest)
|
43
|
+
client.blob_put TABLE_NAME, digest, string
|
45
44
|
end
|
46
45
|
end
|
47
46
|
end
|
@@ -50,11 +49,11 @@ describe CrateRuby::Client do
|
|
50
49
|
|
51
50
|
before do
|
52
51
|
f = File.read(file_path)
|
53
|
-
client.blob_put(
|
52
|
+
client.blob_put(TABLE_NAME, digest, f)
|
54
53
|
end
|
55
54
|
|
56
55
|
it 'should download a blob' do
|
57
|
-
data = client.blob_get(
|
56
|
+
data = client.blob_get(TABLE_NAME, digest)
|
58
57
|
data.should_not be_false
|
59
58
|
open(store_location, "wb") { |file|
|
60
59
|
file.write(data)
|
@@ -62,31 +61,31 @@ describe CrateRuby::Client do
|
|
62
61
|
end
|
63
62
|
|
64
63
|
after do
|
65
|
-
client.blob_delete(
|
64
|
+
client.blob_delete(TABLE_NAME, digest)
|
66
65
|
end
|
67
66
|
end
|
68
67
|
|
69
68
|
describe '#blob_delete' do
|
70
69
|
before do
|
71
70
|
f = File.read(file_path)
|
72
|
-
client.blob_put(
|
71
|
+
client.blob_put(TABLE_NAME, digest, f)
|
73
72
|
end
|
74
73
|
|
75
74
|
it 'should delete a blob' do
|
76
|
-
client.blob_delete(
|
75
|
+
client.blob_delete(TABLE_NAME, digest)
|
77
76
|
end
|
78
77
|
end
|
79
78
|
end
|
80
79
|
|
81
80
|
describe '#execute' do
|
82
|
-
let(:
|
81
|
+
let(:TABLE_NAME) { "post" }
|
83
82
|
|
84
83
|
after do
|
85
|
-
client.execute("drop TABLE #{
|
84
|
+
client.execute("drop TABLE #{TABLE_NAME}").should be_true
|
86
85
|
end
|
87
86
|
|
88
87
|
it 'should create a new table' do
|
89
|
-
client.execute("CREATE TABLE #{
|
88
|
+
client.execute("CREATE TABLE #{TABLE_NAME} (id int)").should be_true
|
90
89
|
end
|
91
90
|
|
92
91
|
end
|
@@ -96,10 +95,54 @@ describe CrateRuby::Client do
|
|
96
95
|
|
97
96
|
it 'should use host and ports parameters' do
|
98
97
|
logger = double()
|
99
|
-
client = CrateRuby::Client.new ["10.0.0.1:5000"],logger: logger
|
98
|
+
client = CrateRuby::Client.new ["10.0.0.1:5000"], logger: logger
|
100
99
|
client.instance_variable_get(:@servers).should eq(["10.0.0.1:5000"])
|
101
100
|
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#tables' do
|
104
|
+
before do
|
105
|
+
client.create_table "posts", id: :integer
|
106
|
+
client.create_table "comments", id: :integer
|
107
|
+
end
|
108
|
+
|
109
|
+
after do
|
110
|
+
client.drop_table "posts"
|
111
|
+
client.drop_table "comments"
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should return all user tables as an array of string values' do
|
115
|
+
client.tables.should eq ['posts', 'comments']
|
116
|
+
end
|
117
|
+
end
|
102
118
|
|
119
|
+
|
120
|
+
describe '#insert' do
|
121
|
+
before do
|
122
|
+
client.create_table("posts", id: [:string, "primary key"],
|
123
|
+
title: :string,
|
124
|
+
views: :integer)
|
125
|
+
end
|
126
|
+
|
127
|
+
after do
|
128
|
+
client.drop_table "posts"
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should insert the record' do
|
132
|
+
expect do
|
133
|
+
client.insert('posts', id: SecureRandom.uuid, title: "Test" )
|
134
|
+
sleep(1)
|
135
|
+
result_set = client.execute("Select * from posts where title = 'Test'")
|
136
|
+
result_set.rowcount.should eq 1
|
137
|
+
end.not_to raise_exception
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#refresh table' do
|
142
|
+
it 'should issue the proper refresh statment' do
|
143
|
+
client.should_receive(:execute).with("refresh table posts")
|
144
|
+
client.refresh_table('posts')
|
145
|
+
end
|
103
146
|
end
|
104
147
|
|
105
148
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/test_server.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
class TestServer
|
3
|
+
CRATE_PATH = "~/crate"
|
4
|
+
TEST_PORT = 4209
|
5
|
+
NAME = "TestCluster"
|
6
|
+
|
7
|
+
|
8
|
+
def initialize(crate_home = nil, port = nil, host = "127.0.0.1")
|
9
|
+
@crate_home = crate_home || CRATE_PATH
|
10
|
+
@port = port || TEST_PORT
|
11
|
+
@host = host
|
12
|
+
end
|
13
|
+
|
14
|
+
def start
|
15
|
+
cmd = "sh #{CRATE_PATH}/bin/crate #{start_params}"
|
16
|
+
@pid = spawn(cmd, :out => "/tmp/crate_test_server.out", :err => "/tmp/crate_test_server.err")
|
17
|
+
Process.detach(@pid)
|
18
|
+
puts 'starting'
|
19
|
+
time_slept = 0
|
20
|
+
while true
|
21
|
+
puts "Crate not yet fully available. Waiting since #{time_slept} seconds..." unless alive?
|
22
|
+
sleep(2)
|
23
|
+
time_slept += 2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def stop
|
28
|
+
Process.kill("HUP", @pid)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
|
34
|
+
def crate_exec
|
35
|
+
end
|
36
|
+
|
37
|
+
def crate_config
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_params
|
41
|
+
"-Des.index.storage.type=memory " +
|
42
|
+
"-Des.node.name=#{NAME} " +
|
43
|
+
"-Des.cluster.name=Testing#{@port} " +
|
44
|
+
"-Des.http.port=#{@port}-#{@port} " +
|
45
|
+
"-Des.network.host=localhost " +
|
46
|
+
"-Des.discovery.type=zen " +
|
47
|
+
"-Des.discovery.zen.ping.multicast.enabled=false"
|
48
|
+
end
|
49
|
+
|
50
|
+
def alive?
|
51
|
+
req = Net::HTTP::Get.new('/')
|
52
|
+
resp = Net::HTTP.new(@host, @port)
|
53
|
+
begin
|
54
|
+
response = resp.start { |http| http.request(req) }
|
55
|
+
response.code == "200" ? true : false
|
56
|
+
rescue Errno::ECONNREFUSED
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
server = TestServer.new.start *ARGV
|
64
|
+
|
65
|
+
trap("INT") do
|
66
|
+
puts "Script terminated by user."
|
67
|
+
server.stop
|
68
|
+
puts "Server stopped"
|
69
|
+
exit
|
70
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crate_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christoph Klocker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- spec/crate_ruby/client_spec.rb
|
75
75
|
- spec/crate_ruby/result_set_spec.rb
|
76
76
|
- spec/spec_helper.rb
|
77
|
+
- spec/test_server.rb
|
77
78
|
- spec/uploads/get_logo-crate.png
|
78
79
|
- spec/uploads/logo-crate.png
|
79
80
|
- spec/uploads/text.txt
|
@@ -105,6 +106,7 @@ test_files:
|
|
105
106
|
- spec/crate_ruby/client_spec.rb
|
106
107
|
- spec/crate_ruby/result_set_spec.rb
|
107
108
|
- spec/spec_helper.rb
|
109
|
+
- spec/test_server.rb
|
108
110
|
- spec/uploads/get_logo-crate.png
|
109
111
|
- spec/uploads/logo-crate.png
|
110
112
|
- spec/uploads/text.txt
|