cassandra_model 0.9.3.2 → 0.9.18
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 +4 -4
- data/LICENSE.txt +0 -0
- data/README.md +0 -0
- data/lib/cassandra_model/batch_reactor/future.rb +0 -0
- data/lib/cassandra_model/batch_reactor.rb +0 -0
- data/lib/cassandra_model/composite_record.rb +4 -2
- data/lib/cassandra_model/composite_record_static.rb +69 -37
- data/lib/cassandra_model/concurrency_helper.rb +19 -0
- data/lib/cassandra_model/connection_cache.rb +0 -0
- data/lib/cassandra_model/counter_record.rb +8 -4
- data/lib/cassandra_model/data_inquirer.rb +3 -3
- data/lib/cassandra_model/data_modelling.rb +0 -0
- data/lib/cassandra_model/data_set.rb +0 -0
- data/lib/cassandra_model/displayable_attributes.rb +30 -2
- data/lib/cassandra_model/global_callbacks.rb +0 -0
- data/lib/cassandra_model/logging.rb +0 -0
- data/lib/cassandra_model/meta_columns.rb +0 -0
- data/lib/cassandra_model/meta_table.rb +0 -0
- data/lib/cassandra_model/query_builder.rb +15 -6
- data/lib/cassandra_model/query_helper.rb +0 -0
- data/lib/cassandra_model/query_result.rb +0 -0
- data/lib/cassandra_model/raw_connection.rb +2 -14
- data/lib/cassandra_model/record.rb +103 -16
- data/lib/cassandra_model/record_debug.rb +25 -0
- data/lib/cassandra_model/result_paginator.rb +0 -0
- data/lib/cassandra_model/rotating_table.rb +3 -1
- data/lib/cassandra_model/single_token_batch.rb +0 -0
- data/lib/cassandra_model/single_token_counter_batch.rb +0 -0
- data/lib/cassandra_model/single_token_logged_batch.rb +0 -0
- data/lib/cassandra_model/single_token_unlogged_batch.rb +0 -0
- data/lib/cassandra_model/table_debug.rb +36 -0
- data/lib/cassandra_model/table_definition.rb +10 -3
- data/lib/cassandra_model/table_descriptor.rb +0 -0
- data/lib/cassandra_model/table_redux.rb +1 -0
- data/lib/cassandra_model/type_guessing.rb +8 -8
- data/lib/cassandra_model.rb +7 -0
- metadata +15 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be8e45a8dab05f33396f041ca36c48c5e1fe207b
|
4
|
+
data.tar.gz: a3ec0023e367251890116beb12ff834c281e2928
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 530aee143ab413ec91369652ab008a735eaaeac79b9d562f5b5a137fde28ff8e3bf2b1058fb91b87a09bcab00fccc41ab8fe86139ea591ec15fdb553e72c67eb
|
7
|
+
data.tar.gz: 5b17cd82d99a77133afb742bdef04102b6399374f1c848bbecc29c495de43b85883c0bc12ce9f914d5ce0de86a503e64cd3a05e7698eed004d371d95f1c3a57c
|
data/LICENSE.txt
CHANGED
File without changes
|
data/README.md
CHANGED
File without changes
|
File without changes
|
File without changes
|
@@ -29,7 +29,9 @@ module CassandraModel
|
|
29
29
|
|
30
30
|
def composite_rows
|
31
31
|
(self.class.composite_defaults || []).map do |row|
|
32
|
-
merged_attributes = attributes.merge(row)
|
32
|
+
merged_attributes = self.class.deferred_columns.inject(attributes.merge(row)) do |memo, column|
|
33
|
+
memo.merge!(column => public_send(column))
|
34
|
+
end
|
33
35
|
self.class.new(merged_attributes, validate: false)
|
34
36
|
end
|
35
37
|
end
|
@@ -46,4 +48,4 @@ module CassandraModel
|
|
46
48
|
end
|
47
49
|
end
|
48
50
|
end
|
49
|
-
end
|
51
|
+
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
module CassandraModel
|
2
2
|
module CompositeRecordStatic
|
3
|
+
PK_MUTEX = Mutex.new
|
4
|
+
CK_MUTEX = Mutex.new
|
5
|
+
|
3
6
|
extend Forwardable
|
4
7
|
|
5
8
|
def_delegator :table_config, :composite_defaults=
|
@@ -26,16 +29,24 @@ module CassandraModel
|
|
26
29
|
|
27
30
|
def composite_pk_map
|
28
31
|
unless table_data.composite_pk_map
|
29
|
-
|
30
|
-
|
32
|
+
PK_MUTEX.synchronize do
|
33
|
+
return table_data.composite_pk_map if table_data.composite_pk_map
|
34
|
+
|
35
|
+
table_data.composite_pk_map = {}
|
36
|
+
columns
|
37
|
+
end
|
31
38
|
end
|
32
39
|
table_data.composite_pk_map
|
33
40
|
end
|
34
41
|
|
35
42
|
def composite_ck_map
|
36
43
|
unless table_data.composite_ck_map
|
37
|
-
|
38
|
-
|
44
|
+
CK_MUTEX.synchronize do
|
45
|
+
return table_data.composite_ck_map if table_data.composite_ck_map
|
46
|
+
|
47
|
+
table_data.composite_ck_map = {}
|
48
|
+
columns
|
49
|
+
end
|
39
50
|
end
|
40
51
|
table_data.composite_ck_map
|
41
52
|
end
|
@@ -63,8 +74,50 @@ module CassandraModel
|
|
63
74
|
end
|
64
75
|
end
|
65
76
|
|
77
|
+
def restriction_attributes(restriction)
|
78
|
+
updated_restriction = restriction.inject({}) do |memo, (key, value)|
|
79
|
+
updated_key = key_for_where_params(key)
|
80
|
+
memo.merge!(updated_key => value)
|
81
|
+
end
|
82
|
+
|
83
|
+
missing_keys = Set.new(internal_partition_key - updated_restriction.keys)
|
84
|
+
default_clause = composite_defaults.find { |row| (missing_keys ^ row.keys).empty? }
|
85
|
+
updated_restriction.merge!(default_clause) if default_clause
|
86
|
+
updated_restriction
|
87
|
+
end
|
88
|
+
|
89
|
+
def normalized_column(column)
|
90
|
+
column = super(column)
|
91
|
+
|
92
|
+
if column =~ /^rk_/ || column =~ /^ck_/
|
93
|
+
mapped_column(column)
|
94
|
+
else
|
95
|
+
column
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def normalized_attributes(attributes)
|
100
|
+
attributes = super(attributes)
|
101
|
+
|
102
|
+
attributes.inject({}) do |memo, (column, value)|
|
103
|
+
memo.merge!(normalized_column(column) => value)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def select_columns(columns)
|
108
|
+
columns.map { |column| select_column(column) }
|
109
|
+
end
|
110
|
+
|
111
|
+
def select_column(column)
|
112
|
+
has_field?(column) ? column : mapped_column(column)
|
113
|
+
end
|
114
|
+
|
66
115
|
private
|
67
116
|
|
117
|
+
def has_field?(column)
|
118
|
+
internal_columns.include?(column)
|
119
|
+
end
|
120
|
+
|
68
121
|
def build_composite_map
|
69
122
|
if table_config.composite_defaults
|
70
123
|
table_config.composite_defaults.map { |row| row_composite_default(row) }
|
@@ -90,36 +143,27 @@ module CassandraModel
|
|
90
143
|
end
|
91
144
|
|
92
145
|
def select_clause(select)
|
93
|
-
select =
|
146
|
+
select = select_columns(select) if select
|
94
147
|
super(select)
|
95
148
|
end
|
96
149
|
|
97
150
|
def order_by_clause(order_by)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
mapped_column(column)
|
151
|
+
if order_by
|
152
|
+
order_by = [order_by] unless order_by.is_a?(Array)
|
153
|
+
order_by = order_by.map do |column|
|
154
|
+
if column.is_a?(Hash)
|
155
|
+
column, direction = column.first
|
156
|
+
{select_column(column) => direction}
|
157
|
+
else
|
158
|
+
select_column(column)
|
159
|
+
end
|
108
160
|
end
|
109
161
|
end
|
162
|
+
super(order_by)
|
110
163
|
end
|
111
164
|
|
112
165
|
def where_params(clause)
|
113
|
-
|
114
|
-
updated_key = key_for_where_params(key)
|
115
|
-
memo.merge!(updated_key => value)
|
116
|
-
end
|
117
|
-
|
118
|
-
missing_keys = Set.new(internal_partition_key - updated_clause.keys)
|
119
|
-
default_clause = composite_defaults.find { |row| (missing_keys ^ row.keys).empty? }
|
120
|
-
updated_clause.merge!(default_clause) if default_clause
|
121
|
-
|
122
|
-
super(updated_clause)
|
166
|
+
super restriction_attributes(clause)
|
123
167
|
end
|
124
168
|
|
125
169
|
def key_for_where_params(key)
|
@@ -149,18 +193,6 @@ module CassandraModel
|
|
149
193
|
composite_pk_map[key] || key
|
150
194
|
end
|
151
195
|
|
152
|
-
def row_attributes(row)
|
153
|
-
row = super(row)
|
154
|
-
|
155
|
-
row.inject({}) do |memo, (column, value)|
|
156
|
-
if column =~ /^rk_/ || column =~ /^ck_/
|
157
|
-
memo.merge!(mapped_column(column) => value)
|
158
|
-
else
|
159
|
-
memo.merge!(column => value)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
196
|
def mapped_column(column)
|
165
197
|
(composite_ck_map[column] || composite_pk_map[column] || column)
|
166
198
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CassandraModel
|
2
|
+
module ConcurrencyHelper
|
3
|
+
private
|
4
|
+
|
5
|
+
def safe_getset_variable(mutex, name, &block)
|
6
|
+
result = instance_variable_get(name)
|
7
|
+
return result if result
|
8
|
+
|
9
|
+
mutex.synchronize do
|
10
|
+
raise Cassandra::Errors::InvalidError.new('Connection invalidated!', 'Dummy') if !!@shutdown
|
11
|
+
|
12
|
+
result = instance_variable_get(name)
|
13
|
+
return result if result
|
14
|
+
|
15
|
+
instance_variable_set(name, block.call)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
File without changes
|
@@ -5,16 +5,20 @@ module CassandraModel
|
|
5
5
|
counter_clause = counter_clause(options)
|
6
6
|
row_key = internal_primary_key.values
|
7
7
|
statement = increment_statement(counter_clause)
|
8
|
+
column_values = options.values + row_key
|
9
|
+
|
10
|
+
validation_error = validate_primary_key!(statement, column_values)
|
11
|
+
return validation_error if validation_error
|
8
12
|
|
9
13
|
future = if batch_reactor
|
10
|
-
execute_async_in_batch(statement,
|
14
|
+
execute_async_in_batch(statement, column_values)
|
11
15
|
else
|
12
|
-
session.execute_async(statement, *
|
16
|
+
session.execute_async(statement, *column_values, write_query_options)
|
13
17
|
end
|
14
18
|
future.on_success { execute_callback(:record_saved) }
|
15
19
|
future.on_failure do |error|
|
16
20
|
Logging.logger.error("Error incrementing #{self.class}: #{error}")
|
17
|
-
execute_callback(:save_record_failed, error)
|
21
|
+
execute_callback(:save_record_failed, error, statement, column_values)
|
18
22
|
end.then { self }
|
19
23
|
end
|
20
24
|
|
@@ -29,7 +33,7 @@ module CassandraModel
|
|
29
33
|
private
|
30
34
|
|
31
35
|
def internal_primary_key
|
32
|
-
|
36
|
+
self.class.internal_primary_key.inject({}) { |memo, key| memo.merge!(key => internal_attributes[key]) }
|
33
37
|
end
|
34
38
|
|
35
39
|
def increment_statement(counter_clause)
|
@@ -2,7 +2,7 @@ module CassandraModel
|
|
2
2
|
class DataInquirer
|
3
3
|
include TypeGuessing
|
4
4
|
|
5
|
-
attr_reader :partition_key, :column_defaults, :
|
5
|
+
attr_reader :partition_key, :column_defaults, :shard_column
|
6
6
|
|
7
7
|
def initialize
|
8
8
|
@partition_key = Hash.new { |hash, key| hash[key] = :text }
|
@@ -20,8 +20,8 @@ module CassandraModel
|
|
20
20
|
self
|
21
21
|
end
|
22
22
|
|
23
|
-
def shards_queries
|
24
|
-
@
|
23
|
+
def shards_queries(column = :shard)
|
24
|
+
@shard_column = column
|
25
25
|
end
|
26
26
|
|
27
27
|
def composite_rows
|
File without changes
|
File without changes
|
@@ -5,6 +5,10 @@ module CassandraModel
|
|
5
5
|
table_config.display_attributes = map ? map : columns
|
6
6
|
end
|
7
7
|
|
8
|
+
def filter_display_attributes(*filter_columns)
|
9
|
+
table_config.display_attributes = columns - filter_columns
|
10
|
+
end
|
11
|
+
|
8
12
|
def displayable_attributes
|
9
13
|
table_config.display_attributes
|
10
14
|
end
|
@@ -19,18 +23,42 @@ module CassandraModel
|
|
19
23
|
if displayable_attributes
|
20
24
|
displayable_attributes.is_a?(Hash) ? mapped_as_json : sliced_displayable_attributes
|
21
25
|
else
|
22
|
-
|
26
|
+
json_attributes
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
26
30
|
private
|
27
31
|
|
32
|
+
def json_attributes
|
33
|
+
json_attributes = attributes.keys.inject({}) do |memo, column|
|
34
|
+
case column_type(column)
|
35
|
+
when :blob
|
36
|
+
when :timestamp
|
37
|
+
memo[column] = attributes[column].to_i
|
38
|
+
when :timeuuid
|
39
|
+
memo[column] = attributes[column].to_s
|
40
|
+
when :uuid
|
41
|
+
memo[column] = attributes[column].to_s
|
42
|
+
else
|
43
|
+
memo[column] = attributes[column]
|
44
|
+
end
|
45
|
+
memo
|
46
|
+
end
|
47
|
+
self.class.deferred_columns.inject(json_attributes) do |memo, column|
|
48
|
+
memo.merge!(column => public_send(column))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def column_type(column)
|
53
|
+
self.class.cassandra_columns[self.class.select_column(column)]
|
54
|
+
end
|
55
|
+
|
28
56
|
def mapped_as_json
|
29
57
|
sliced_displayable_attributes.inject({}) { |memo, (key, value)| memo.merge!(displayable_attributes[key] => value) }
|
30
58
|
end
|
31
59
|
|
32
60
|
def sliced_displayable_attributes
|
33
|
-
|
61
|
+
json_attributes.slice(*displayable_attributes_slice)
|
34
62
|
end
|
35
63
|
|
36
64
|
def displayable_attributes_slice
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -82,15 +82,11 @@ module CassandraModel
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def select(*columns)
|
85
|
-
|
86
|
-
@options[:select].concat(columns)
|
87
|
-
self
|
85
|
+
append_option(columns, :select)
|
88
86
|
end
|
89
87
|
|
90
88
|
def order(*columns)
|
91
|
-
|
92
|
-
@options[:order_by].concat(columns)
|
93
|
-
self
|
89
|
+
append_option(columns, :order_by)
|
94
90
|
end
|
95
91
|
|
96
92
|
def limit(limit)
|
@@ -110,6 +106,19 @@ module CassandraModel
|
|
110
106
|
|
111
107
|
private
|
112
108
|
|
109
|
+
def append_option(columns, option)
|
110
|
+
@options[option] ||= []
|
111
|
+
if columns.first.is_a?(Hash)
|
112
|
+
columns = columns.first.map do |column, direction|
|
113
|
+
{column => direction}
|
114
|
+
end
|
115
|
+
@options[option].concat(columns)
|
116
|
+
else
|
117
|
+
@options[option].concat(columns)
|
118
|
+
end
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
113
122
|
def pluck_values(columns, result)
|
114
123
|
result.attributes.slice(*columns).values
|
115
124
|
end
|
File without changes
|
File without changes
|
@@ -19,6 +19,8 @@ module CassandraModel
|
|
19
19
|
timeout: 10
|
20
20
|
}.freeze
|
21
21
|
|
22
|
+
include ConcurrencyHelper
|
23
|
+
|
22
24
|
def initialize(config_name = nil)
|
23
25
|
@config_name = config_name
|
24
26
|
@statement_cache = {}
|
@@ -127,20 +129,6 @@ module CassandraModel
|
|
127
129
|
end
|
128
130
|
end
|
129
131
|
|
130
|
-
def safe_getset_variable(mutex, name, &block)
|
131
|
-
result = instance_variable_get(name)
|
132
|
-
return result if result
|
133
|
-
|
134
|
-
mutex.synchronize do
|
135
|
-
raise Cassandra::Errors::InvalidError.new('Connection invalidated!', 'Dummy') if !!@shutdown
|
136
|
-
|
137
|
-
result = instance_variable_get(name)
|
138
|
-
return result if result
|
139
|
-
|
140
|
-
instance_variable_set(name, block.call)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
132
|
def load_config
|
145
133
|
if File.exists?(config_path)
|
146
134
|
config = yaml_config || {}
|
@@ -3,9 +3,10 @@ require_relative 'meta_columns'
|
|
3
3
|
|
4
4
|
module CassandraModel
|
5
5
|
class Record
|
6
|
-
extend
|
7
|
-
include
|
8
|
-
include
|
6
|
+
extend QueryHelper
|
7
|
+
include MetaColumns
|
8
|
+
include DisplayableAttributes
|
9
|
+
include RecordDebug
|
9
10
|
|
10
11
|
attr_reader :attributes, :valid, :execution_info
|
11
12
|
|
@@ -25,6 +26,8 @@ module CassandraModel
|
|
25
26
|
:composite_primary_key,
|
26
27
|
|
27
28
|
:composite_shard_key,
|
29
|
+
|
30
|
+
:cassandra_columns,
|
28
31
|
) # Using this instead of OpenStruct, as there seems to be a bug in JRuby that causes this to get mangled over time
|
29
32
|
ConfigureableAttributes = Struct.new(
|
30
33
|
:table_name,
|
@@ -116,9 +119,21 @@ module CassandraModel
|
|
116
119
|
end
|
117
120
|
|
118
121
|
def inspected_attributes
|
119
|
-
|
120
|
-
|
121
|
-
end
|
122
|
+
columns = self.class.cassandra_columns.map do |column, type|
|
123
|
+
self.class.normalized_column(column) unless type == :blob
|
124
|
+
end.compact.uniq
|
125
|
+
|
126
|
+
base_attributes = columns.map do |column|
|
127
|
+
if (value = attributes[column])
|
128
|
+
%Q{#{column}: "#{value.to_s.truncate(53)}"}
|
129
|
+
else
|
130
|
+
"#{column}: (empty)"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
base_attributes += deferred_columns.map do |column|
|
134
|
+
%Q{#{column}: "#{public_send(column)}"}
|
135
|
+
end
|
136
|
+
base_attributes * ', '
|
122
137
|
end
|
123
138
|
|
124
139
|
protected
|
@@ -232,17 +247,56 @@ module CassandraModel
|
|
232
247
|
|
233
248
|
def save_row_async(options)
|
234
249
|
statement = statement(query_for_save(options))
|
250
|
+
save_column_values = column_values
|
251
|
+
|
252
|
+
validation_error = validate_primary_key!(statement, save_column_values)
|
253
|
+
return validation_error if validation_error
|
254
|
+
|
235
255
|
future = if batch_reactor
|
236
|
-
execute_async_in_batch(statement,
|
256
|
+
execute_async_in_batch(statement, save_column_values)
|
237
257
|
else
|
238
|
-
session.execute_async(statement, *
|
258
|
+
session.execute_async(statement, *save_column_values, write_query_options(options))
|
239
259
|
end
|
240
260
|
future.on_failure do |error|
|
241
|
-
|
242
|
-
execute_callback(:save_record_failed, error)
|
261
|
+
handle_save_error(error, save_column_values, statement)
|
243
262
|
end
|
244
263
|
end
|
245
264
|
|
265
|
+
def validate_primary_key!(statement, save_column_values)
|
266
|
+
missing_primary_columns = invalid_primary_key_parts
|
267
|
+
if missing_primary_columns.present?
|
268
|
+
error = invalid_key_error(missing_primary_columns, statement)
|
269
|
+
handle_save_error(error, save_column_values, statement)
|
270
|
+
Cassandra::Future.error(error)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def handle_save_error(error, save_column_values, statement)
|
275
|
+
Logging.logger.error("Error saving #{self.class}: #{error}")
|
276
|
+
execute_callback(:save_record_failed, error, statement, save_column_values)
|
277
|
+
end
|
278
|
+
|
279
|
+
def invalid_key_error(missing_primary_columns, statement)
|
280
|
+
Cassandra::Errors::InvalidError.new(missing_key_message(missing_primary_columns), statement)
|
281
|
+
end
|
282
|
+
|
283
|
+
def missing_key_message(missing_primary_columns)
|
284
|
+
"Invalid primary key parts #{missing_primary_columns.map(&:to_s).map(&:inspect) * ', '}"
|
285
|
+
end
|
286
|
+
|
287
|
+
def invalid_primary_key_parts
|
288
|
+
save_attributes = internal_attributes
|
289
|
+
if self.class.internal_partition_key.one? && save_attributes[internal_partition_key_part_one].blank?
|
290
|
+
[internal_partition_key_part_one]
|
291
|
+
else
|
292
|
+
self.class.internal_primary_key.select { |value| save_attributes[value].nil? }
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def internal_partition_key_part_one
|
297
|
+
self.class.internal_partition_key.first
|
298
|
+
end
|
299
|
+
|
246
300
|
def execute_callback(callback, *extra_params)
|
247
301
|
GlobalCallbacks.call(callback, self, *extra_params)
|
248
302
|
end
|
@@ -369,6 +423,32 @@ module CassandraModel
|
|
369
423
|
|
370
424
|
alias :create! :create
|
371
425
|
|
426
|
+
def restriction_attributes(restriction)
|
427
|
+
restriction
|
428
|
+
end
|
429
|
+
|
430
|
+
def normalized_column(column)
|
431
|
+
column.to_sym
|
432
|
+
end
|
433
|
+
|
434
|
+
def normalized_attributes(attributes)
|
435
|
+
attributes.symbolize_keys
|
436
|
+
end
|
437
|
+
|
438
|
+
def select_columns(columns)
|
439
|
+
columns
|
440
|
+
end
|
441
|
+
|
442
|
+
def select_column(column)
|
443
|
+
column
|
444
|
+
end
|
445
|
+
|
446
|
+
def cassandra_columns
|
447
|
+
table_data.cassandra_columns ||= table.connection.keyspace.table(table_name).columns.inject({}) do |memo, column|
|
448
|
+
memo.merge!(column.name.to_sym => column.type)
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
372
452
|
def request_async(clause, options = {})
|
373
453
|
page_size = options[:page_size]
|
374
454
|
trace = options[:trace]
|
@@ -398,7 +478,18 @@ module CassandraModel
|
|
398
478
|
end
|
399
479
|
|
400
480
|
def order_by_clause(order_by)
|
401
|
-
|
481
|
+
if order_by
|
482
|
+
order_by = [order_by] unless order_by.is_a?(Array)
|
483
|
+
ordering_columns = order_by.map do |column|
|
484
|
+
if column.is_a?(Hash)
|
485
|
+
column, direction = column.first
|
486
|
+
"#{column} #{direction.upcase}"
|
487
|
+
else
|
488
|
+
column
|
489
|
+
end
|
490
|
+
end
|
491
|
+
" ORDER BY #{multi_csv_clause(ordering_columns)}"
|
492
|
+
end
|
402
493
|
end
|
403
494
|
|
404
495
|
def first_async(clause = {}, options = {})
|
@@ -526,14 +617,10 @@ module CassandraModel
|
|
526
617
|
end
|
527
618
|
|
528
619
|
def record_from_result(row, execution_info, invalidate_result)
|
529
|
-
attributes =
|
620
|
+
attributes = normalized_attributes(row)
|
530
621
|
new(attributes, execution_info: execution_info).tap { |result| result.invalidate! if invalidate_result }
|
531
622
|
end
|
532
623
|
|
533
|
-
def row_attributes(row)
|
534
|
-
row.symbolize_keys
|
535
|
-
end
|
536
|
-
|
537
624
|
def manual_shard(&block)
|
538
625
|
before_save { attributes[shard_key] = instance_eval(&block) }
|
539
626
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CassandraModel
|
2
|
+
module RecordDebug
|
3
|
+
DebugDump = Struct.new(
|
4
|
+
:record,
|
5
|
+
:klass,
|
6
|
+
:table,
|
7
|
+
:table_config,
|
8
|
+
:table_data,
|
9
|
+
:attributes,
|
10
|
+
:internal_attributes,
|
11
|
+
)
|
12
|
+
|
13
|
+
def debug
|
14
|
+
DebugDump.new(
|
15
|
+
self,
|
16
|
+
self.class,
|
17
|
+
self.class.table,
|
18
|
+
self.class.send(:table_config),
|
19
|
+
self.class.send(:table_data),
|
20
|
+
attributes,
|
21
|
+
internal_attributes,
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
File without changes
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module CassandraModel
|
2
2
|
class RotatingTable
|
3
3
|
extend Forwardable
|
4
|
+
include TableDebug
|
4
5
|
|
5
6
|
def_delegators :first_table, :primary_key, :partition_key, :clustering_columns, :columns
|
6
7
|
def_delegators :table, :connection, :name, :truncate!
|
@@ -14,6 +15,7 @@ module CassandraModel
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def allow_truncation!
|
18
|
+
@allow_truncation = true
|
17
19
|
tables.each(&:allow_truncation!)
|
18
20
|
end
|
19
21
|
|
@@ -46,4 +48,4 @@ module CassandraModel
|
|
46
48
|
end
|
47
49
|
|
48
50
|
end
|
49
|
-
end
|
51
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module CassandraModel
|
2
|
+
module TableDebug
|
3
|
+
Debug = Struct.new(
|
4
|
+
:name,
|
5
|
+
:table,
|
6
|
+
:rotating_tables,
|
7
|
+
:first_table,
|
8
|
+
:connection_name,
|
9
|
+
:connection,
|
10
|
+
:partition_key,
|
11
|
+
:clustering_columns,
|
12
|
+
:primary_key,
|
13
|
+
:columns,
|
14
|
+
:allows_truncation?,
|
15
|
+
:rotating_schedule,
|
16
|
+
)
|
17
|
+
|
18
|
+
def debug
|
19
|
+
first_table = (@tables.first if @tables)
|
20
|
+
Debug.new(
|
21
|
+
name,
|
22
|
+
table,
|
23
|
+
@tables,
|
24
|
+
first_table,
|
25
|
+
@connection_name,
|
26
|
+
connection,
|
27
|
+
partition_key,
|
28
|
+
clustering_columns,
|
29
|
+
primary_key,
|
30
|
+
columns,
|
31
|
+
!!@allow_truncation,
|
32
|
+
@schedule,
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -2,12 +2,19 @@ module CassandraModel
|
|
2
2
|
class TableDefinition
|
3
3
|
attr_reader :name
|
4
4
|
|
5
|
-
def self.from_data_model(
|
5
|
+
def self.from_data_model(table_name, inquirer, data_set)
|
6
6
|
partition_key = inquirer_partition_key(inquirer)
|
7
|
-
|
7
|
+
if inquirer.shard_column
|
8
|
+
if inquirer.shard_column.is_a?(Hash)
|
9
|
+
column_name, type = inquirer.shard_column.first
|
10
|
+
partition_key.merge!(:"rk_#{column_name}" => type)
|
11
|
+
else
|
12
|
+
partition_key.merge!(:"rk_#{inquirer.shard_column}" => :int)
|
13
|
+
end
|
14
|
+
end
|
8
15
|
clustering_columns = table_set_clustering_columns(data_set)
|
9
16
|
remaining_columns = table_set_remaining_columns(data_set)
|
10
|
-
new(name:
|
17
|
+
new(name: table_name, partition_key: partition_key,
|
11
18
|
clustering_columns: clustering_columns,
|
12
19
|
remaining_columns: remaining_columns)
|
13
20
|
end
|
File without changes
|
@@ -13,21 +13,21 @@ module TypeGuessing
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def postfix_type
|
16
|
-
if column =~ /
|
16
|
+
if column =~ /(^|_)at$/
|
17
17
|
:timestamp
|
18
|
-
elsif column =~ /
|
18
|
+
elsif column =~ /(^|_)at_id$/
|
19
19
|
:timeuuid
|
20
|
-
elsif column =~ /
|
20
|
+
elsif column =~ /(^|_)id$/
|
21
21
|
:uuid
|
22
|
-
elsif column =~ /_(price|average|stddev)$/
|
22
|
+
elsif column =~ /(^|_)(price|average|stddev)$/
|
23
23
|
:double
|
24
|
-
elsif column =~ /_(total|count)$/
|
24
|
+
elsif column =~ /(^|_)(total|count)$/
|
25
25
|
counter_type
|
26
|
-
elsif column =~ /_(year|day|month|index)$/
|
26
|
+
elsif column =~ /(^|_)(year|day|month|index)$/
|
27
27
|
:int
|
28
|
-
elsif column =~ /
|
28
|
+
elsif column =~ /(^|_)data/
|
29
29
|
:blob
|
30
|
-
elsif column =~ /
|
30
|
+
elsif column =~ /(^|_)map$/
|
31
31
|
'map<string, string>'
|
32
32
|
end
|
33
33
|
end
|
data/lib/cassandra_model.rb
CHANGED
@@ -14,11 +14,16 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
#++
|
16
16
|
|
17
|
+
require 'yaml'
|
18
|
+
require 'logger'
|
17
19
|
require 'concurrent'
|
18
20
|
require 'cassandra'
|
21
|
+
require 'thomas_utils'
|
22
|
+
require 'batch_reactor'
|
19
23
|
require 'active_support/all'
|
20
24
|
require 'active_support/core_ext/class/attribute_accessors'
|
21
25
|
|
26
|
+
require 'cassandra_model/concurrency_helper'
|
22
27
|
require 'cassandra_model/logging'
|
23
28
|
require 'cassandra_model/global_callbacks'
|
24
29
|
require 'cassandra_model/single_token_batch'
|
@@ -30,11 +35,13 @@ require 'cassandra_model/batch_reactor/future'
|
|
30
35
|
require 'cassandra_model/raw_connection'
|
31
36
|
require 'cassandra_model/connection_cache'
|
32
37
|
require 'cassandra_model/table_definition'
|
38
|
+
require 'cassandra_model/table_debug'
|
33
39
|
require 'cassandra_model/table_redux'
|
34
40
|
require 'cassandra_model/result_paginator'
|
35
41
|
require 'cassandra_model/query_result'
|
36
42
|
require 'cassandra_model/query_builder'
|
37
43
|
require 'cassandra_model/displayable_attributes'
|
44
|
+
require 'cassandra_model/record_debug'
|
38
45
|
require 'cassandra_model/record'
|
39
46
|
require 'cassandra_model/counter_record'
|
40
47
|
require 'cassandra_model/table_descriptor'
|
metadata
CHANGED
@@ -1,69 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cassandra_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas RM Rogers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cassandra-driver
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '4.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '4.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: batch_reactor
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 0.0.1
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.0.1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: thomas_utils
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 0.1.13
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 0.1.13
|
69
69
|
description: |-
|
@@ -81,6 +81,7 @@ files:
|
|
81
81
|
- lib/cassandra_model/batch_reactor/future.rb
|
82
82
|
- lib/cassandra_model/composite_record.rb
|
83
83
|
- lib/cassandra_model/composite_record_static.rb
|
84
|
+
- lib/cassandra_model/concurrency_helper.rb
|
84
85
|
- lib/cassandra_model/connection_cache.rb
|
85
86
|
- lib/cassandra_model/counter_record.rb
|
86
87
|
- lib/cassandra_model/data_inquirer.rb
|
@@ -96,12 +97,14 @@ files:
|
|
96
97
|
- lib/cassandra_model/query_result.rb
|
97
98
|
- lib/cassandra_model/raw_connection.rb
|
98
99
|
- lib/cassandra_model/record.rb
|
100
|
+
- lib/cassandra_model/record_debug.rb
|
99
101
|
- lib/cassandra_model/result_paginator.rb
|
100
102
|
- lib/cassandra_model/rotating_table.rb
|
101
103
|
- lib/cassandra_model/single_token_batch.rb
|
102
104
|
- lib/cassandra_model/single_token_counter_batch.rb
|
103
105
|
- lib/cassandra_model/single_token_logged_batch.rb
|
104
106
|
- lib/cassandra_model/single_token_unlogged_batch.rb
|
107
|
+
- lib/cassandra_model/table_debug.rb
|
105
108
|
- lib/cassandra_model/table_definition.rb
|
106
109
|
- lib/cassandra_model/table_descriptor.rb
|
107
110
|
- lib/cassandra_model/table_redux.rb
|
@@ -116,12 +119,12 @@ require_paths:
|
|
116
119
|
- lib
|
117
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
118
121
|
requirements:
|
119
|
-
- -
|
122
|
+
- - ">="
|
120
123
|
- !ruby/object:Gem::Version
|
121
124
|
version: '0'
|
122
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
126
|
requirements:
|
124
|
-
- -
|
127
|
+
- - ">="
|
125
128
|
- !ruby/object:Gem::Version
|
126
129
|
version: '0'
|
127
130
|
requirements: []
|