cassandra_migrations 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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