cassandra-cql 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +203 -0
- data/README.rdoc +78 -0
- data/Rakefile +150 -0
- data/cassandra-cql.gemspec +29 -0
- data/lib/cassandra-cql.rb +39 -0
- data/lib/cassandra-cql/database.rb +107 -0
- data/lib/cassandra-cql/result.rb +133 -0
- data/lib/cassandra-cql/row.rb +59 -0
- data/lib/cassandra-cql/schema.rb +108 -0
- data/lib/cassandra-cql/statement.rb +111 -0
- data/lib/cassandra-cql/types/abstract_type.rb +47 -0
- data/lib/cassandra-cql/types/ascii_type.rb +25 -0
- data/lib/cassandra-cql/types/boolean_type.rb +25 -0
- data/lib/cassandra-cql/types/bytes_type.rb +21 -0
- data/lib/cassandra-cql/types/decimal_type.rb +25 -0
- data/lib/cassandra-cql/types/double_type.rb +25 -0
- data/lib/cassandra-cql/types/float_type.rb +25 -0
- data/lib/cassandra-cql/types/integer_type.rb +27 -0
- data/lib/cassandra-cql/types/long_type.rb +27 -0
- data/lib/cassandra-cql/types/utf8_type.rb +25 -0
- data/lib/cassandra-cql/types/uuid_type.rb +27 -0
- data/lib/cassandra-cql/utility.rb +37 -0
- data/lib/cassandra-cql/uuid.rb +21 -0
- data/lib/cassandra-cql/version.rb +19 -0
- data/spec/column_family_spec.rb +105 -0
- data/spec/comparator_spec.rb +225 -0
- data/spec/conf/0.8/cassandra.in.sh +41 -0
- data/spec/conf/0.8/cassandra.yaml +61 -0
- data/spec/conf/0.8/log4j-server.properties +40 -0
- data/spec/conf/0.8/schema.txt +10 -0
- data/spec/conf/1.0/cassandra.in.sh +41 -0
- data/spec/conf/1.0/cassandra.yaml +416 -0
- data/spec/conf/1.0/log4j-server.properties +40 -0
- data/spec/conf/1.0/schema.txt +10 -0
- data/spec/result_spec.rb +173 -0
- data/spec/row_spec.rb +55 -0
- data/spec/rowkey_spec.rb +223 -0
- data/spec/schema_spec.rb +51 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/statement_spec.rb +224 -0
- data/spec/utility_spec.rb +26 -0
- data/spec/uuid_spec.rb +26 -0
- data/spec/validation_spec.rb +250 -0
- data/vendor/gen-rb/cassandra.rb +2212 -0
- data/vendor/gen-rb/cassandra_constants.rb +10 -0
- data/vendor/gen-rb/cassandra_types.rb +854 -0
- metadata +171 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2011 Inside Systems, Inc.
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
here = File.dirname(__FILE__)
|
18
|
+
require "#{here}/../vendor/gen-rb/cassandra"
|
19
|
+
|
20
|
+
require 'bigdecimal'
|
21
|
+
require 'thrift_client'
|
22
|
+
require 'cassandra-cql/types/abstract_type'
|
23
|
+
require 'cassandra-cql/types/ascii_type'
|
24
|
+
require 'cassandra-cql/types/boolean_type'
|
25
|
+
require 'cassandra-cql/types/bytes_type'
|
26
|
+
require 'cassandra-cql/types/decimal_type'
|
27
|
+
require 'cassandra-cql/types/double_type'
|
28
|
+
require 'cassandra-cql/types/float_type'
|
29
|
+
require 'cassandra-cql/types/integer_type'
|
30
|
+
require 'cassandra-cql/types/long_type'
|
31
|
+
require 'cassandra-cql/types/utf8_type'
|
32
|
+
require 'cassandra-cql/types/uuid_type'
|
33
|
+
require 'cassandra-cql/utility'
|
34
|
+
require 'cassandra-cql/uuid'
|
35
|
+
require 'cassandra-cql/database'
|
36
|
+
require 'cassandra-cql/schema'
|
37
|
+
require 'cassandra-cql/statement'
|
38
|
+
require 'cassandra-cql/result'
|
39
|
+
require 'cassandra-cql/row'
|
@@ -0,0 +1,107 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2011 Inside Systems, Inc.
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
module CassandraCQL
|
18
|
+
module Error
|
19
|
+
class InvalidRequestException < Exception; end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Database
|
23
|
+
attr_reader :connection, :schema, :keyspace
|
24
|
+
|
25
|
+
def initialize(servers, options={}, thrift_client_options={})
|
26
|
+
@options = {
|
27
|
+
:keyspace => 'system'
|
28
|
+
}.merge(options)
|
29
|
+
|
30
|
+
@thrift_client_options = {
|
31
|
+
:exception_class_overrides => CassandraCQL::Thrift::InvalidRequestException
|
32
|
+
}.merge(thrift_client_options)
|
33
|
+
|
34
|
+
@keyspace = @options[:keyspace]
|
35
|
+
@servers = servers
|
36
|
+
connect!
|
37
|
+
execute("USE #{@keyspace}")
|
38
|
+
end
|
39
|
+
|
40
|
+
def connect!
|
41
|
+
@connection = ThriftClient.new(CassandraCQL::Thrift::Client, @servers, @thrift_client_options)
|
42
|
+
obj = self
|
43
|
+
@connection.add_callback(:post_connect) do
|
44
|
+
execute("USE #{@keyspace}")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def disconnect!
|
49
|
+
@connection.disconnect! if active?
|
50
|
+
end
|
51
|
+
|
52
|
+
def active?
|
53
|
+
# TODO: This should be replaced with a CQL call that doesn't exist yet
|
54
|
+
@connection.describe_version
|
55
|
+
true
|
56
|
+
rescue Exception
|
57
|
+
false
|
58
|
+
end
|
59
|
+
alias_method :ping, :active?
|
60
|
+
|
61
|
+
def reset!
|
62
|
+
disconnect!
|
63
|
+
reconnect!
|
64
|
+
end
|
65
|
+
alias_method :reconnect!, :reset!
|
66
|
+
|
67
|
+
def prepare(statement, options={}, &block)
|
68
|
+
stmt = Statement.new(self, statement)
|
69
|
+
if block_given?
|
70
|
+
yield stmt
|
71
|
+
else
|
72
|
+
stmt
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def execute(statement, *bind_vars)
|
77
|
+
result = Statement.new(self, statement).execute(bind_vars)
|
78
|
+
if block_given?
|
79
|
+
yield result
|
80
|
+
else
|
81
|
+
result
|
82
|
+
end
|
83
|
+
rescue CassandraCQL::Thrift::InvalidRequestException
|
84
|
+
raise Error::InvalidRequestException.new($!.why)
|
85
|
+
end
|
86
|
+
|
87
|
+
def execute_cql_query(cql, compression=CassandraCQL::Thrift::Compression::NONE)
|
88
|
+
@connection.execute_cql_query(cql, compression)
|
89
|
+
rescue CassandraCQL::Thrift::InvalidRequestException
|
90
|
+
raise Error::InvalidRequestException.new($!.why)
|
91
|
+
end
|
92
|
+
|
93
|
+
def keyspace=(ks)
|
94
|
+
@keyspace = (ks.nil? ? nil : ks.to_s)
|
95
|
+
end
|
96
|
+
|
97
|
+
def keyspaces
|
98
|
+
# TODO: This should be replaced with a CQL call that doesn't exist yet
|
99
|
+
@connection.describe_keyspaces.map { |keyspace| Schema.new(keyspace) }
|
100
|
+
end
|
101
|
+
|
102
|
+
def schema
|
103
|
+
# TODO: This should be replaced with a CQL call that doesn't exist yet
|
104
|
+
Schema.new(@connection.describe_keyspace(@keyspace))
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2011 Inside Systems, Inc.
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
module CassandraCQL
|
18
|
+
module Error
|
19
|
+
class InvalidResultType < Exception; end
|
20
|
+
class InvalidCursor < Exception; end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ResultSchema
|
24
|
+
attr_reader :names, :values
|
25
|
+
|
26
|
+
def initialize(schema)
|
27
|
+
# When https://issues.apache.org/jira/browse/CASSANDRA-3436 is resolve, no more need to split/last
|
28
|
+
@names = Hash.new(schema.default_name_type.split(".").last)
|
29
|
+
schema.name_types.each_pair { |key, type|
|
30
|
+
@names[key] = type.split(".").last
|
31
|
+
}
|
32
|
+
@values = Hash.new(schema.default_value_type.split(".").last)
|
33
|
+
schema.value_types.each_pair { |key, type|
|
34
|
+
@values[key] = type.split(".").last
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Result
|
40
|
+
attr_reader :result, :schema, :cursor
|
41
|
+
|
42
|
+
def initialize(result)
|
43
|
+
@result = result
|
44
|
+
@schema = ResultSchema.new(result.schema) if rows?
|
45
|
+
@cursor = 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def void?
|
49
|
+
@result.type == CassandraCQL::Thrift::CqlResultType::VOID
|
50
|
+
end
|
51
|
+
|
52
|
+
def int?
|
53
|
+
@result.type == CassandraCQL::Thrift::CqlResultType::INT
|
54
|
+
end
|
55
|
+
|
56
|
+
def rows?
|
57
|
+
@result.type == CassandraCQL::Thrift::CqlResultType::ROWS
|
58
|
+
end
|
59
|
+
|
60
|
+
def rows
|
61
|
+
@result.rows.size
|
62
|
+
end
|
63
|
+
|
64
|
+
def cursor=(cursor)
|
65
|
+
@cursor = cursor.to_i
|
66
|
+
rescue Exception => e
|
67
|
+
raise Error::InvalidCursor, e.to_s
|
68
|
+
end
|
69
|
+
|
70
|
+
def fetch_row
|
71
|
+
case @result.type
|
72
|
+
when CassandraCQL::Thrift::CqlResultType::ROWS
|
73
|
+
return nil if @cursor >= rows
|
74
|
+
|
75
|
+
row = Row.new(@result.rows[@cursor], @schema)
|
76
|
+
@cursor += 1
|
77
|
+
return row
|
78
|
+
when CassandraCQL::Thrift::CqlResultType::VOID
|
79
|
+
return nil
|
80
|
+
when CassandraCQL::Thrift::CqlResultType::INT
|
81
|
+
return @result.num
|
82
|
+
else
|
83
|
+
raise Error::InvalidResultType, "Expects one of 0, 1, 2; was #{@result.type} "
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def fetch
|
88
|
+
if block_given?
|
89
|
+
while row = fetch_row
|
90
|
+
yield row
|
91
|
+
end
|
92
|
+
else
|
93
|
+
fetch_row
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def fetch_hash
|
98
|
+
if block_given?
|
99
|
+
while row = fetch_row
|
100
|
+
if row.kind_of?(Fixnum)
|
101
|
+
yield({row => row})
|
102
|
+
else
|
103
|
+
yield row.to_hash
|
104
|
+
end
|
105
|
+
end
|
106
|
+
else
|
107
|
+
if (row = fetch_row).kind_of?(Fixnum)
|
108
|
+
{row => row}
|
109
|
+
else
|
110
|
+
row.to_hash
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def fetch_array
|
116
|
+
if block_given?
|
117
|
+
while row = fetch_row
|
118
|
+
if row.kind_of?(Fixnum)
|
119
|
+
yield [row]
|
120
|
+
else
|
121
|
+
yield row.to_a
|
122
|
+
end
|
123
|
+
end
|
124
|
+
else
|
125
|
+
if (row = fetch_row).kind_of?(Fixnum)
|
126
|
+
[row]
|
127
|
+
else
|
128
|
+
row.to_a
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2011 Inside Systems, Inc.
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
module CassandraCQL
|
18
|
+
class Row
|
19
|
+
attr_reader :row
|
20
|
+
|
21
|
+
def initialize(row, schema)
|
22
|
+
@row, @schema = row, schema
|
23
|
+
end
|
24
|
+
|
25
|
+
def [](obj)
|
26
|
+
# Rows include the row key so we skip the first one
|
27
|
+
column_index = obj.kind_of?(Fixnum) ? obj : column_names.index(obj)
|
28
|
+
return nil if column_index.nil?
|
29
|
+
column_values[column_index]
|
30
|
+
end
|
31
|
+
|
32
|
+
def column_names
|
33
|
+
@names ||= @row.columns.map do |column|
|
34
|
+
ColumnFamily.cast(column.name, @schema.names[column.name])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def column_values
|
39
|
+
@values ||= @row.columns.map { |column| ColumnFamily.cast(column.value, @schema.values[column.name]) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def columns
|
43
|
+
@row.columns.size
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_a
|
47
|
+
column_values
|
48
|
+
end
|
49
|
+
|
50
|
+
# TODO: This should be an ordered hash
|
51
|
+
def to_hash
|
52
|
+
Hash[([column_names, column_values]).transpose]
|
53
|
+
end
|
54
|
+
|
55
|
+
def key
|
56
|
+
ColumnFamily.cast(@row.key, @schema.values[@row.key])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2011 Inside Systems, Inc.
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
=end
|
16
|
+
|
17
|
+
module CassandraCQL
|
18
|
+
class Schema
|
19
|
+
attr_reader :schema, :column_families
|
20
|
+
|
21
|
+
def initialize(schema)
|
22
|
+
@schema = schema
|
23
|
+
@column_families = {}
|
24
|
+
@schema.cf_defs.each { |cf|
|
25
|
+
@column_families[cf.name] = ColumnFamily.new(cf)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_missing(method, *args, &block)
|
30
|
+
if @schema.respond_to?(method)
|
31
|
+
@schema.send(method)
|
32
|
+
else
|
33
|
+
super(method, *args, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
keyspace
|
39
|
+
end
|
40
|
+
|
41
|
+
def keyspace
|
42
|
+
name
|
43
|
+
end
|
44
|
+
|
45
|
+
def column_family_names
|
46
|
+
@column_families.keys
|
47
|
+
end
|
48
|
+
alias_method :tables, :column_family_names
|
49
|
+
end
|
50
|
+
|
51
|
+
class ColumnFamily
|
52
|
+
attr_reader :cf_def
|
53
|
+
|
54
|
+
def initialize(cf_def)
|
55
|
+
@cf_def = cf_def
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(method, *args, &block)
|
59
|
+
if @cf_def.respond_to?(method)
|
60
|
+
@cf_def.send(method)
|
61
|
+
else
|
62
|
+
super(method, *args, &block)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def columns
|
67
|
+
return @columns if @columns
|
68
|
+
|
69
|
+
@columns = Hash.new(default_validation_class)
|
70
|
+
@cf_def.column_metadata.each do |col|
|
71
|
+
@columns[col.name] = col.validation_class
|
72
|
+
end
|
73
|
+
@columns[key_alias] = key_validation_class
|
74
|
+
|
75
|
+
@columns
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.cast(value, type)
|
79
|
+
return nil if value.nil?
|
80
|
+
|
81
|
+
if CassandraCQL::Types.const_defined?(type)
|
82
|
+
CassandraCQL::Types.const_get(type).cast(value)
|
83
|
+
else
|
84
|
+
CassandraCQL::Types::AbstractType.cast(value)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def name
|
89
|
+
@cf_def.name
|
90
|
+
end
|
91
|
+
|
92
|
+
def type
|
93
|
+
@cf_def.column_type
|
94
|
+
end
|
95
|
+
|
96
|
+
def id
|
97
|
+
@cf_def.id
|
98
|
+
end
|
99
|
+
|
100
|
+
def standard?
|
101
|
+
type == 'Standard'
|
102
|
+
end
|
103
|
+
|
104
|
+
def super?
|
105
|
+
type == 'Super'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|