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 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: