crate_ruby 0.0.2 → 0.0.4
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.
- 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
|