cassanity 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +11 -0
  5. data/Guardfile +17 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +99 -0
  8. data/Rakefile +16 -0
  9. data/cassanity.gemspec +21 -0
  10. data/examples/_shared.rb +8 -0
  11. data/examples/batch.rb +40 -0
  12. data/examples/column_families.rb +68 -0
  13. data/examples/keyspaces.rb +57 -0
  14. data/lib/cassanity/argument_generators/batch.rb +52 -0
  15. data/lib/cassanity/argument_generators/column_family_alter.rb +47 -0
  16. data/lib/cassanity/argument_generators/column_family_create.rb +44 -0
  17. data/lib/cassanity/argument_generators/column_family_delete.rb +65 -0
  18. data/lib/cassanity/argument_generators/column_family_drop.rb +18 -0
  19. data/lib/cassanity/argument_generators/column_family_insert.rb +53 -0
  20. data/lib/cassanity/argument_generators/column_family_select.rb +34 -0
  21. data/lib/cassanity/argument_generators/column_family_truncate.rb +18 -0
  22. data/lib/cassanity/argument_generators/column_family_update.rb +69 -0
  23. data/lib/cassanity/argument_generators/index_create.rb +22 -0
  24. data/lib/cassanity/argument_generators/index_drop.rb +13 -0
  25. data/lib/cassanity/argument_generators/keyspace_create.rb +51 -0
  26. data/lib/cassanity/argument_generators/keyspace_drop.rb +13 -0
  27. data/lib/cassanity/argument_generators/keyspace_use.rb +13 -0
  28. data/lib/cassanity/argument_generators/keyspaces.rb +12 -0
  29. data/lib/cassanity/argument_generators/set_clause.rb +30 -0
  30. data/lib/cassanity/argument_generators/using_clause.rb +24 -0
  31. data/lib/cassanity/argument_generators/where_clause.rb +29 -0
  32. data/lib/cassanity/argument_generators/with_clause.rb +32 -0
  33. data/lib/cassanity/column_family.rb +233 -0
  34. data/lib/cassanity/connection.rb +88 -0
  35. data/lib/cassanity/error.rb +28 -0
  36. data/lib/cassanity/executors/cassandra_cql.rb +120 -0
  37. data/lib/cassanity/keyspace.rb +118 -0
  38. data/lib/cassanity/result_transformers/column_family_select.rb +15 -0
  39. data/lib/cassanity/result_transformers/mirror.rb +12 -0
  40. data/lib/cassanity/schema.rb +26 -0
  41. data/lib/cassanity/version.rb +3 -0
  42. data/lib/cassanity.rb +5 -0
  43. data/spec/helper.rb +27 -0
  44. data/spec/integration/cassanity/column_family_spec.rb +243 -0
  45. data/spec/integration/cassanity/connection_spec.rb +87 -0
  46. data/spec/integration/cassanity/keyspace_spec.rb +64 -0
  47. data/spec/support/cassanity_helpers.rb +35 -0
  48. data/spec/unit/cassanity/argument_generators/batch_spec.rb +36 -0
  49. data/spec/unit/cassanity/argument_generators/column_family_alter_spec.rb +85 -0
  50. data/spec/unit/cassanity/argument_generators/column_family_create_spec.rb +107 -0
  51. data/spec/unit/cassanity/argument_generators/column_family_delete_spec.rb +92 -0
  52. data/spec/unit/cassanity/argument_generators/column_family_drop_spec.rb +25 -0
  53. data/spec/unit/cassanity/argument_generators/column_family_insert_spec.rb +70 -0
  54. data/spec/unit/cassanity/argument_generators/column_family_select_spec.rb +113 -0
  55. data/spec/unit/cassanity/argument_generators/column_family_truncate_spec.rb +25 -0
  56. data/spec/unit/cassanity/argument_generators/column_family_update_spec.rb +109 -0
  57. data/spec/unit/cassanity/argument_generators/index_create_spec.rb +39 -0
  58. data/spec/unit/cassanity/argument_generators/index_drop_spec.rb +14 -0
  59. data/spec/unit/cassanity/argument_generators/keyspace_create_spec.rb +53 -0
  60. data/spec/unit/cassanity/argument_generators/keyspace_drop_spec.rb +14 -0
  61. data/spec/unit/cassanity/argument_generators/keyspace_use_spec.rb +14 -0
  62. data/spec/unit/cassanity/argument_generators/keyspaces_spec.rb +12 -0
  63. data/spec/unit/cassanity/argument_generators/set_clause_spec.rb +85 -0
  64. data/spec/unit/cassanity/argument_generators/using_clause_spec.rb +44 -0
  65. data/spec/unit/cassanity/argument_generators/where_clause_spec.rb +57 -0
  66. data/spec/unit/cassanity/argument_generators/with_clause_spec.rb +63 -0
  67. data/spec/unit/cassanity/column_family_spec.rb +250 -0
  68. data/spec/unit/cassanity/connection_spec.rb +75 -0
  69. data/spec/unit/cassanity/error_spec.rb +35 -0
  70. data/spec/unit/cassanity/executors/cassandra_cql_spec.rb +178 -0
  71. data/spec/unit/cassanity/keyspace_spec.rb +137 -0
  72. data/spec/unit/cassanity/result_transformers/column_family_select_spec.rb +0 -0
  73. data/spec/unit/cassanity/result_transformers/mirror_spec.rb +12 -0
  74. data/spec/unit/cassanity/schema_spec.rb +23 -0
  75. data/spec/unit/cassanity_spec.rb +5 -0
  76. metadata +172 -0
@@ -0,0 +1,28 @@
1
+ module Cassanity
2
+ class Error < Exception
3
+ # Public: The original error this exception is wrapping.
4
+ attr_reader :original
5
+
6
+ # Public: Initializes an Error.
7
+ #
8
+ # args - The Hash of arguments.
9
+ # :original - The Exception being wrapped (optional).
10
+ #
11
+ # Returns the duplicated String.
12
+ def initialize(args = {})
13
+ @original = args.fetch(:original) { $! }
14
+ @message = args.fetch(:message) {
15
+ if @original
16
+ "Original Exception: #{@original.class}: #{@original.message}"
17
+ else
18
+ "Something truly horrible went wrong"
19
+ end
20
+ }
21
+
22
+ super @message
23
+ end
24
+ end
25
+
26
+ class UnknownCommand < Error
27
+ end
28
+ end
@@ -0,0 +1,120 @@
1
+ require 'cassandra-cql'
2
+ require 'cassanity/error'
3
+ require 'cassanity/argument_generators/keyspaces'
4
+ require 'cassanity/argument_generators/keyspace_create'
5
+ require 'cassanity/argument_generators/keyspace_drop'
6
+ require 'cassanity/argument_generators/keyspace_use'
7
+ require 'cassanity/argument_generators/column_family_create'
8
+ require 'cassanity/argument_generators/column_family_drop'
9
+ require 'cassanity/argument_generators/column_family_truncate'
10
+ require 'cassanity/argument_generators/column_family_select'
11
+ require 'cassanity/argument_generators/column_family_insert'
12
+ require 'cassanity/argument_generators/column_family_update'
13
+ require 'cassanity/argument_generators/column_family_delete'
14
+ require 'cassanity/argument_generators/column_family_alter'
15
+ require 'cassanity/argument_generators/index_create'
16
+ require 'cassanity/argument_generators/index_drop'
17
+ require 'cassanity/argument_generators/batch'
18
+ require 'cassanity/result_transformers/column_family_select'
19
+ require 'cassanity/result_transformers/mirror'
20
+
21
+ module Cassanity
22
+ module Executors
23
+ class CassandraCql
24
+
25
+ # Private: Hash of commands to related argument generators.
26
+ ArgumentGenerators = {
27
+ keyspaces: Cassanity::ArgumentGenerators::Keyspaces.new,
28
+ keyspace_create: Cassanity::ArgumentGenerators::KeyspaceCreate.new,
29
+ keyspace_drop: Cassanity::ArgumentGenerators::KeyspaceDrop.new,
30
+ keyspace_use: Cassanity::ArgumentGenerators::KeyspaceUse.new,
31
+ column_family_create: Cassanity::ArgumentGenerators::ColumnFamilyCreate.new,
32
+ column_family_drop: Cassanity::ArgumentGenerators::ColumnFamilyDrop.new,
33
+ column_family_truncate: Cassanity::ArgumentGenerators::ColumnFamilyTruncate.new,
34
+ column_family_select: Cassanity::ArgumentGenerators::ColumnFamilySelect.new,
35
+ column_family_insert: Cassanity::ArgumentGenerators::ColumnFamilyInsert.new,
36
+ column_family_update: Cassanity::ArgumentGenerators::ColumnFamilyUpdate.new,
37
+ column_family_delete: Cassanity::ArgumentGenerators::ColumnFamilyDelete.new,
38
+ column_family_alter: Cassanity::ArgumentGenerators::ColumnFamilyAlter.new,
39
+ index_create: Cassanity::ArgumentGenerators::IndexCreate.new,
40
+ index_drop: Cassanity::ArgumentGenerators::IndexDrop.new,
41
+ batch: Cassanity::ArgumentGenerators::Batch.new,
42
+ }
43
+
44
+ # Private: Hash of commands to related result transformers.
45
+ ResultTransformers = {
46
+ column_family_select: Cassanity::ResultTransformers::ColumnFamilySelect.new,
47
+ }
48
+
49
+ # Private: Default result transformer for commands that do not have one.
50
+ Mirror = Cassanity::ResultTransformers::Mirror.new
51
+
52
+ # Private
53
+ attr_reader :client
54
+
55
+ # Private
56
+ attr_reader :argument_generators
57
+
58
+ # Private
59
+ attr_reader :result_transformers
60
+
61
+ # Internal: Initializes a cassandra-cql based CQL executor.
62
+ #
63
+ # args - The Hash of arguments.
64
+ # :client - The CassandraCQL::Database connection instance.
65
+ # :argument_generators - A Hash where each key is a command name
66
+ # and each value is the related argument
67
+ # generator that responds to `call`
68
+ # (optional).
69
+ # :result_transformers - A Hash where each key is a command name
70
+ # and each value is the related result
71
+ # transformer that responds to `call`
72
+ # (optional).
73
+ #
74
+ # Examples
75
+ #
76
+ # client = CassandraCQL::Database.new('host')
77
+ # Cassanity::Executors::CassandraCql.new(client: client)
78
+ #
79
+ def initialize(args = {})
80
+ @client = args.fetch(:client)
81
+ @argument_generators = args.fetch(:argument_generators) { ArgumentGenerators }
82
+ @result_transformers = args.fetch(:result_transformers) { ResultTransformers }
83
+ end
84
+
85
+ # Internal: Execute a CQL query.
86
+ #
87
+ # args - One or more arguments to send to execute. First should always be
88
+ # String CQL query. The rest should be the bound variables if any
89
+ # are needed.
90
+ #
91
+ # Examples
92
+ #
93
+ # call({
94
+ # command: :keyspaces,
95
+ # })
96
+ #
97
+ # call({
98
+ # command: :keyspace_create,
99
+ # arguments: {name: 'analytics'},
100
+ # })
101
+ #
102
+ # Returns the result of execution.
103
+ # Raises Cassanity::Error if anything goes wrong during execution.
104
+ def call(args = {})
105
+ command = args.fetch(:command)
106
+ generator = @argument_generators.fetch(command)
107
+ execute_arguments = generator.call(args[:arguments])
108
+
109
+ result = @client.execute(*execute_arguments)
110
+
111
+ transformer = @result_transformers.fetch(command) { Mirror }
112
+ transformer.call(result)
113
+ rescue KeyError
114
+ raise Cassanity::UnknownCommand
115
+ rescue Exception => e
116
+ raise Cassanity::Error
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,118 @@
1
+ require 'cassanity/column_family'
2
+
3
+ module Cassanity
4
+ class Keyspace
5
+ # Public
6
+ attr_reader :name
7
+
8
+ # Internal
9
+ attr_reader :executor
10
+
11
+ # Internal
12
+ attr_reader :strategy_class
13
+
14
+ # Internal
15
+ attr_reader :strategy_options
16
+
17
+ # Public: Initializes a Keyspace.
18
+ #
19
+ # args - The Hash of arguments (default: {}).
20
+ # :name - The String name of the keyspace.
21
+ # :executor - What will execute the queries. Must respond to `call`.
22
+ # :strategy_class - The String strategy class name to use when
23
+ # creating keyspace.
24
+ # :strategy_options - The Hash of strategy options to use when
25
+ # creating keyspace.
26
+ #
27
+ def initialize(args = {})
28
+ @name = args.fetch(:name)
29
+ @executor = args.fetch(:executor)
30
+ @strategy_class = args[:strategy_class]
31
+ @strategy_options = args[:strategy_options]
32
+ end
33
+
34
+ # Public: Creates the keyspace
35
+ #
36
+ # args - The Hash of arguments to pass to the argument generator
37
+ # (default: {}). :name is always included.
38
+ #
39
+ # Examples
40
+ #
41
+ # create # uses options from initialization
42
+ #
43
+ # # override options from initialization
44
+ # create({
45
+ # strategy_class: 'NetworkTopologyStrategy',
46
+ # strategy_options: {
47
+ # dc1: 1,
48
+ # dc2: 3,
49
+ # }
50
+ # })
51
+ #
52
+ # Returns whatever is returned by executor.
53
+ def create(args = {})
54
+ @executor.call({
55
+ command: :keyspace_create,
56
+ arguments: args.merge({
57
+ name: @name,
58
+ })
59
+ })
60
+ end
61
+
62
+ # Public: Uses a keyspace
63
+ #
64
+ # args - The Hash of arguments to pass to the argument generator
65
+ # (default: {}). :name is always included.
66
+ #
67
+ # Examples
68
+ #
69
+ # use # you shouldn't really ever need more than this
70
+ #
71
+ # Returns whatever is returned by executor.
72
+ def use(args = {})
73
+ @executor.call({
74
+ command: :keyspace_use,
75
+ arguments: args.merge({
76
+ name: @name,
77
+ }),
78
+ })
79
+ end
80
+
81
+ # Public: Drops a keyspace
82
+ #
83
+ # args - The Hash of arguments to pass to the argument generator
84
+ # (default: {}). :name is always included.
85
+ #
86
+ # Examples
87
+ #
88
+ # drop # you shouldn't really ever need more than this
89
+ #
90
+ # Returns whatever is returned by executor.
91
+ def drop(args = {})
92
+ @executor.call({
93
+ command: :keyspace_drop,
94
+ arguments: args.merge({
95
+ name: @name,
96
+ }),
97
+ })
98
+ end
99
+
100
+ # Public: Get a column family instance
101
+ #
102
+ # name - The String name of the column family.
103
+ # args - The Hash of arguments to use for ColumnFamily initialization
104
+ # (optional, default: {}). :name and :keyspace are always included.
105
+ #
106
+ # Returns a Cassanity::ColumnFamily instance.
107
+ def column_family(name, args = {})
108
+ column_family_args = args.merge({
109
+ name: name,
110
+ keyspace: self,
111
+ })
112
+
113
+ ColumnFamily.new(column_family_args)
114
+ end
115
+ alias_method :table, :column_family
116
+ alias_method :[], :column_family
117
+ end
118
+ end
@@ -0,0 +1,15 @@
1
+ module Cassanity
2
+ module ResultTransformers
3
+ class ColumnFamilySelect
4
+
5
+ # Internal: Turns result into Array of Hashes.
6
+ def call(result)
7
+ rows = []
8
+ result.fetch_hash do |row|
9
+ rows << row
10
+ end
11
+ rows
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module Cassanity
2
+ module ResultTransformers
3
+ class Mirror
4
+
5
+ # Internal: Returns whatever result is passed to it. This is used as the
6
+ # default result transformer when a command does not have one.
7
+ def call(result)
8
+ result
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ module Cassanity
2
+ class Schema
3
+ # Internal
4
+ attr_reader :primary_key
5
+
6
+ # Internal
7
+ attr_reader :columns
8
+
9
+ # Internal
10
+ attr_reader :with
11
+
12
+ # Public: Initializes a Schema.
13
+ #
14
+ # args - The Hash of arguments.
15
+ # :primary_key - The String or Symbol key or Array of String/Symbol
16
+ # keys to use as primary key.
17
+ # :columns - The Hash of columns where the name is the column name
18
+ # and the value is the column type.
19
+ # :with - The Hash of options for the WITH clause.
20
+ def initialize(args = {})
21
+ @primary_key = args.fetch(:primary_key)
22
+ @columns = args.fetch(:columns)
23
+ @with = args[:with] || {}
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ module Cassanity
2
+ VERSION = "0.1.0"
3
+ end
data/lib/cassanity.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Cassanity
2
+ end
3
+
4
+ require 'cassanity/connection'
5
+ require 'cassanity/executors/cassandra_cql'
data/spec/helper.rb ADDED
@@ -0,0 +1,27 @@
1
+ $:.unshift(File.expand_path('../../lib', __FILE__))
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+
6
+ Bundler.require :default
7
+
8
+ require 'cassanity'
9
+
10
+ root = Pathname(__FILE__).dirname.join('..').expand_path
11
+
12
+ Dir[root.join("spec/support/**/*.rb")].each { |f| require f }
13
+
14
+ RSpec.configure do |config|
15
+ config.order = :random
16
+
17
+ config.filter_run :focused => true
18
+ config.alias_example_to :fit, :focused => true
19
+ config.alias_example_to :xit, :pending => true
20
+ config.run_all_when_everything_filtered = true
21
+
22
+ config.backtrace_clean_patterns = [
23
+ /lib\/rspec\/(core|expectations|matchers|mocks)/,
24
+ ]
25
+
26
+ config.include CassanityHelpers
27
+ end
@@ -0,0 +1,243 @@
1
+ require 'helper'
2
+ require 'cassanity/keyspace'
3
+ require 'cassanity/executors/cassandra_cql'
4
+
5
+ describe Cassanity::ColumnFamily do
6
+ let(:keyspace_name) { 'cassanity_test' }
7
+ let(:column_family_name) { 'apps' }
8
+ let(:counters_column_family_name) { 'counters' }
9
+
10
+ let(:client) {
11
+ CassandraCQL::Database.new('127.0.0.1:9160', {
12
+ cql_version: '3.0.0',
13
+ })
14
+ }
15
+
16
+ let(:keyspace) {
17
+ Cassanity::Keyspace.new({
18
+ name: keyspace_name,
19
+ executor: executor,
20
+ })
21
+ }
22
+
23
+ let(:executor) {
24
+ Cassanity::Executors::CassandraCql.new({
25
+ client: client,
26
+ })
27
+ }
28
+
29
+ let(:schema) {
30
+ Cassanity::Schema.new({
31
+ primary_key: :id,
32
+ columns: {
33
+ id: :timeuuid,
34
+ name: :text,
35
+ },
36
+ with: {
37
+ comment: 'For storing things',
38
+ }
39
+ })
40
+ }
41
+
42
+ let(:arguments) {
43
+ {
44
+ keyspace: keyspace,
45
+ name: column_family_name,
46
+ schema: schema,
47
+ }
48
+ }
49
+
50
+ subject {
51
+ described_class.new(arguments)
52
+ }
53
+
54
+ before do
55
+ client_drop_keyspace(client, keyspace_name)
56
+ client_create_keyspace(client, keyspace_name)
57
+ client_create_column_family(client, column_family_name, "id text PRIMARY KEY, name text")
58
+ client_create_column_family(client, counters_column_family_name, "id text PRIMARY KEY, views counter")
59
+ end
60
+
61
+ after do
62
+ client_drop_keyspace(client, keyspace_name)
63
+ end
64
+
65
+ it "can create itself" do
66
+ column_family = described_class.new(arguments.merge(name: 'people'))
67
+ column_family.create
68
+
69
+ apps_column_family = client.schema.column_families.fetch(column_family.name)
70
+ apps_column_family.comment.should eq('For storing things')
71
+
72
+ columns = apps_column_family.columns
73
+ columns.should have_key('id')
74
+ columns.should have_key('name')
75
+ columns['id'].should eq('org.apache.cassandra.db.marshal.TimeUUIDType')
76
+ columns['name'].should eq('org.apache.cassandra.db.marshal.UTF8Type')
77
+ end
78
+
79
+ it "can truncate" do
80
+ client.execute("INSERT INTO #{column_family_name} (id, name) VALUES (?, ?)", '1', 'github')
81
+ client.execute("INSERT INTO #{column_family_name} (id, name) VALUES (?, ?)", '2', 'gist')
82
+ result = client.execute("SELECT * FROM #{column_family_name}")
83
+ result.rows.should eq(2)
84
+
85
+ subject.truncate
86
+
87
+ result = client.execute("SELECT * FROM #{column_family_name}")
88
+ result.rows.should eq(0)
89
+ end
90
+
91
+ it "can drop" do
92
+ client_column_family?(client, column_family_name).should be_true
93
+ subject.drop
94
+ client_column_family?(client, column_family_name).should be_false
95
+ end
96
+
97
+ it "can drop when using a different keyspace" do
98
+ client_column_family?(client, column_family_name).should be_true
99
+ client.execute('USE system')
100
+ subject.drop
101
+ client_column_family?(client, column_family_name).should be_false
102
+ end
103
+
104
+ it "can alter" do
105
+ subject.alter(add: {created_at: :timestamp})
106
+
107
+ apps_column_family = client.schema.column_families.fetch(column_family_name)
108
+ columns = apps_column_family.columns
109
+ columns.should have_key('created_at')
110
+ columns['created_at'].should eq('org.apache.cassandra.db.marshal.DateType')
111
+
112
+ subject.alter(alter: {created_at: :timeuuid})
113
+
114
+ apps_column_family = client.schema.column_families.fetch(column_family_name)
115
+ columns = apps_column_family.columns
116
+ columns.should have_key('created_at')
117
+ columns['created_at'].should eq('org.apache.cassandra.db.marshal.TimeUUIDType')
118
+
119
+ subject.alter(drop: :created_at)
120
+
121
+ apps_column_family = client.schema.column_families.fetch(column_family_name)
122
+ columns = apps_column_family.columns
123
+ columns.should_not have_key('created_at')
124
+
125
+ subject.alter(with: {comment: 'Some new comment'})
126
+ apps_column_family = client.schema.column_families.fetch(column_family_name)
127
+ apps_column_family.comment.should eq('Some new comment')
128
+ end
129
+
130
+ it "can create and drop indexes" do
131
+ subject.create_index({
132
+ name: :apps_name_index,
133
+ column_name: :name,
134
+ })
135
+
136
+ apps = client.schema.column_families['apps']
137
+ apps_meta = apps.column_metadata
138
+ index = apps_meta.detect { |c| c.index_name == 'apps_name_index' }
139
+ index.should_not be_nil
140
+
141
+ subject.drop_index({
142
+ name: :apps_name_index,
143
+ })
144
+
145
+ apps = client.schema.column_families['apps']
146
+ apps_meta = apps.column_metadata
147
+ index = apps_meta.detect { |c| c.index_name == 'apps_name_index' }
148
+ index.should be_nil
149
+ end
150
+
151
+ it "can select data" do
152
+ client.execute("INSERT INTO #{column_family_name} (id, name) VALUES (?, ?)", '1', 'github')
153
+ client.execute("INSERT INTO #{column_family_name} (id, name) VALUES (?, ?)", '2', 'gist')
154
+ result = subject.select({
155
+ select: :name,
156
+ where: {
157
+ id: '2',
158
+ },
159
+ })
160
+ result.should eq([
161
+ {'name' => 'gist'}
162
+ ])
163
+ end
164
+
165
+ it "can insert data" do
166
+ subject.insert({
167
+ data: {
168
+ id: '1',
169
+ name: 'GitHub',
170
+ },
171
+ })
172
+
173
+ result = client.execute("SELECT * FROM #{column_family_name}")
174
+ result.rows.should eq(1)
175
+ row = result.fetch_hash
176
+ row['id'].should eq('1')
177
+ row['name'].should eq('GitHub')
178
+ end
179
+
180
+ it "can update data" do
181
+ client.execute("INSERT INTO #{column_family_name} (id, name) VALUES (?, ?)", '1', 'github')
182
+ client.execute("INSERT INTO #{column_family_name} (id, name) VALUES (?, ?)", '2', 'gist')
183
+
184
+ subject.update({
185
+ set: {name: 'New Name'},
186
+ where: {id: '1'},
187
+ })
188
+
189
+ result = client.execute("SELECT * FROM #{column_family_name} WHERE id = '1'")
190
+ result.rows.should eq(1)
191
+ row = result.fetch_hash
192
+ row['id'].should eq('1')
193
+ row['name'].should eq('New Name')
194
+
195
+ # does not update other rows
196
+ result = client.execute("SELECT * FROM #{column_family_name} WHERE id = '2'")
197
+ result.rows.should eq(1)
198
+ row = result.fetch_hash
199
+ row['id'].should eq('2')
200
+ row['name'].should eq('gist')
201
+ end
202
+
203
+ describe "updating a counter column" do
204
+ subject {
205
+ described_class.new({
206
+ keyspace: keyspace,
207
+ name: counters_column_family_name,
208
+ })
209
+ }
210
+
211
+ it "works" do
212
+ subject.update({
213
+ set: {views: 'views + 2'},
214
+ where: {id: '1'},
215
+ })
216
+
217
+ result = client.execute("SELECT * FROM #{counters_column_family_name} WHERE id = '1'")
218
+ result.rows.should eq(1)
219
+ row = result.fetch_hash
220
+ row['id'].should eq('1')
221
+ row['views'].should be(2)
222
+ end
223
+ end
224
+
225
+ it "can delete data" do
226
+ client.execute("INSERT INTO #{column_family_name} (id, name) VALUES (?, ?)", '1', 'github')
227
+ client.execute("INSERT INTO #{column_family_name} (id, name) VALUES (?, ?)", '2', 'gist')
228
+
229
+ result = client.execute("SELECT * FROM #{column_family_name}")
230
+ result.rows.should eq(2)
231
+
232
+ subject.delete({
233
+ where: {id: '1'},
234
+ })
235
+
236
+ result = client.execute("SELECT * FROM #{column_family_name} WHERE id = '1'")
237
+ result.rows.should eq(0)
238
+
239
+ # does not delete other rows
240
+ result = client.execute("SELECT * FROM #{column_family_name} WHERE id = '2'")
241
+ result.rows.should eq(1)
242
+ end
243
+ end
@@ -0,0 +1,87 @@
1
+ require 'helper'
2
+ require 'cassanity/connection'
3
+ require 'cassanity/executors/cassandra_cql'
4
+
5
+ describe Cassanity::Connection do
6
+ let(:keyspace_name) { 'cassanity_test' }
7
+ let(:column_family_name) { 'apps' }
8
+
9
+ let(:client) {
10
+ CassandraCQL::Database.new('127.0.0.1:9160', {
11
+ cql_version: '3.0.0',
12
+ })
13
+ }
14
+
15
+ let(:executor) {
16
+ Cassanity::Executors::CassandraCql.new({
17
+ client: client,
18
+ })
19
+ }
20
+
21
+ subject {
22
+ described_class.new({
23
+ executor: executor,
24
+ })
25
+ }
26
+
27
+ before do
28
+ client_drop_keyspace(client, keyspace_name)
29
+ end
30
+
31
+ after do
32
+ client_drop_keyspace(client, keyspace_name)
33
+ end
34
+
35
+ it "can batch" do
36
+ client_create_keyspace(client, keyspace_name)
37
+ client_create_column_family(client, column_family_name, "id text PRIMARY KEY, name text")
38
+
39
+ default_arguments = {
40
+ keyspace_name: keyspace_name,
41
+ name: column_family_name,
42
+ }
43
+
44
+ subject.batch({
45
+ :modifications => [
46
+ [:insert, default_arguments.merge(data: {id: '1', name: 'github'})],
47
+ [:insert, default_arguments.merge(data: {id: '2', name: 'gist'})],
48
+ [:update, default_arguments.merge(set: {name: 'github.com'}, where: {id: '1'})],
49
+ [:delete, default_arguments.merge(where: {id: '2'})],
50
+ ]
51
+ })
52
+
53
+ result = client.execute("SELECT * FROM apps")
54
+ result.rows.should be(1)
55
+
56
+ rows = []
57
+ result.fetch_hash { |row| rows << row }
58
+
59
+ rows.should eq([
60
+ {'id' => '1', 'name' => 'github.com'},
61
+ ])
62
+ end
63
+
64
+ it "knows keyspaces" do
65
+ client_create_keyspace(client, 'something1')
66
+ client_create_keyspace(client, 'something2')
67
+
68
+ result = subject.keyspaces
69
+ result.each do |keyspace|
70
+ keyspace.should be_instance_of(Cassanity::Keyspace)
71
+ keyspace.executor.should eq(subject.executor)
72
+ end
73
+
74
+ names = result.map(&:name)
75
+ names.should include('something1')
76
+ names.should include('something2')
77
+
78
+ client_drop_keyspace(client, 'something1')
79
+ client_drop_keyspace(client, 'something2')
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
+ end