cassanity 0.1.0 → 0.2.0
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/README.md +0 -2
- data/cassanity.gemspec +1 -1
- data/lib/cassanity/argument_generators/column_family_create.rb +7 -7
- data/lib/cassanity/argument_generators/column_family_drop.rb +1 -1
- data/lib/cassanity/argument_generators/keyspace_create.rb +10 -9
- data/lib/cassanity/argument_generators/keyspace_drop.rb +1 -1
- data/lib/cassanity/connection.rb +13 -24
- data/lib/cassanity/executors/cassandra_cql.rb +9 -2
- data/lib/cassanity/keyspace.rb +24 -8
- data/lib/cassanity/result_transformers/{column_family_select.rb → result_to_array.rb} +1 -1
- data/lib/cassanity/schema.rb +39 -2
- data/lib/cassanity/version.rb +1 -1
- data/spec/integration/cassanity/connection_spec.rb +0 -6
- data/spec/integration/cassanity/keyspace_spec.rb +19 -0
- data/spec/unit/cassanity/connection_spec.rb +59 -6
- data/spec/unit/cassanity/executors/cassandra_cql_spec.rb +38 -0
- data/spec/unit/cassanity/keyspace_spec.rb +136 -6
- data/spec/unit/cassanity/result_transformers/result_to_array_spec.rb +28 -0
- data/spec/unit/cassanity/schema_spec.rb +95 -0
- metadata +12 -7
- data/spec/unit/cassanity/result_transformers/column_family_select_spec.rb +0 -0
data/README.md
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
Layer of goodness on top of cassandra-cql so you do not have to write CQL strings all over the place.
|
4
4
|
|
5
|
-
Current status: Incomplete and changing fast. **Do not use this yet**, but feel free to follow along.
|
6
|
-
|
7
5
|
## Installation
|
8
6
|
|
9
7
|
Add this line to your application's Gemfile:
|
data/cassanity.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
|
|
10
10
|
gem.email = ["nunemaker@gmail.com"]
|
11
11
|
gem.description = %q{Layer of goodness on top of cassandra-cql so you do not have to write CQL strings all over the place.}
|
12
12
|
gem.summary = %q{Layer of goodness on top of cassandra-cql so you do not have to write CQL strings all over the place.}
|
13
|
-
gem.homepage = "
|
13
|
+
gem.homepage = "http://johnnunemaker.com/cassanity/"
|
14
14
|
|
15
15
|
gem.files = `git ls-files`.split($/)
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
@@ -11,11 +11,11 @@ module Cassanity
|
|
11
11
|
|
12
12
|
# Internal
|
13
13
|
def call(args = {})
|
14
|
-
name
|
15
|
-
schema
|
16
|
-
columns
|
17
|
-
|
18
|
-
with
|
14
|
+
name = args.fetch(:name)
|
15
|
+
schema = args.fetch(:schema)
|
16
|
+
columns = schema.columns
|
17
|
+
primary_keys = schema.primary_keys
|
18
|
+
with = schema.with
|
19
19
|
|
20
20
|
definitions, variables = [], []
|
21
21
|
|
@@ -27,11 +27,11 @@ module Cassanity
|
|
27
27
|
definitions << "#{name} #{type}"
|
28
28
|
end
|
29
29
|
|
30
|
-
definitions << "PRIMARY KEY (
|
30
|
+
definitions << "PRIMARY KEY (#{primary_keys.join(', ')})"
|
31
31
|
|
32
32
|
cql_definition = definitions.join(', ')
|
33
33
|
|
34
|
-
cql = "CREATE COLUMNFAMILY #{name} (
|
34
|
+
cql = "CREATE COLUMNFAMILY #{name} (#{cql_definition})"
|
35
35
|
|
36
36
|
with_cql, *with_variables = @with_clause.call(with: with)
|
37
37
|
cql << with_cql
|
@@ -1,12 +1,18 @@
|
|
1
|
+
require 'cassanity/argument_generators/with_clause'
|
2
|
+
|
1
3
|
module Cassanity
|
2
4
|
module ArgumentGenerators
|
3
5
|
class KeyspaceCreate
|
4
6
|
|
7
|
+
def initialize(args = {})
|
8
|
+
@with_clause = args.fetch(:with_clause) { WithClause.new }
|
9
|
+
end
|
10
|
+
|
5
11
|
# Internal
|
6
12
|
def call(args = {})
|
7
13
|
options, variables = [], []
|
8
14
|
name = args.fetch(:name)
|
9
|
-
cql = "CREATE KEYSPACE
|
15
|
+
cql = "CREATE KEYSPACE #{name}"
|
10
16
|
|
11
17
|
with = {
|
12
18
|
strategy_class: default_strategy_class,
|
@@ -17,20 +23,15 @@ module Cassanity
|
|
17
23
|
with[:strategy_class] = args[:strategy_class]
|
18
24
|
end
|
19
25
|
|
20
|
-
cql << "strategy_class = ? AND "
|
21
|
-
variables << with[:strategy_class]
|
22
|
-
|
23
26
|
if args[:strategy_options]
|
24
27
|
args[:strategy_options].each do |key, value|
|
25
28
|
with[:strategy_options][key] = value
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
29
|
-
with
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
cql << options.join(' AND ')
|
32
|
+
with_cql, *with_variables = @with_clause.call(with: with)
|
33
|
+
cql << with_cql
|
34
|
+
variables.concat(with_variables)
|
34
35
|
|
35
36
|
[cql, *variables]
|
36
37
|
end
|
data/lib/cassanity/connection.rb
CHANGED
@@ -42,17 +42,11 @@ module Cassanity
|
|
42
42
|
#
|
43
43
|
# Returns Array of Cassanity::Keyspace instances.
|
44
44
|
def keyspaces
|
45
|
-
|
46
|
-
|
47
|
-
result = @executor.call({
|
45
|
+
rows = @executor.call({
|
48
46
|
command: :keyspaces,
|
49
47
|
})
|
50
48
|
|
51
|
-
|
52
|
-
keyspaces << row
|
53
|
-
end
|
54
|
-
|
55
|
-
keyspaces.map { |row|
|
49
|
+
rows.map { |row|
|
56
50
|
Keyspace.new({
|
57
51
|
name: row['name'],
|
58
52
|
executor: @executor,
|
@@ -60,27 +54,22 @@ module Cassanity
|
|
60
54
|
}
|
61
55
|
end
|
62
56
|
|
63
|
-
# Public: Find out if a keyspace exists or not
|
64
|
-
#
|
65
|
-
# name - The String name of the keyspace
|
66
|
-
#
|
67
|
-
# Returns true if keyspace exists else false.
|
68
|
-
def keyspace?(name)
|
69
|
-
keyspaces.map(&:name).include?(name)
|
70
|
-
end
|
71
|
-
|
72
57
|
# Public: Get a keyspace instance
|
73
58
|
#
|
74
|
-
#
|
59
|
+
# name_or_args - The String name of the keyspace or a Hash which has a name
|
60
|
+
# key and possibly other arguments.
|
61
|
+
# args - The Hash of arguments to use for Keyspace initialization.
|
62
|
+
# (optional, default: {}). :executor is always included.
|
75
63
|
#
|
76
64
|
# Returns a Cassanity::Keyspace instance.
|
77
|
-
def keyspace(
|
78
|
-
keyspace_args =
|
79
|
-
|
80
|
-
|
81
|
-
|
65
|
+
def keyspace(name_or_args, args = {})
|
66
|
+
keyspace_args = if name_or_args.is_a?(Hash)
|
67
|
+
name_or_args.merge(args)
|
68
|
+
else
|
69
|
+
args.merge(name: name_or_args)
|
70
|
+
end
|
82
71
|
|
83
|
-
Keyspace.new(keyspace_args)
|
72
|
+
Keyspace.new(keyspace_args.merge(executor: executor))
|
84
73
|
end
|
85
74
|
|
86
75
|
alias_method :[], :keyspace
|
@@ -15,7 +15,7 @@ require 'cassanity/argument_generators/column_family_alter'
|
|
15
15
|
require 'cassanity/argument_generators/index_create'
|
16
16
|
require 'cassanity/argument_generators/index_drop'
|
17
17
|
require 'cassanity/argument_generators/batch'
|
18
|
-
require 'cassanity/result_transformers/
|
18
|
+
require 'cassanity/result_transformers/result_to_array'
|
19
19
|
require 'cassanity/result_transformers/mirror'
|
20
20
|
|
21
21
|
module Cassanity
|
@@ -43,7 +43,8 @@ module Cassanity
|
|
43
43
|
|
44
44
|
# Private: Hash of commands to related result transformers.
|
45
45
|
ResultTransformers = {
|
46
|
-
column_family_select: Cassanity::ResultTransformers::
|
46
|
+
column_family_select: Cassanity::ResultTransformers::ResultToArray.new,
|
47
|
+
keyspaces: Cassanity::ResultTransformers::ResultToArray.new,
|
47
48
|
}
|
48
49
|
|
49
50
|
# Private: Default result transformer for commands that do not have one.
|
@@ -62,6 +63,7 @@ module Cassanity
|
|
62
63
|
#
|
63
64
|
# args - The Hash of arguments.
|
64
65
|
# :client - The CassandraCQL::Database connection instance.
|
66
|
+
# :logger - What to use to log the cql and such being executed.
|
65
67
|
# :argument_generators - A Hash where each key is a command name
|
66
68
|
# and each value is the related argument
|
67
69
|
# generator that responds to `call`
|
@@ -78,6 +80,7 @@ module Cassanity
|
|
78
80
|
#
|
79
81
|
def initialize(args = {})
|
80
82
|
@client = args.fetch(:client)
|
83
|
+
@logger = args[:logger]
|
81
84
|
@argument_generators = args.fetch(:argument_generators) { ArgumentGenerators }
|
82
85
|
@result_transformers = args.fetch(:result_transformers) { ResultTransformers }
|
83
86
|
end
|
@@ -106,6 +109,10 @@ module Cassanity
|
|
106
109
|
generator = @argument_generators.fetch(command)
|
107
110
|
execute_arguments = generator.call(args[:arguments])
|
108
111
|
|
112
|
+
if @logger
|
113
|
+
@logger.debug { "#{self.class} executing #{execute_arguments.inspect}" }
|
114
|
+
end
|
115
|
+
|
109
116
|
result = @client.execute(*execute_arguments)
|
110
117
|
|
111
118
|
transformer = @result_transformers.fetch(command) { Mirror }
|
data/lib/cassanity/keyspace.rb
CHANGED
@@ -31,6 +31,15 @@ module Cassanity
|
|
31
31
|
@strategy_options = args[:strategy_options]
|
32
32
|
end
|
33
33
|
|
34
|
+
# Public: Returns true or false depending on if keyspace exists in the
|
35
|
+
# current cluster.
|
36
|
+
#
|
37
|
+
# Returns true if keyspace exists, false if it does not.
|
38
|
+
def exists?
|
39
|
+
rows = @executor.call(command: :keyspaces)
|
40
|
+
rows.any? { |row| row['name'].to_s == name.to_s }
|
41
|
+
end
|
42
|
+
|
34
43
|
# Public: Creates the keyspace
|
35
44
|
#
|
36
45
|
# args - The Hash of arguments to pass to the argument generator
|
@@ -59,6 +68,11 @@ module Cassanity
|
|
59
68
|
})
|
60
69
|
end
|
61
70
|
|
71
|
+
def recreate(args = {})
|
72
|
+
drop if exists?
|
73
|
+
create
|
74
|
+
end
|
75
|
+
|
62
76
|
# Public: Uses a keyspace
|
63
77
|
#
|
64
78
|
# args - The Hash of arguments to pass to the argument generator
|
@@ -99,18 +113,20 @@ module Cassanity
|
|
99
113
|
|
100
114
|
# Public: Get a column family instance
|
101
115
|
#
|
102
|
-
#
|
116
|
+
# name_or_args - The String name of the column family or a Hash which has
|
117
|
+
# the name key and possibly other arguments.
|
103
118
|
# args - The Hash of arguments to use for ColumnFamily initialization
|
104
|
-
# (optional, default: {}). :
|
119
|
+
# (optional, default: {}). :keyspace is always included.
|
105
120
|
#
|
106
121
|
# Returns a Cassanity::ColumnFamily instance.
|
107
|
-
def column_family(
|
108
|
-
column_family_args =
|
109
|
-
|
110
|
-
|
111
|
-
|
122
|
+
def column_family(name_or_args, args = {})
|
123
|
+
column_family_args = if name_or_args.is_a?(Hash)
|
124
|
+
name_or_args.merge(args)
|
125
|
+
else
|
126
|
+
args.merge(name: name_or_args)
|
127
|
+
end
|
112
128
|
|
113
|
-
ColumnFamily.new(column_family_args)
|
129
|
+
ColumnFamily.new(column_family_args.merge(keyspace: self))
|
114
130
|
end
|
115
131
|
alias_method :table, :column_family
|
116
132
|
alias_method :[], :column_family
|
data/lib/cassanity/schema.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
module Cassanity
|
2
2
|
class Schema
|
3
3
|
# Internal
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :primary_keys
|
5
|
+
|
6
|
+
# Internal
|
7
|
+
alias_method :primary_key, :primary_keys
|
5
8
|
|
6
9
|
# Internal
|
7
10
|
attr_reader :columns
|
@@ -17,10 +20,44 @@ module Cassanity
|
|
17
20
|
# :columns - The Hash of columns where the name is the column name
|
18
21
|
# and the value is the column type.
|
19
22
|
# :with - The Hash of options for the WITH clause.
|
23
|
+
# Raises KeyError if missing required argument key.
|
24
|
+
# Raises ArgumentError if primary key is not included in the columns.
|
20
25
|
def initialize(args = {})
|
21
|
-
@
|
26
|
+
@primary_keys = Array(args.fetch(:primary_key))
|
22
27
|
@columns = args.fetch(:columns)
|
28
|
+
|
29
|
+
ensure_primary_keys_are_columns
|
30
|
+
|
23
31
|
@with = args[:with] || {}
|
32
|
+
@composite_primary_key = @primary_keys.size > 1
|
33
|
+
end
|
34
|
+
|
35
|
+
# Public
|
36
|
+
def composite_primary_key?
|
37
|
+
@composite_primary_key == true
|
38
|
+
end
|
39
|
+
|
40
|
+
# Public: Returns an array of the column names
|
41
|
+
def column_names
|
42
|
+
@column_names ||= @columns.keys
|
43
|
+
end
|
44
|
+
|
45
|
+
# Public: Returns an array of the column types
|
46
|
+
def column_types
|
47
|
+
@column_types ||= @columns.values
|
48
|
+
end
|
49
|
+
|
50
|
+
# Private
|
51
|
+
def ensure_primary_keys_are_columns
|
52
|
+
unless primary_keys_are_defined_as_columns?
|
53
|
+
raise ArgumentError, "Not all primary keys (#{primary_keys.inspect}) were defined as columns (#{column_names.inspect})"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Private
|
58
|
+
def primary_keys_are_defined_as_columns?
|
59
|
+
shared_columns = column_names & @primary_keys
|
60
|
+
shared_columns == @primary_keys
|
24
61
|
end
|
25
62
|
end
|
26
63
|
end
|
data/lib/cassanity/version.rb
CHANGED
@@ -78,10 +78,4 @@ describe Cassanity::Connection do
|
|
78
78
|
client_drop_keyspace(client, 'something1')
|
79
79
|
client_drop_keyspace(client, 'something2')
|
80
80
|
end
|
81
|
-
|
82
|
-
it "knows if a keyspace exists" do
|
83
|
-
subject.keyspace?(keyspace_name).should be_false
|
84
|
-
client_create_keyspace(client, keyspace_name)
|
85
|
-
subject.keyspace?(keyspace_name).should be_true
|
86
|
-
end
|
87
81
|
end
|
@@ -49,6 +49,25 @@ describe Cassanity::Keyspace do
|
|
49
49
|
client_keyspace?(client, self_created_keyspace_name).should be_true
|
50
50
|
end
|
51
51
|
|
52
|
+
it "knows if it exists" do
|
53
|
+
subject.exists?.should be_true
|
54
|
+
client_drop_keyspace(client, keyspace_name)
|
55
|
+
subject.exists?.should be_false
|
56
|
+
end
|
57
|
+
|
58
|
+
it "can recreate when not created" do
|
59
|
+
client_drop_keyspace(client, keyspace_name)
|
60
|
+
client_keyspace?(client, keyspace_name).should be_false
|
61
|
+
subject.recreate
|
62
|
+
client_keyspace?(client, keyspace_name).should be_true
|
63
|
+
end
|
64
|
+
|
65
|
+
it "can recreate when already created" do
|
66
|
+
client_keyspace?(client, keyspace_name).should be_true
|
67
|
+
subject.recreate
|
68
|
+
client_keyspace?(client, keyspace_name).should be_true
|
69
|
+
end
|
70
|
+
|
52
71
|
it "can use" do
|
53
72
|
client.execute("USE system")
|
54
73
|
client.keyspace.should_not eq(keyspace_name)
|
@@ -38,21 +38,31 @@ describe Cassanity::Connection do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
describe "#keyspace" do
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
context "with only name" do
|
42
|
+
before do
|
43
|
+
@return_value = subject.keyspace(keyspace_name)
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
46
|
+
it "returns instance of keyspace" do
|
47
|
+
@return_value.should be_instance_of(Cassanity::Keyspace)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "sets name" do
|
51
|
+
@return_value.name.should eq(keyspace_name)
|
52
|
+
end
|
47
53
|
end
|
48
54
|
|
49
|
-
context "with args" do
|
55
|
+
context "with name and args" do
|
50
56
|
before do
|
51
57
|
@return_value = subject.keyspace(keyspace_name, {
|
52
58
|
strategy_class: 'NetworkTopologyStrategy',
|
53
59
|
})
|
54
60
|
end
|
55
61
|
|
62
|
+
it "correctly sets name" do
|
63
|
+
@return_value.name.should eq(keyspace_name)
|
64
|
+
end
|
65
|
+
|
56
66
|
it "passes args to initialization" do
|
57
67
|
@return_value.strategy_class.should eq('NetworkTopologyStrategy')
|
58
68
|
end
|
@@ -61,6 +71,49 @@ describe Cassanity::Connection do
|
|
61
71
|
@return_value.should be_instance_of(Cassanity::Keyspace)
|
62
72
|
end
|
63
73
|
end
|
74
|
+
|
75
|
+
context "with single hash" do
|
76
|
+
before do
|
77
|
+
@return_value = subject.keyspace({
|
78
|
+
name: keyspace_name,
|
79
|
+
strategy_class: 'NetworkTopologyStrategy',
|
80
|
+
})
|
81
|
+
end
|
82
|
+
|
83
|
+
it "returns instance of keyspace" do
|
84
|
+
@return_value.should be_instance_of(Cassanity::Keyspace)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "correctly sets name" do
|
88
|
+
@return_value.name.should eq(keyspace_name)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "passes args to initialization" do
|
92
|
+
@return_value.strategy_class.should eq('NetworkTopologyStrategy')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with two hashes" do
|
97
|
+
before do
|
98
|
+
@return_value = subject.keyspace({
|
99
|
+
name: keyspace_name,
|
100
|
+
}, {
|
101
|
+
strategy_class: 'NetworkTopologyStrategy',
|
102
|
+
})
|
103
|
+
end
|
104
|
+
|
105
|
+
it "returns instance of keyspace" do
|
106
|
+
@return_value.should be_instance_of(Cassanity::Keyspace)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "correctly sets name" do
|
110
|
+
@return_value.name.should eq(keyspace_name)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "passes args to initialization" do
|
114
|
+
@return_value.strategy_class.should eq('NetworkTopologyStrategy')
|
115
|
+
end
|
116
|
+
end
|
64
117
|
end
|
65
118
|
|
66
119
|
describe "#[]" do
|
@@ -105,6 +105,44 @@ describe Cassanity::Executors::CassandraCql do
|
|
105
105
|
subject.call(args)
|
106
106
|
end
|
107
107
|
|
108
|
+
context "with logger" do
|
109
|
+
let(:logger) {
|
110
|
+
Class.new do
|
111
|
+
attr_reader :logs
|
112
|
+
|
113
|
+
def initialize
|
114
|
+
@logs = []
|
115
|
+
end
|
116
|
+
|
117
|
+
def debug
|
118
|
+
@logs << {debug: yield}
|
119
|
+
end
|
120
|
+
end.new
|
121
|
+
}
|
122
|
+
|
123
|
+
subject {
|
124
|
+
described_class.new(required_arguments.merge({
|
125
|
+
argument_generators: argument_generators,
|
126
|
+
logger: logger,
|
127
|
+
}))
|
128
|
+
}
|
129
|
+
|
130
|
+
it "logs executed arguments" do
|
131
|
+
args = {
|
132
|
+
command: :foo,
|
133
|
+
arguments: {
|
134
|
+
something: 'else',
|
135
|
+
},
|
136
|
+
}
|
137
|
+
|
138
|
+
subject.call(args)
|
139
|
+
|
140
|
+
logger.logs.should eq([
|
141
|
+
{debug: 'Cassanity::Executors::CassandraCql executing ["mapped", {:something=>"else"}]'},
|
142
|
+
])
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
108
146
|
context "with result transformer" do
|
109
147
|
subject {
|
110
148
|
described_class.new(required_arguments.merge({
|
@@ -62,15 +62,21 @@ describe Cassanity::Keyspace do
|
|
62
62
|
describe "#column_family" do
|
63
63
|
let(:column_family_name) { 'apps' }
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
context "with only name" do
|
66
|
+
before do
|
67
|
+
@return_value = subject.column_family(column_family_name)
|
68
|
+
end
|
68
69
|
|
69
|
-
|
70
|
-
|
70
|
+
it "returns instance of column family" do
|
71
|
+
@return_value.should be_instance_of(Cassanity::ColumnFamily)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "sets name" do
|
75
|
+
@return_value.name.should eq(column_family_name)
|
76
|
+
end
|
71
77
|
end
|
72
78
|
|
73
|
-
context "with
|
79
|
+
context "with name and hash" do
|
74
80
|
let(:schema) { double('Schema') }
|
75
81
|
|
76
82
|
before do
|
@@ -83,6 +89,57 @@ describe Cassanity::Keyspace do
|
|
83
89
|
@return_value.schema.should eq(schema)
|
84
90
|
end
|
85
91
|
|
92
|
+
it "sets name" do
|
93
|
+
@return_value.name.should eq(column_family_name)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "returns instance of column family" do
|
97
|
+
@return_value.should be_instance_of(Cassanity::ColumnFamily)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "with hash" do
|
102
|
+
let(:schema) { double('Schema') }
|
103
|
+
|
104
|
+
before do
|
105
|
+
@return_value = subject.column_family({
|
106
|
+
name: column_family_name,
|
107
|
+
schema: schema,
|
108
|
+
})
|
109
|
+
end
|
110
|
+
|
111
|
+
it "passes args to initialization" do
|
112
|
+
@return_value.schema.should eq(schema)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "sets name" do
|
116
|
+
@return_value.name.should eq(column_family_name)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "returns instance of column family" do
|
120
|
+
@return_value.should be_instance_of(Cassanity::ColumnFamily)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "with two hashes" do
|
125
|
+
let(:schema) { double('Schema') }
|
126
|
+
|
127
|
+
before do
|
128
|
+
@return_value = subject.column_family({
|
129
|
+
name: column_family_name,
|
130
|
+
}, {
|
131
|
+
schema: schema,
|
132
|
+
})
|
133
|
+
end
|
134
|
+
|
135
|
+
it "passes args to initialization" do
|
136
|
+
@return_value.schema.should eq(schema)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "sets name" do
|
140
|
+
@return_value.name.should eq(column_family_name)
|
141
|
+
end
|
142
|
+
|
86
143
|
it "returns instance of column family" do
|
87
144
|
@return_value.should be_instance_of(Cassanity::ColumnFamily)
|
88
145
|
end
|
@@ -96,6 +153,10 @@ describe Cassanity::Keyspace do
|
|
96
153
|
@return_value = subject.table(column_family_name)
|
97
154
|
end
|
98
155
|
|
156
|
+
it "sets name" do
|
157
|
+
@return_value.name.should eq(column_family_name)
|
158
|
+
end
|
159
|
+
|
99
160
|
it "returns instance of column family" do
|
100
161
|
@return_value.should be_instance_of(Cassanity::ColumnFamily)
|
101
162
|
end
|
@@ -108,11 +169,80 @@ describe Cassanity::Keyspace do
|
|
108
169
|
@return_value = subject[column_family_name]
|
109
170
|
end
|
110
171
|
|
172
|
+
it "sets name" do
|
173
|
+
@return_value.name.should eq(column_family_name)
|
174
|
+
end
|
175
|
+
|
111
176
|
it "returns instance of column family" do
|
112
177
|
@return_value.should be_instance_of(Cassanity::ColumnFamily)
|
113
178
|
end
|
114
179
|
end
|
115
180
|
|
181
|
+
describe "#exists?" do
|
182
|
+
it "returns true if name in existing keyspace names" do
|
183
|
+
executor.should_receive(:call).with(command: :keyspaces).and_return([
|
184
|
+
{'name' => keyspace_name.to_s},
|
185
|
+
])
|
186
|
+
subject.exists?.should be_true
|
187
|
+
end
|
188
|
+
|
189
|
+
it "returns false if name not in existing keyspace names" do
|
190
|
+
executor.should_receive(:call).with(command: :keyspaces).and_return([
|
191
|
+
{'name' => 'batman'},
|
192
|
+
])
|
193
|
+
subject.exists?.should be_false
|
194
|
+
end
|
195
|
+
|
196
|
+
it "returns false if no keyspaces" do
|
197
|
+
executor.should_receive(:call).with(command: :keyspaces).and_return([])
|
198
|
+
subject.exists?.should be_false
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe "#create" do
|
203
|
+
it "sends command and arguments, including :name, to executor" do
|
204
|
+
args = {something: 'else'}
|
205
|
+
executor.should_receive(:call).with({
|
206
|
+
command: :keyspace_create,
|
207
|
+
arguments: args.merge(name: keyspace_name),
|
208
|
+
})
|
209
|
+
subject.create(args)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "#recreate" do
|
214
|
+
context "for existing keyspace" do
|
215
|
+
before do
|
216
|
+
subject.stub(:exist? => true)
|
217
|
+
end
|
218
|
+
it "performs drop" do
|
219
|
+
subject.should_not_receive(:drop)
|
220
|
+
subject.recreate
|
221
|
+
end
|
222
|
+
|
223
|
+
it "performs create" do
|
224
|
+
subject.should_receive(:create)
|
225
|
+
subject.recreate
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context "for non-existing keyspace" do
|
230
|
+
before do
|
231
|
+
subject.stub(:exist? => false)
|
232
|
+
end
|
233
|
+
|
234
|
+
it "does not perform drop" do
|
235
|
+
subject.should_not_receive(:drop)
|
236
|
+
subject.recreate
|
237
|
+
end
|
238
|
+
|
239
|
+
it "performs create" do
|
240
|
+
subject.should_receive(:create)
|
241
|
+
subject.recreate
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
116
246
|
describe "#use" do
|
117
247
|
it "sends command and arguments, including :name, to executor" do
|
118
248
|
args = {something: 'else'}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'cassanity/result_transformers/result_to_array'
|
3
|
+
|
4
|
+
describe Cassanity::ResultTransformers::ResultToArray do
|
5
|
+
let(:result_array) {
|
6
|
+
[{one: 1}, {two: 2}, {three: 3}]
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:result) {
|
10
|
+
Class.new do
|
11
|
+
def initialize(array)
|
12
|
+
@array = array
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch_hash
|
16
|
+
@array.each do |row|
|
17
|
+
yield row
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end.new(result_array)
|
21
|
+
}
|
22
|
+
|
23
|
+
describe "#call" do
|
24
|
+
it "it iterates fetch_hash and returns array" do
|
25
|
+
subject.call(result).should eq(result_array)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -12,6 +12,22 @@ describe Cassanity::Schema do
|
|
12
12
|
}
|
13
13
|
}
|
14
14
|
|
15
|
+
let(:composite_required_arguments) {
|
16
|
+
{
|
17
|
+
primary_key: [:bucket, :id],
|
18
|
+
columns: {
|
19
|
+
bucket: :text,
|
20
|
+
id: :text,
|
21
|
+
name: :text,
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
let(:schema) { described_class.new(required_arguments) }
|
27
|
+
let(:composite_schema) { described_class.new(composite_required_arguments) }
|
28
|
+
|
29
|
+
subject { schema }
|
30
|
+
|
15
31
|
describe "#initialize" do
|
16
32
|
[:primary_key, :columns].each do |key|
|
17
33
|
it "raises error without :#{key} key" do
|
@@ -19,5 +35,84 @@ describe Cassanity::Schema do
|
|
19
35
|
expect { described_class.new(args) }.to raise_error(KeyError)
|
20
36
|
end
|
21
37
|
end
|
38
|
+
|
39
|
+
it "raises error if primary_keys are not all included in columns" do
|
40
|
+
args = required_arguments.merge({
|
41
|
+
primary_key: [:foo, :bar],
|
42
|
+
columns: {
|
43
|
+
id: :text,
|
44
|
+
}
|
45
|
+
})
|
46
|
+
|
47
|
+
expect {
|
48
|
+
described_class.new(args)
|
49
|
+
}.to raise_error(ArgumentError, "Not all primary keys ([:foo, :bar]) were defined as columns ([:id])")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#column_names" do
|
54
|
+
it "returns array of column names" do
|
55
|
+
subject.column_names.should eq([:id, :name])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#column_types" do
|
60
|
+
it "returns array of column types" do
|
61
|
+
subject.column_types.should eq([:text, :text])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#primary_keys" do
|
66
|
+
context "with single primary key" do
|
67
|
+
subject { schema }
|
68
|
+
|
69
|
+
it "returns array of primary keys" do
|
70
|
+
subject.primary_keys.should eq([:id])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "with composite primary key" do
|
75
|
+
subject { composite_schema }
|
76
|
+
|
77
|
+
it "returns array of primary keys" do
|
78
|
+
subject.primary_keys.should eq([:bucket, :id])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#primary_key" do
|
84
|
+
context "with single primary key" do
|
85
|
+
subject { schema }
|
86
|
+
|
87
|
+
it "returns array of primary keys" do
|
88
|
+
subject.primary_key.should eq([:id])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with composite primary key" do
|
93
|
+
subject { composite_schema }
|
94
|
+
|
95
|
+
it "returns array of primary keys" do
|
96
|
+
subject.primary_key.should eq([:bucket, :id])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#composite_primary_key?" do
|
102
|
+
context "with single primary key" do
|
103
|
+
subject { schema }
|
104
|
+
|
105
|
+
it "returns returns false" do
|
106
|
+
subject.composite_primary_key?.should be_false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "with composite primary key" do
|
111
|
+
subject { composite_schema }
|
112
|
+
|
113
|
+
it "returns true" do
|
114
|
+
subject.composite_primary_key?.should be_true
|
115
|
+
end
|
116
|
+
end
|
22
117
|
end
|
23
118
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cassanity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cassandra-cql
|
@@ -73,8 +73,8 @@ files:
|
|
73
73
|
- lib/cassanity/error.rb
|
74
74
|
- lib/cassanity/executors/cassandra_cql.rb
|
75
75
|
- lib/cassanity/keyspace.rb
|
76
|
-
- lib/cassanity/result_transformers/column_family_select.rb
|
77
76
|
- lib/cassanity/result_transformers/mirror.rb
|
77
|
+
- lib/cassanity/result_transformers/result_to_array.rb
|
78
78
|
- lib/cassanity/schema.rb
|
79
79
|
- lib/cassanity/version.rb
|
80
80
|
- spec/helper.rb
|
@@ -106,11 +106,11 @@ files:
|
|
106
106
|
- spec/unit/cassanity/error_spec.rb
|
107
107
|
- spec/unit/cassanity/executors/cassandra_cql_spec.rb
|
108
108
|
- spec/unit/cassanity/keyspace_spec.rb
|
109
|
-
- spec/unit/cassanity/result_transformers/column_family_select_spec.rb
|
110
109
|
- spec/unit/cassanity/result_transformers/mirror_spec.rb
|
110
|
+
- spec/unit/cassanity/result_transformers/result_to_array_spec.rb
|
111
111
|
- spec/unit/cassanity/schema_spec.rb
|
112
112
|
- spec/unit/cassanity_spec.rb
|
113
|
-
homepage:
|
113
|
+
homepage: http://johnnunemaker.com/cassanity/
|
114
114
|
licenses: []
|
115
115
|
post_install_message:
|
116
116
|
rdoc_options: []
|
@@ -122,12 +122,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
122
|
- - ! '>='
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
segments:
|
126
|
+
- 0
|
127
|
+
hash: -3410109094406772154
|
125
128
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
129
|
none: false
|
127
130
|
requirements:
|
128
131
|
- - ! '>='
|
129
132
|
- !ruby/object:Gem::Version
|
130
133
|
version: '0'
|
134
|
+
segments:
|
135
|
+
- 0
|
136
|
+
hash: -3410109094406772154
|
131
137
|
requirements: []
|
132
138
|
rubyforge_project:
|
133
139
|
rubygems_version: 1.8.23
|
@@ -165,8 +171,7 @@ test_files:
|
|
165
171
|
- spec/unit/cassanity/error_spec.rb
|
166
172
|
- spec/unit/cassanity/executors/cassandra_cql_spec.rb
|
167
173
|
- spec/unit/cassanity/keyspace_spec.rb
|
168
|
-
- spec/unit/cassanity/result_transformers/column_family_select_spec.rb
|
169
174
|
- spec/unit/cassanity/result_transformers/mirror_spec.rb
|
175
|
+
- spec/unit/cassanity/result_transformers/result_to_array_spec.rb
|
170
176
|
- spec/unit/cassanity/schema_spec.rb
|
171
177
|
- spec/unit/cassanity_spec.rb
|
172
|
-
has_rdoc:
|
File without changes
|