hallelujah-cassandra-cql 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.gitignore +9 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +203 -0
  4. data/README.rdoc +71 -0
  5. data/Rakefile +151 -0
  6. data/hallelujah-cassandra-cql.gemspec +33 -0
  7. data/lib/cassandra-cql.rb +49 -0
  8. data/lib/cassandra-cql/0.8.rb +7 -0
  9. data/lib/cassandra-cql/0.8/result.rb +23 -0
  10. data/lib/cassandra-cql/0.8/statement.rb +38 -0
  11. data/lib/cassandra-cql/1.0.rb +7 -0
  12. data/lib/cassandra-cql/1.0/result.rb +6 -0
  13. data/lib/cassandra-cql/1.0/statement.rb +6 -0
  14. data/lib/cassandra-cql/1.1.rb +7 -0
  15. data/lib/cassandra-cql/1.1/result.rb +6 -0
  16. data/lib/cassandra-cql/1.1/statement.rb +6 -0
  17. data/lib/cassandra-cql/database.rb +127 -0
  18. data/lib/cassandra-cql/result.rb +133 -0
  19. data/lib/cassandra-cql/row.rb +54 -0
  20. data/lib/cassandra-cql/schema.rb +108 -0
  21. data/lib/cassandra-cql/statement.rb +116 -0
  22. data/lib/cassandra-cql/types/abstract_type.rb +47 -0
  23. data/lib/cassandra-cql/types/ascii_type.rb +25 -0
  24. data/lib/cassandra-cql/types/boolean_type.rb +25 -0
  25. data/lib/cassandra-cql/types/bytes_type.rb +21 -0
  26. data/lib/cassandra-cql/types/date_type.rb +25 -0
  27. data/lib/cassandra-cql/types/decimal_type.rb +25 -0
  28. data/lib/cassandra-cql/types/double_type.rb +25 -0
  29. data/lib/cassandra-cql/types/float_type.rb +25 -0
  30. data/lib/cassandra-cql/types/integer_type.rb +27 -0
  31. data/lib/cassandra-cql/types/long_type.rb +27 -0
  32. data/lib/cassandra-cql/types/utf8_type.rb +25 -0
  33. data/lib/cassandra-cql/types/uuid_type.rb +27 -0
  34. data/lib/cassandra-cql/utility.rb +37 -0
  35. data/lib/cassandra-cql/uuid.rb +21 -0
  36. data/lib/cassandra-cql/version.rb +19 -0
  37. data/spec/column_family_spec.rb +105 -0
  38. data/spec/comparator_spec.rb +249 -0
  39. data/spec/conf/0.8/cassandra.in.sh +41 -0
  40. data/spec/conf/0.8/cassandra.yaml +61 -0
  41. data/spec/conf/0.8/log4j-server.properties +40 -0
  42. data/spec/conf/0.8/schema.txt +10 -0
  43. data/spec/conf/1.0/cassandra.in.sh +41 -0
  44. data/spec/conf/1.0/cassandra.yaml +416 -0
  45. data/spec/conf/1.0/log4j-server.properties +40 -0
  46. data/spec/conf/1.0/schema.txt +10 -0
  47. data/spec/conf/1.1/cassandra.in.sh +41 -0
  48. data/spec/conf/1.1/cassandra.yaml +560 -0
  49. data/spec/conf/1.1/log4j-server.properties +44 -0
  50. data/spec/conf/1.1/schema.txt +10 -0
  51. data/spec/database_spec.rb +25 -0
  52. data/spec/result_spec.rb +173 -0
  53. data/spec/row_spec.rb +49 -0
  54. data/spec/rowkey_spec.rb +233 -0
  55. data/spec/schema_spec.rb +51 -0
  56. data/spec/spec_helper.rb +30 -0
  57. data/spec/statement_spec.rb +226 -0
  58. data/spec/utility_spec.rb +26 -0
  59. data/spec/uuid_spec.rb +26 -0
  60. data/spec/validation_spec.rb +272 -0
  61. data/vendor/0.8/gen-rb/cassandra.rb +2210 -0
  62. data/vendor/0.8/gen-rb/cassandra_constants.rb +10 -0
  63. data/vendor/0.8/gen-rb/cassandra_types.rb +811 -0
  64. data/vendor/1.0/gen-rb/cassandra.rb +2212 -0
  65. data/vendor/1.0/gen-rb/cassandra_constants.rb +10 -0
  66. data/vendor/1.0/gen-rb/cassandra_types.rb +854 -0
  67. data/vendor/1.1/gen-rb/cassandra.rb +2511 -0
  68. data/vendor/1.1/gen-rb/cassandra_constants.rb +13 -0
  69. data/vendor/1.1/gen-rb/cassandra_types.rb +928 -0
  70. metadata +230 -0
@@ -0,0 +1,49 @@
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; end;
18
+ unless CassandraCQL.respond_to?(:CASSANDRA_VERSION)
19
+ require "cassandra-cql/1.1"
20
+ end
21
+
22
+ here = File.expand_path(File.dirname(__FILE__))
23
+ require "#{here}/../vendor/#{CassandraCQL.CASSANDRA_VERSION}/gen-rb/cassandra"
24
+
25
+ require 'bigdecimal'
26
+ require 'date'
27
+ require 'thrift_client'
28
+ require 'cassandra-cql/types/abstract_type'
29
+ require 'cassandra-cql/types/ascii_type'
30
+ require 'cassandra-cql/types/boolean_type'
31
+ require 'cassandra-cql/types/bytes_type'
32
+ require 'cassandra-cql/types/date_type'
33
+ require 'cassandra-cql/types/decimal_type'
34
+ require 'cassandra-cql/types/double_type'
35
+ require 'cassandra-cql/types/float_type'
36
+ require 'cassandra-cql/types/integer_type'
37
+ require 'cassandra-cql/types/long_type'
38
+ require 'cassandra-cql/types/utf8_type'
39
+ require 'cassandra-cql/types/uuid_type'
40
+ require 'cassandra-cql/utility'
41
+ require 'cassandra-cql/uuid'
42
+ require 'cassandra-cql/database'
43
+ require 'cassandra-cql/schema'
44
+ require 'cassandra-cql/statement'
45
+ require 'cassandra-cql/result'
46
+ require 'cassandra-cql/row'
47
+
48
+ require "cassandra-cql/#{CassandraCQL.CASSANDRA_VERSION}/result"
49
+ require "cassandra-cql/#{CassandraCQL.CASSANDRA_VERSION}/statement"
@@ -0,0 +1,7 @@
1
+ module CassandraCQL
2
+ def self.CASSANDRA_VERSION
3
+ "0.8"
4
+ end
5
+ end
6
+
7
+ require "#{File.expand_path(File.dirname(__FILE__))}/../cassandra-cql"
@@ -0,0 +1,23 @@
1
+ module CassandraCQL
2
+ module V08
3
+ class ResultSchema < CassandraCQL::ResultSchema
4
+ def initialize(column_family)
5
+ type_slice = lambda {|type| type[type.rindex('.')+1..-1] }
6
+
7
+ @names = Hash.new(type_slice.call(column_family.comparator_type))
8
+ @values = Hash.new(type_slice.call(column_family.default_validation_class))
9
+ column_family.columns.each_pair do |name, type|
10
+ @values[name] = type_slice.call(type)
11
+ end
12
+ end
13
+ end
14
+
15
+ class Result < CassandraCQL::Result
16
+ def initialize(result, column_family)
17
+ @result = result
18
+ @schema = ResultSchema.new(column_family) if rows?
19
+ @cursor = 0
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,38 @@
1
+ module CassandraCQL
2
+ module V08
3
+ class Statement < CassandraCQL::Statement
4
+ SCHEMA_CHANGE_RE = /\s*(create|drop|alter)\s+(\w+)/i
5
+ COLFAM_RE = /\s*select.*from\s+'?(\w+)/i
6
+
7
+ def execute(bind_vars=[], options={})
8
+ column_family = nil
9
+ if @statement =~ COLFAM_RE
10
+ column_family = @handle.schema.column_families[$1].dup
11
+ end
12
+
13
+ sanitized_query = self.class.sanitize(@statement, bind_vars)
14
+ compression_type = CassandraCQL::Thrift::Compression::NONE
15
+ if options[:compression]
16
+ compression_type = CassandraCQL::Thrift::Compression::GZIP
17
+ sanitized_query = Utility.compress(sanitized_query)
18
+ end
19
+
20
+ res = V08::Result.new(@handle.execute_cql_query(sanitized_query, compression_type), column_family)
21
+
22
+ # Change our keyspace if required
23
+ if @statement =~ KS_CHANGE_RE
24
+ @handle.keyspace = $1
25
+ elsif @statement =~ KS_DROP_RE
26
+ @handle.keyspace = nil
27
+ end
28
+
29
+ # We let ints be fetched for now because they'll probably be deprecated later
30
+ if res.void?
31
+ nil
32
+ else
33
+ res
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ module CassandraCQL
2
+ def self.CASSANDRA_VERSION
3
+ "1.0"
4
+ end
5
+ end
6
+
7
+ require "#{File.expand_path(File.dirname(__FILE__))}/../cassandra-cql"
@@ -0,0 +1,6 @@
1
+ module CassandraCQL
2
+ module V10
3
+ class Result < CassandraCQL::Result
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module CassandraCQL
2
+ module V10
3
+ class Statement < CassandraCQL::Statement
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module CassandraCQL
2
+ def self.CASSANDRA_VERSION
3
+ "1.1"
4
+ end
5
+ end
6
+
7
+ require "#{File.expand_path(File.dirname(__FILE__))}/../cassandra-cql"
@@ -0,0 +1,6 @@
1
+ module CassandraCQL
2
+ module V11
3
+ class Result < CassandraCQL::Result
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module CassandraCQL
2
+ module V11
3
+ class Statement < CassandraCQL::Statement
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,127 @@
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
+ @cql_version = @options[:cql_version]
36
+ @servers = servers
37
+ connect!
38
+ execute("USE #{@keyspace}")
39
+ end
40
+
41
+ def connect!
42
+ @connection = ThriftClient.new(CassandraCQL::Thrift::Client, @servers, @thrift_client_options)
43
+ obj = self
44
+ @connection.add_callback(:post_connect) do
45
+ @connection.set_cql_version(@cql_version) if @cql_version
46
+ execute("USE #{@keyspace}")
47
+ @connection.login(@auth_request) if @auth_request
48
+ end
49
+ end
50
+
51
+ def disconnect!
52
+ @connection.disconnect! if active?
53
+ end
54
+
55
+ def active?
56
+ # TODO: This should be replaced with a CQL call that doesn't exist yet
57
+ @connection.describe_version
58
+ true
59
+ rescue Exception
60
+ false
61
+ end
62
+ alias_method :ping, :active?
63
+
64
+ def reset!
65
+ disconnect!
66
+ connect!
67
+ end
68
+ alias_method :reconnect!, :reset!
69
+
70
+ def statement_class
71
+ return @statement_class if @statement_class
72
+
73
+ version_module = 'V' + CassandraCQL.CASSANDRA_VERSION.gsub('.', '')
74
+ return @statement_class = CassandraCQL.const_get(version_module).const_get(:Statement)
75
+ end
76
+
77
+ def prepare(statement, options={}, &block)
78
+ stmt = statement_class.new(self, statement)
79
+ if block_given?
80
+ yield stmt
81
+ else
82
+ stmt
83
+ end
84
+ end
85
+
86
+ def execute(statement, *bind_vars)
87
+ result = statement_class.new(self, statement).execute(bind_vars)
88
+ if block_given?
89
+ yield result
90
+ else
91
+ result
92
+ end
93
+ rescue CassandraCQL::Thrift::InvalidRequestException
94
+ raise Error::InvalidRequestException.new($!.why)
95
+ end
96
+
97
+ def execute_cql_query(cql, compression=CassandraCQL::Thrift::Compression::NONE)
98
+ @connection.execute_cql_query(cql, compression)
99
+ rescue CassandraCQL::Thrift::InvalidRequestException
100
+ raise Error::InvalidRequestException.new($!.why)
101
+ end
102
+
103
+ def keyspace=(ks)
104
+ @keyspace = (ks.nil? ? nil : ks.to_s)
105
+ end
106
+
107
+ def keyspaces
108
+ # TODO: This should be replaced with a CQL call that doesn't exist yet
109
+ @connection.describe_keyspaces.map { |keyspace| Schema.new(keyspace) }
110
+ end
111
+
112
+ def schema
113
+ # TODO: This should be replaced with a CQL call that doesn't exist yet
114
+ Schema.new(@connection.describe_keyspace(@keyspace))
115
+ end
116
+
117
+ def login!(username, password)
118
+ request = CassandraCQL::Thrift::AuthenticationRequest.new
119
+ request.credentials = {'username' => username, 'password' => password}
120
+ ret = @connection.login(request)
121
+ # To avoid a double login on the initial connect, we set
122
+ # @auth_request after the first successful login.
123
+ @auth_request = request
124
+ ret
125
+ end
126
+ end
127
+ 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,54 @@
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
+ column_index = obj.kind_of?(Fixnum) ? obj : column_names.index(obj)
27
+ return nil if column_index.nil?
28
+ column_values[column_index]
29
+ end
30
+
31
+ def column_names
32
+ @names ||= @row.columns.map do |column|
33
+ ColumnFamily.cast(column.name, @schema.names[column.name])
34
+ end
35
+ end
36
+
37
+ def column_values
38
+ @values ||= @row.columns.map { |column| ColumnFamily.cast(column.value, @schema.values[column.name]) }
39
+ end
40
+
41
+ def columns
42
+ @row.columns.size
43
+ end
44
+
45
+ def to_a
46
+ column_values
47
+ end
48
+
49
+ # TODO: This should be an ordered hash
50
+ def to_hash
51
+ Hash[([column_names, column_values]).transpose]
52
+ end
53
+ end
54
+ end