cassanity 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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 = "https://github.com/jnunemaker/cassanity/"
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 = args.fetch(:name)
15
- schema = args.fetch(:schema)
16
- columns = schema.columns
17
- primary_key = schema.primary_key
18
- with = schema.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 (%s)" % Array(primary_key).join(', ')
30
+ definitions << "PRIMARY KEY (#{primary_keys.join(', ')})"
31
31
 
32
32
  cql_definition = definitions.join(', ')
33
33
 
34
- cql = "CREATE COLUMNFAMILY #{name} (%s)" % cql_definition
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
@@ -10,7 +10,7 @@ module Cassanity
10
10
  name = "#{keyspace_name}.#{name}"
11
11
  end
12
12
 
13
- cql = "DROP COLUMNFAMILY %s" % name
13
+ cql = "DROP COLUMNFAMILY #{name}"
14
14
  [cql]
15
15
  end
16
16
  end
@@ -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 %s WITH " % name.to_s
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[:strategy_options].each do |key, value|
30
- options << "strategy_options:#{key} = ?"
31
- variables << value
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
@@ -5,7 +5,7 @@ module Cassanity
5
5
  # Internal
6
6
  def call(args = {})
7
7
  name = args.fetch(:name)
8
- cql = "DROP KEYSPACE %s" % name
8
+ cql = "DROP KEYSPACE #{name}"
9
9
  [cql]
10
10
  end
11
11
  end
@@ -42,17 +42,11 @@ module Cassanity
42
42
  #
43
43
  # Returns Array of Cassanity::Keyspace instances.
44
44
  def keyspaces
45
- keyspaces = []
46
-
47
- result = @executor.call({
45
+ rows = @executor.call({
48
46
  command: :keyspaces,
49
47
  })
50
48
 
51
- result.fetch_hash do |row|
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
- # name - The String name of the keyspace.
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(name, args = {})
78
- keyspace_args = args.merge({
79
- name: name,
80
- executor: @executor,
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/column_family_select'
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::ColumnFamilySelect.new,
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 }
@@ -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
- # name - The String name of the column family.
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: {}). :name and :keyspace are always included.
119
+ # (optional, default: {}). :keyspace is always included.
105
120
  #
106
121
  # Returns a Cassanity::ColumnFamily instance.
107
- def column_family(name, args = {})
108
- column_family_args = args.merge({
109
- name: name,
110
- keyspace: self,
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
@@ -1,6 +1,6 @@
1
1
  module Cassanity
2
2
  module ResultTransformers
3
- class ColumnFamilySelect
3
+ class ResultToArray
4
4
 
5
5
  # Internal: Turns result into Array of Hashes.
6
6
  def call(result)
@@ -1,7 +1,10 @@
1
1
  module Cassanity
2
2
  class Schema
3
3
  # Internal
4
- attr_reader :primary_key
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
- @primary_key = args.fetch(:primary_key)
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
@@ -1,3 +1,3 @@
1
1
  module Cassanity
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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
- before do
42
- @return_value = subject.keyspace(keyspace_name)
43
- end
41
+ context "with only name" do
42
+ before do
43
+ @return_value = subject.keyspace(keyspace_name)
44
+ end
44
45
 
45
- it "returns instance of keyspace" do
46
- @return_value.should be_instance_of(Cassanity::Keyspace)
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
- before do
66
- @return_value = subject.column_family(column_family_name)
67
- end
65
+ context "with only name" do
66
+ before do
67
+ @return_value = subject.column_family(column_family_name)
68
+ end
68
69
 
69
- it "returns instance of column family" do
70
- @return_value.should be_instance_of(Cassanity::ColumnFamily)
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 args" do
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.1.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-06 00:00:00.000000000 Z
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: https://github.com/jnunemaker/cassanity/
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: