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