cassandra_migrations 0.2.0 → 0.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c812cb0c202ab7c93f145b144dc36664734588f4
4
- data.tar.gz: 5aa232dd59bcd781a41b5e6bb7f2fb2b1b50b089
3
+ metadata.gz: 176ea1fc4dd207d821e6e128a4753582187eb49b
4
+ data.tar.gz: ac4409ef8ccf0290e55c73c034991964ba47c2aa
5
5
  SHA512:
6
- metadata.gz: 3eb66aa211265871e762ad3b56f1df6a79e5a0299174d3454ff38dc2b62eda8d981f591eb51efaa17331e669909c15ee53143b1f049d3440c93bd008aafb6d66
7
- data.tar.gz: f3768b62b72d021660f7a6ef8bf634585ee777c8a8c84649d70d299b926e960d9121abd5ee35e619427bfaaf61498edbcdd5172dea764c6061679340dcd30f64
6
+ metadata.gz: 7b37cf578a202b2d26ee5e97de8b3ea6775792311d93f8b5baa8ccf39af98d17c3d6aae1dcb56d228c4ed27578898c03dabefa46db7596d0616d629a7ea210f8
7
+ data.tar.gz: 150fb7344b9c8eb6eae4049fa502c230de30d30df13a73492e99b99084a76f1df210f28715610046ff3772c9ed5bc5a3e8a45b3c0d4d747e3578ecbdd6b0c150
@@ -3,122 +3,139 @@
3
3
  module CassandraMigrations
4
4
  module Cassandra
5
5
  module Queries
6
-
6
+
7
7
  def write!(table, value_hash, options={})
8
8
  columns = []
9
9
  values = []
10
-
11
- value_hash.each do |column, value|
10
+
11
+ value_hash.each do |column, value|
12
12
  columns << column.to_s
13
13
  values << to_cql_value(column, value, table, options)
14
14
  end
15
-
15
+
16
16
  query = "INSERT INTO #{table} (#{columns.join(', ')}) VALUES (#{values.join(', ')})"
17
-
17
+
18
18
  if options[:ttl]
19
19
  query += " USING TTL #{options[:ttl]}"
20
20
  end
21
-
21
+
22
22
  execute(query)
23
23
  end
24
-
24
+
25
25
  def update!(table, selection, value_hash, options={})
26
26
  set_terms = []
27
- value_hash.each do |column, value|
27
+ value_hash.each do |column, value|
28
28
  set_terms << "#{column} = #{to_cql_value(column, value, table, options)}"
29
29
  end
30
-
30
+
31
31
  query = "UPDATE #{table}"
32
-
32
+
33
33
  if options[:ttl]
34
34
  query += " USING TTL #{options[:ttl]}"
35
35
  end
36
-
36
+
37
37
  query += " SET #{set_terms.join(', ')} WHERE #{selection}"
38
-
38
+
39
39
  execute(query)
40
40
  end
41
-
41
+
42
42
  def select(table, options={})
43
43
  query_string = "SELECT #{options[:projection] || '*'} FROM #{table}"
44
-
44
+
45
45
  if options[:selection]
46
46
  query_string << " WHERE #{options[:selection]}"
47
47
  end
48
-
48
+
49
49
  if options[:order_by]
50
50
  query_string << " ORDER BY #{options[:order_by]}"
51
51
  end
52
-
52
+
53
53
  if options[:limit]
54
54
  query_string << " LIMIT #{options[:limit]}"
55
55
  end
56
-
56
+
57
57
  if options[:allow_filtering]
58
58
  query_string << " ALLOW FILTERING"
59
59
  end
60
-
60
+
61
61
  execute(query_string)
62
62
  end
63
-
63
+
64
64
  def delete!(table, selection, options={})
65
65
  options[:projection] = options[:projection].to_s + ' ' if options[:projection]
66
66
  execute("DELETE #{options[:projection]}FROM #{table} WHERE #{selection}")
67
67
  end
68
-
68
+
69
69
  def truncate!(table)
70
70
  execute("TRUNCATE #{table}")
71
71
  end
72
-
72
+
73
73
  private
74
-
74
+
75
+ SYMBOL_FOR_TYPE = {
76
+ 'SetType' => :set,
77
+ 'ListType' => :list,
78
+ 'MapType' => :map,
79
+ 'BooleanType' => :boolean,
80
+ 'FloatType' => :float,
81
+ 'Int32Type' => :int,
82
+ 'DateType' => :timestamp,
83
+ 'UTF8Type' => :string,
84
+ 'BytesType' => :blob,
85
+ 'UUIDType' => :uuid,
86
+ 'DoubleType' => :double,
87
+ 'InetAddressType' => :inet,
88
+ 'AsciiType' => :ascii,
89
+ 'LongType' => :bigint ,
90
+ 'DecimalType' => :decimal,
91
+ 'TimeUUIDType' => :timeuuid
92
+ }
93
+
75
94
  def get_column_type(table, column)
76
95
  column_info = client.execute("SELECT VALIDATOR FROM system.schema_columns WHERE keyspace_name = '#{client.keyspace}' AND columnfamily_name = '#{table}' AND column_name = '#{column}'")
77
- raw_type = column_info.first['validator']
78
-
79
- case
80
- when raw_type.include?('SetType'); :set
81
- when raw_type.include?('ListType'); :list
82
- when raw_type.include?('MapType'); :map
83
- when raw_type.include?('BooleanType'); :boolean
84
- when raw_type.include?('FloatType'); :float
85
- when raw_type.include?('Int32Type'); :int
86
- when raw_type.include?('DateType'); :timestamp
87
- when raw_type.include?('UTF8Type'); :string
88
- when raw_type.include?('BytesType'); :blob
89
- when raw_type.include?('UUIDType'); :uuid
90
- when raw_type.include?('DoubleType'); :double
91
- when raw_type.include?('InetAddressType'); :inet
92
- when raw_type.include?('AsciiType'); :ascii
93
- when raw_type.include?('LongType'); :bigint
94
- when raw_type.include?('DecimalType'); :decimal
95
- when raw_type.include?('TimeUUIDType'); :timeuuid
96
- end
96
+ SYMBOL_FOR_TYPE[column_info.first['validator']]
97
97
  end
98
-
98
+
99
99
  def to_cql_value(column, value, table, options={})
100
100
  operator = options[:operations] ? options[:operations][column.to_sym] : nil
101
101
  operation = operator ? "#{column} #{operator} " : ''
102
-
102
+
103
103
  if value.respond_to?(:strftime)
104
- "'#{value.strftime('%Y-%m-%d %H:%M:%S%z')}'"
104
+ datetime_to_cql(value)
105
105
  elsif value.is_a?(String)
106
- "'#{value}'"
106
+ string_to_cql(value)
107
107
  elsif value.is_a?(Array)
108
- type = get_column_type(table, column)
109
- values = %[#{value.map { |v| to_cql_value(nil, v, nil) } * ', '}]
110
-
111
- if type && type == :list
112
- %[#{operation}[#{values}]]
113
- else # it must be a set!
114
- %[#{operation}{#{values}}]
115
- end
108
+ array_value_to_cql(column, value, table, operation)
116
109
  elsif value.is_a?(Hash)
117
- "#{operation}{ #{value.reduce([]) {|sum, (key, value)| sum << "'#{key}': '#{value}'" }.join(", ") } }"
110
+ hash_to_cql(value, operation)
118
111
  else
119
112
  value.to_s
120
113
  end
121
114
  end
115
+
116
+ def string_to_cql(value)
117
+ "'#{value}'"
118
+ end
119
+
120
+ def datetime_to_cql(value)
121
+ "'#{value.strftime('%Y-%m-%d %H:%M:%S%z')}'"
122
+ end
123
+
124
+ def array_value_to_cql(column, value, table, operation)
125
+ type = get_column_type(table, column)
126
+ values = %[#{value.map { |v| to_cql_value(nil, v, nil) } * ', '}]
127
+
128
+ if type && type == :list
129
+ %[#{operation}[#{values}]]
130
+ else # it must be a set!
131
+ %[#{operation}{#{values}}]
132
+ end
133
+ end
134
+
135
+ def hash_to_cql(value, operation)
136
+ "#{operation}{ #{value.reduce([]) {|sum, (key, value)| sum << "'#{key}': '#{value}'" }.join(", ") } }"
137
+ end
138
+
122
139
  end
123
140
  end
124
141
  end
@@ -34,7 +34,7 @@ end
34
34
 
35
35
  class Client
36
36
  def self.connect(options)
37
- @cluster = Cassandra.connect(options)
37
+ @cluster = Cassandra.cluster(options)
38
38
  self.new(@cluster)
39
39
  end
40
40
 
@@ -16,21 +16,21 @@ module CassandraMigrations
16
16
  #
17
17
  # C* Data Types. See http://www.datastax.com/documentation/cql/3.0/cql/cql_reference/cql_data_types_c.html
18
18
  #
19
-
20
- # Migration | CQL Type | Ruby | Description
19
+ # ------------------------------------------------------------------------
20
+ # Migration | CQL Type | Ruby | Description
21
21
  # Type | | Class |
22
22
  # ------------------------------------------------------------------------
23
23
  # string | varchar | String | UTF-8 encoded string
24
- # text | text | String | UTF-8 encoded string
25
- # ascii | ascii | String | US-ASCII character string
24
+ # text | text | String | UTF-8 encoded string
25
+ # ascii | ascii | String | US-ASCII character string
26
26
  # ------------------------------------------------------------------------
27
27
  # integer(4) | int | Integer | 32-bit signed integer
28
- # integer(8) | bigint | Fixnum | 64-bit signed long
28
+ # integer(8) | bigint | Fixnum | 64-bit signed long
29
29
  # varint | varint | Bignum | Arbitrary-precision integer
30
30
  # ------------------------------------------------------------------------
31
- # decimal | decimal | BigDecimal | Variable-precision decimal
31
+ # decimal | decimal | BigDecimal | Variable-precision decimal
32
32
  # float(4) | float | | 32-bit IEEE-754 floating point
33
- # double | double | | Float 64-bit IEEE-754 floating point
33
+ # double | double | | Float 64-bit IEEE-754 floating point
34
34
  # float(8) | double | |
35
35
  # ------------------------------------------------------------------------
36
36
  # boolean | boolean | TrueClass | true or false
@@ -46,19 +46,17 @@ module CassandraMigrations
46
46
  # | | | bytes since epoch
47
47
  # datetime | timestamp | |
48
48
  # ------------------------------------------------------------------------
49
- # list | list | Array | A collection of one or more
49
+ # list | list | Array | A collection of one or more
50
50
  # | | | ordered elements
51
- # map | map | Hash | A JSON-style array of literals:
51
+ # map | map | Hash | A JSON-style array of literals:
52
52
  # | | | { literal : literal, ... }
53
53
  # set | set | Set | A collection of one or more
54
54
  # | | | elements
55
- # binary | blob | | Arbitrary bytes (no validation),
55
+ # binary | blob | | Arbitrary bytes (no validation),
56
56
  # | | | expressed as hexadecimal
57
57
  # | counter | | Distributed counter value
58
58
  # | | | (64-bit long)
59
-
60
-
61
-
59
+ # ------------------------------------------------------------------------
62
60
  def initialize()
63
61
  @columns_name_type_hash = {}
64
62
  @primary_keys = []
@@ -67,32 +65,9 @@ module CassandraMigrations
67
65
 
68
66
  def to_create_cql
69
67
  cql = []
70
-
71
- if !@columns_name_type_hash.empty?
72
- @columns_name_type_hash.each do |column_name, type|
73
- cql << "#{column_name} #{type}"
74
- end
75
- else
76
- raise Errors::MigrationDefinitionError, 'No columns defined for table.'
77
- end
78
-
79
- if (@columns_name_type_hash.values.include? :counter)
80
- non_key_columns = @columns_name_type_hash.keys - @primary_keys
81
- counter_columns = @columns_name_type_hash.select { |name, type| type == :counter }.keys
82
- if (non_key_columns - counter_columns).present?
83
- raise Errors::MigrationDefinitionError, 'Non key fields not allowed in tables with counter'
84
- end
85
- end
86
-
87
- key_info = (@primary_keys - @partition_keys)
88
- key_info = ["(#{@partition_keys.join(', ')})", *key_info] if @partition_keys.any?
89
-
90
- if key_info.any?
91
- cql << "PRIMARY KEY(#{key_info.join(', ')})"
92
- else
93
- raise Errors::MigrationDefinitionError, 'No primary key defined.'
94
- end
95
-
68
+ build_name_type_cql(cql)
69
+ check_for_non_key_fields_in_counter_table
70
+ build_pk_clause(cql)
96
71
  cql.join(', ')
97
72
  end
98
73
 
@@ -188,29 +163,11 @@ module CassandraMigrations
188
163
  end
189
164
 
190
165
  def list(column_name, options={})
191
- type = options[:type]
192
- if type.nil?
193
- raise Errors::MigrationDefinitionError, 'A list must define a collection type.'
194
- elsif !self.respond_to?(type)
195
- raise Errors::MigrationDefinitionError, "Type '#{type}' is not valid for cassandra migration."
196
- end
197
- if options[:primary_key]
198
- raise Errors::MigrationDefinitionError, 'A collection cannot be used as a primary key.'
199
- end
200
- @columns_name_type_hash[column_name.to_sym] = :"list<#{column_type_for(type)}>"
166
+ list_or_set(:list, column_name, options)
201
167
  end
202
168
 
203
169
  def set(column_name, options={})
204
- type = options[:type]
205
- if type.nil?
206
- raise Errors::MigrationDefinitionError, 'A set must define a collection type.'
207
- elsif !self.respond_to?(type)
208
- raise Errors::MigrationDefinitionError, "Type '#{type}' is not valid for cassandra migration."
209
- end
210
- if options[:primary_key]
211
- raise Errors::MigrationDefinitionError, 'A collection cannot be used as a primary key.'
212
- end
213
- @columns_name_type_hash[column_name.to_sym] = :"set<#{column_type_for(type)}>"
170
+ list_or_set(:set, column_name, options)
214
171
  end
215
172
 
216
173
  def map(column_name, options={})
@@ -294,6 +251,50 @@ module CassandraMigrations
294
251
  end
295
252
  end
296
253
 
254
+ def build_name_type_cql(cql)
255
+ if !@columns_name_type_hash.empty?
256
+ @columns_name_type_hash.each do |column_name, type|
257
+ cql << "#{column_name} #{type}"
258
+ end
259
+ else
260
+ raise Errors::MigrationDefinitionError, 'No columns defined for table.'
261
+ end
262
+ end
263
+
264
+ def check_for_non_key_fields_in_counter_table
265
+ if (@columns_name_type_hash.values.include? :counter)
266
+ non_key_columns = @columns_name_type_hash.keys - @primary_keys
267
+ counter_columns = @columns_name_type_hash.select { |name, type| type == :counter }.keys
268
+ if (non_key_columns - counter_columns).present?
269
+ raise Errors::MigrationDefinitionError, 'Non key fields not allowed in tables with counter'
270
+ end
271
+ end
272
+ end
273
+
274
+ def build_pk_clause(cql)
275
+ key_info = (@primary_keys - @partition_keys)
276
+ key_info = ["(#{@partition_keys.join(', ')})", *key_info] if @partition_keys.any?
277
+
278
+ if key_info.any?
279
+ cql << "PRIMARY KEY(#{key_info.join(', ')})"
280
+ else
281
+ raise Errors::MigrationDefinitionError, 'No primary key defined.'
282
+ end
283
+ end
284
+
285
+ def list_or_set(collection_type, column_name, options={})
286
+ type = options[:type]
287
+ if type.nil?
288
+ raise Errors::MigrationDefinitionError, "A #{collection_type} must define a collection type."
289
+ elsif !self.respond_to?(type)
290
+ raise Errors::MigrationDefinitionError, "Type '#{type}' is not valid for cassandra migration."
291
+ end
292
+ if options[:primary_key]
293
+ raise Errors::MigrationDefinitionError, 'A collection cannot be used as a primary key.'
294
+ end
295
+ @columns_name_type_hash[column_name.to_sym] = :"#{collection_type}<#{column_type_for(type)}>"
296
+ end
297
+
297
298
  end
298
299
  end
299
300
  end
@@ -4,18 +4,18 @@ require 'cassandra_migrations/migration/table_definition'
4
4
 
5
5
  module CassandraMigrations
6
6
  class Migration
7
-
7
+
8
8
  # Module grouping methods used in migrations to make table operations like:
9
9
  # - creating tables
10
10
  # - dropping tables
11
11
  module TableOperations
12
-
12
+
13
13
  # Creates a new table in the keyspace
14
14
  #
15
15
  # options:
16
16
  # - :primary_keys: single value or array (for compound primary keys). If
17
- # not defined, some column must be chosen as primary key in the table definition.
18
-
17
+ # not defined, some column must be chosen as primary key in the table definition.
18
+
19
19
  def create_table(table_name, options = {})
20
20
  table_definition = TableDefinition.new
21
21
  table_definition.define_primary_keys(options[:primary_keys]) if options[:primary_keys]
@@ -30,29 +30,29 @@ module CassandraMigrations
30
30
  create_cql << table_definition.to_create_cql
31
31
  create_cql << ")"
32
32
  create_cql << table_definition.options
33
-
33
+
34
34
  announce_suboperation create_cql
35
-
35
+
36
36
  execute create_cql
37
37
  end
38
-
38
+
39
39
  def create_index(table_name, column_name, options = {})
40
40
  announce_operation "create_index(#{table_name})"
41
41
  create_index_cql = "CREATE INDEX #{options[:name]} ON #{table_name} (#{column_name})".squeeze(' ')
42
42
  announce_suboperation create_index_cql
43
-
43
+
44
44
  execute create_index_cql
45
45
  end
46
-
46
+
47
47
  # Drops a table
48
48
  def drop_table(table_name)
49
49
  announce_operation "drop_table(#{table_name})"
50
50
  drop_cql = "DROP TABLE #{table_name}"
51
51
  announce_suboperation drop_cql
52
-
52
+
53
53
  execute drop_cql
54
54
  end
55
-
55
+
56
56
  def drop_index(table_or_index_name, column_name = nil, options = {})
57
57
  if column_name
58
58
  index_name = "#{table_or_index_name}_#{column_name}_idx"
@@ -61,16 +61,28 @@ module CassandraMigrations
61
61
  end
62
62
  drop_index_cql = "DROP INDEX #{options[:if_exists] ? 'IF EXISTS' : ''}#{index_name}"
63
63
  announce_suboperation drop_index_cql
64
-
65
- execute drop_index_cql
64
+
65
+ execute drop_index_cql
66
66
  end
67
67
 
68
- def add_options(table_name, options)
69
- announce_operation "add_options_#{table_name}"
70
- add_options_cql = "ALTER TABLE #{properties_cql(options)}"
71
- announce_suboperation drop_index_cql
68
+ def create_table(table_name, options = {})
69
+ table_definition = TableDefinition.new
70
+ table_definition.define_primary_keys(options[:primary_keys]) if options[:primary_keys]
71
+ table_definition.define_partition_keys(options[:partition_keys]) if options[:partition_keys]
72
+ table_definition.define_options(options[:options]) if options[:options]
73
+
74
+ yield table_definition if block_given?
75
+
76
+ announce_operation "create_table(#{table_name})"
77
+
78
+ create_cql = "CREATE TABLE #{table_name} ("
79
+ create_cql << table_definition.to_create_cql
80
+ create_cql << ")"
81
+ create_cql << table_definition.options
72
82
 
73
- execute add_options_cql
83
+ announce_suboperation create_cql
84
+
85
+ execute create_cql
74
86
  end
75
87
 
76
88
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cassandra_migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henrique Gubert
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-15 00:00:00.000000000 Z
12
+ date: 2014-12-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cassandra-driver
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: 1.0.0.beta.3
20
+ version: 1.1.1
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: 1.0.0.beta.3
27
+ version: 1.1.1
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement