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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 176ea1fc4dd207d821e6e128a4753582187eb49b
|
4
|
+
data.tar.gz: ac4409ef8ccf0290e55c73c034991964ba47c2aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
104
|
+
datetime_to_cql(value)
|
105
105
|
elsif value.is_a?(String)
|
106
|
-
|
106
|
+
string_to_cql(value)
|
107
107
|
elsif value.is_a?(Array)
|
108
|
-
|
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
|
-
|
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
|
@@ -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
|
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
|
25
|
-
# ascii | ascii | 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
|
28
|
+
# integer(8) | bigint | Fixnum | 64-bit signed long
|
29
29
|
# varint | varint | Bignum | Arbitrary-precision integer
|
30
30
|
# ------------------------------------------------------------------------
|
31
|
-
# decimal
|
31
|
+
# decimal | decimal | BigDecimal | Variable-precision decimal
|
32
32
|
# float(4) | float | | 32-bit IEEE-754 floating point
|
33
|
-
# double | double
|
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
|
49
|
+
# list | list | Array | A collection of one or more
|
50
50
|
# | | | ordered elements
|
51
|
-
# map | map | Hash
|
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
|
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
|
-
|
72
|
-
|
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
|
-
|
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
|
-
|
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
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
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.
|
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-
|
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.
|
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.
|
27
|
+
version: 1.1.1
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rake
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|