cassandra-cql 1.0.1
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.
- 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
|