cassandra_model 0.9.3.2

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.
Files changed (34) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +13 -0
  3. data/README.md +170 -0
  4. data/lib/cassandra_model.rb +48 -0
  5. data/lib/cassandra_model/batch_reactor.rb +32 -0
  6. data/lib/cassandra_model/batch_reactor/future.rb +49 -0
  7. data/lib/cassandra_model/composite_record.rb +49 -0
  8. data/lib/cassandra_model/composite_record_static.rb +169 -0
  9. data/lib/cassandra_model/connection_cache.rb +24 -0
  10. data/lib/cassandra_model/counter_record.rb +58 -0
  11. data/lib/cassandra_model/data_inquirer.rb +105 -0
  12. data/lib/cassandra_model/data_modelling.rb +45 -0
  13. data/lib/cassandra_model/data_set.rb +84 -0
  14. data/lib/cassandra_model/displayable_attributes.rb +44 -0
  15. data/lib/cassandra_model/global_callbacks.rb +39 -0
  16. data/lib/cassandra_model/logging.rb +8 -0
  17. data/lib/cassandra_model/meta_columns.rb +162 -0
  18. data/lib/cassandra_model/meta_table.rb +66 -0
  19. data/lib/cassandra_model/query_builder.rb +122 -0
  20. data/lib/cassandra_model/query_helper.rb +44 -0
  21. data/lib/cassandra_model/query_result.rb +23 -0
  22. data/lib/cassandra_model/raw_connection.rb +163 -0
  23. data/lib/cassandra_model/record.rb +551 -0
  24. data/lib/cassandra_model/result_paginator.rb +37 -0
  25. data/lib/cassandra_model/rotating_table.rb +49 -0
  26. data/lib/cassandra_model/single_token_batch.rb +23 -0
  27. data/lib/cassandra_model/single_token_counter_batch.rb +5 -0
  28. data/lib/cassandra_model/single_token_logged_batch.rb +5 -0
  29. data/lib/cassandra_model/single_token_unlogged_batch.rb +5 -0
  30. data/lib/cassandra_model/table_definition.rb +72 -0
  31. data/lib/cassandra_model/table_descriptor.rb +49 -0
  32. data/lib/cassandra_model/table_redux.rb +58 -0
  33. data/lib/cassandra_model/type_guessing.rb +40 -0
  34. metadata +133 -0
@@ -0,0 +1,37 @@
1
+ module CassandraModel
2
+ class ResultPaginator
3
+ include Enumerable
4
+
5
+ def initialize(first_page, &callback)
6
+ @page = first_page
7
+ @callback = callback
8
+ end
9
+
10
+ def each(&block)
11
+ return to_enum(:each) unless block_given?
12
+
13
+ each_slice { |slice| slice.each(&block) }
14
+ end
15
+
16
+ def each_slice
17
+ return to_enum(:each_slice) unless block_given?
18
+
19
+ current_page = @page
20
+ loop do
21
+ page_results = current_page.get
22
+ modified_results = page_results.map { |result| @callback.call(result, page_results.execution_info) }
23
+ break if page_results.empty?
24
+ if page_results.last_page?
25
+ yield modified_results
26
+ break
27
+ else
28
+ current_page = page_results.next_page_async
29
+ yield modified_results
30
+ end
31
+ end
32
+ end
33
+
34
+ alias :get :to_a
35
+
36
+ end
37
+ end
@@ -0,0 +1,49 @@
1
+ module CassandraModel
2
+ class RotatingTable
3
+ extend Forwardable
4
+
5
+ def_delegators :first_table, :primary_key, :partition_key, :clustering_columns, :columns
6
+ def_delegators :table, :connection, :name, :truncate!
7
+
8
+ def initialize(tables, schedule)
9
+ columns = tables.first.columns
10
+ raise 'RotatingTable, Table columns do not match' unless valid_tables?(columns, tables)
11
+
12
+ @tables = tables
13
+ @schedule = schedule
14
+ end
15
+
16
+ def allow_truncation!
17
+ tables.each(&:allow_truncation!)
18
+ end
19
+
20
+ def reset_local_schema!
21
+ @tables.reject { |table| table.is_a?(MetaTable) }.each(&:reset_local_schema!)
22
+ end
23
+
24
+ def ==(rhs)
25
+ @schedule == rhs.schedule &&
26
+ @tables == rhs.tables
27
+ end
28
+
29
+ protected
30
+
31
+ attr_reader :schedule, :tables
32
+
33
+ private
34
+
35
+ def first_table
36
+ @tables.first
37
+ end
38
+
39
+ def table
40
+ index = (Time.now.to_f / @schedule).to_i % @tables.count
41
+ @tables[index]
42
+ end
43
+
44
+ def valid_tables?(columns, tables)
45
+ tables.map(&:columns).reduce(&:|) == columns
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,23 @@
1
+ module CassandraModel
2
+ module SingleTokenBatch
3
+ extend Forwardable
4
+ include Enumerable
5
+
6
+ attr_writer :result
7
+
8
+ def_delegators :result, :execution_info, :empty?, :each
9
+
10
+ def keyspace
11
+ nil
12
+ end
13
+
14
+ def partition_key
15
+ @statements.first.partition_key
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :result
21
+
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module CassandraModel
2
+ class SingleTokenCounterBatch < Cassandra::Statements::Batch::Counter
3
+ include SingleTokenBatch
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module CassandraModel
2
+ class SingleTokenLoggedBatch < Cassandra::Statements::Batch::Logged
3
+ include SingleTokenBatch
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module CassandraModel
2
+ class SingleTokenUnloggedBatch < Cassandra::Statements::Batch::Unlogged
3
+ include SingleTokenBatch
4
+ end
5
+ end
@@ -0,0 +1,72 @@
1
+ module CassandraModel
2
+ class TableDefinition
3
+ attr_reader :name
4
+
5
+ def self.from_data_model(name, inquirer, data_set)
6
+ partition_key = inquirer_partition_key(inquirer)
7
+ partition_key.merge!(rk_shard: :int) if inquirer.is_sharding
8
+ clustering_columns = table_set_clustering_columns(data_set)
9
+ remaining_columns = table_set_remaining_columns(data_set)
10
+ new(name: name, partition_key: partition_key,
11
+ clustering_columns: clustering_columns,
12
+ remaining_columns: remaining_columns)
13
+ end
14
+
15
+ def initialize(options)
16
+ @partition_key = options[:partition_key].keys
17
+ @clustering_columns = options[:clustering_columns].keys
18
+ @name = options[:name]
19
+ @columns = options[:partition_key].merge(options[:clustering_columns].merge(options[:remaining_columns]))
20
+ end
21
+
22
+ def to_cql(options = {})
23
+ table_name = options[:no_id] ? name : name_in_cassandra
24
+ exists = if options[:check_exists]
25
+ 'IF NOT EXISTS '
26
+ end
27
+ "CREATE TABLE #{exists}#{table_name} (#{columns}, PRIMARY KEY #{primary_key})"
28
+ end
29
+
30
+ def table_id
31
+ Digest::MD5.hexdigest(columns)
32
+ end
33
+
34
+ def name_in_cassandra
35
+ "#{name}_#{table_id}"
36
+ end
37
+
38
+ def ==(rhs)
39
+ to_cql == rhs.to_cql
40
+ end
41
+
42
+ private
43
+
44
+ def self.table_set_remaining_columns(data_set)
45
+ data_set.columns.except(*data_set.clustering_columns)
46
+ end
47
+
48
+ def self.table_set_clustering_columns(data_set)
49
+ data_set.clustering_columns.inject({}) do |memo, column|
50
+ memo.merge!(:"ck_#{column}" => data_set.columns[column])
51
+ end
52
+ end
53
+
54
+ def self.inquirer_partition_key(inquirer)
55
+ inquirer.partition_key.inject({}) do |memo, (key, value)|
56
+ memo.merge!(:"rk_#{key}" => value)
57
+ end
58
+ end
59
+
60
+ def columns
61
+ @columns.map { |name, type| "#{name} #{type}" } * ', '
62
+ end
63
+
64
+ def primary_key
65
+ if @clustering_columns.present?
66
+ "((#{@partition_key * ', '}), #{@clustering_columns * ', '})"
67
+ else
68
+ "((#{@partition_key * ', '}))"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,49 @@
1
+ module CassandraModel
2
+ class TableDescriptor < Record
3
+
4
+ class << self
5
+ def create_async(table_definition)
6
+ super(table_descriptor(table_definition), check_exists: true)
7
+ end
8
+
9
+ def create(table_definition)
10
+ create_async(table_definition).get
11
+ end
12
+
13
+ def create_descriptor_table
14
+ session.execute(table_desc.to_cql(no_id: true)) unless descriptor_table_exists?
15
+ end
16
+
17
+ def drop_descriptor_table
18
+ session.execute("DROP TABLE #{table_name}") if descriptor_table_exists?
19
+ end
20
+
21
+ private
22
+
23
+ def descriptor_table_exists?
24
+ table.connection.keyspace.table(table.name)
25
+ end
26
+
27
+ def table_descriptor(table_definition)
28
+ {name: table_definition.name.to_s,
29
+ created_at: rounded_time,
30
+ id: table_definition.table_id}
31
+ end
32
+
33
+ def rounded_time
34
+ Time.at((Time.now.to_i / 1.day) * 1.day)
35
+ end
36
+
37
+ def table_desc
38
+ @table_desc ||= begin
39
+ options = {name: table_name,
40
+ partition_key: {name: :ascii},
41
+ clustering_columns: {id: :ascii},
42
+ remaining_columns: {created_at: :timestamp}}
43
+ TableDefinition.new(options)
44
+ end
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,58 @@
1
+ module CassandraModel
2
+ class TableRedux
3
+ extend Forwardable
4
+
5
+ attr_reader :name
6
+
7
+ def initialize(connection_name = nil, table_name)
8
+ @name = table_name.to_s
9
+ @connection_name = connection_name
10
+ end
11
+
12
+ #noinspection RubyUnusedLocalVariable
13
+ def in_context(time)
14
+ yield self
15
+ end
16
+
17
+ def connection
18
+ ConnectionCache[@connection_name]
19
+ end
20
+
21
+ def allow_truncation!
22
+ @allow_truncation = true
23
+ end
24
+
25
+ def truncate!
26
+ raise "Truncation not enabled for table '#{name}'" unless @allow_truncation
27
+ connection.session.execute("TRUNCATE #{name}")
28
+ end
29
+
30
+ def reset_local_schema!
31
+ @partition_key = nil
32
+ @clustering_columns = nil
33
+ @columns = nil
34
+ end
35
+
36
+ def partition_key
37
+ @partition_key ||= table.send(:partition_key).map { |column| column.name.to_sym }
38
+ end
39
+
40
+ def clustering_columns
41
+ @clustering_columns ||= table.send(:clustering_columns).map { |column| column.name.to_sym }
42
+ end
43
+
44
+ def primary_key
45
+ partition_key + clustering_columns
46
+ end
47
+
48
+ def columns
49
+ @columns ||= table.columns.map { |column| column.name.to_sym }
50
+ end
51
+
52
+ private
53
+
54
+ def table
55
+ connection.keyspace.table(name)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,40 @@
1
+ module TypeGuessing
2
+ def guess_data_types!
3
+ @guess_data_types = true
4
+ end
5
+
6
+ private
7
+
8
+ class DataTypeGuess < Struct.new(:column, :counter_type)
9
+ def guessed_type
10
+ postfix_type || :text
11
+ end
12
+
13
+ private
14
+
15
+ def postfix_type
16
+ if column =~ /_at$/
17
+ :timestamp
18
+ elsif column =~ /_at_id$/
19
+ :timeuuid
20
+ elsif column =~ /_id$/
21
+ :uuid
22
+ elsif column =~ /_(price|average|stddev)$/
23
+ :double
24
+ elsif column =~ /_(total|count)$/
25
+ counter_type
26
+ elsif column =~ /_(year|day|month|index)$/
27
+ :int
28
+ elsif column =~ /_data/
29
+ :blob
30
+ elsif column =~ /_map$/
31
+ 'map<string, string>'
32
+ end
33
+ end
34
+ end
35
+
36
+ def guessed_data_type(column, counter_type)
37
+ DataTypeGuess.new(column, counter_type).guessed_type
38
+ end
39
+
40
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cassandra_model
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.3.2
5
+ platform: ruby
6
+ authors:
7
+ - Thomas RM Rogers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cassandra-driver
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: batch_reactor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.0.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.0.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: thomas_utils
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.13
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.13
69
+ description: |-
70
+ Cassandra data modelling framework for Ruby that makes
71
+ data modelling for Cassandra tables easy, fast, and stable
72
+ email: thomasrogers03@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - LICENSE.txt
78
+ - README.md
79
+ - lib/cassandra_model.rb
80
+ - lib/cassandra_model/batch_reactor.rb
81
+ - lib/cassandra_model/batch_reactor/future.rb
82
+ - lib/cassandra_model/composite_record.rb
83
+ - lib/cassandra_model/composite_record_static.rb
84
+ - lib/cassandra_model/connection_cache.rb
85
+ - lib/cassandra_model/counter_record.rb
86
+ - lib/cassandra_model/data_inquirer.rb
87
+ - lib/cassandra_model/data_modelling.rb
88
+ - lib/cassandra_model/data_set.rb
89
+ - lib/cassandra_model/displayable_attributes.rb
90
+ - lib/cassandra_model/global_callbacks.rb
91
+ - lib/cassandra_model/logging.rb
92
+ - lib/cassandra_model/meta_columns.rb
93
+ - lib/cassandra_model/meta_table.rb
94
+ - lib/cassandra_model/query_builder.rb
95
+ - lib/cassandra_model/query_helper.rb
96
+ - lib/cassandra_model/query_result.rb
97
+ - lib/cassandra_model/raw_connection.rb
98
+ - lib/cassandra_model/record.rb
99
+ - lib/cassandra_model/result_paginator.rb
100
+ - lib/cassandra_model/rotating_table.rb
101
+ - lib/cassandra_model/single_token_batch.rb
102
+ - lib/cassandra_model/single_token_counter_batch.rb
103
+ - lib/cassandra_model/single_token_logged_batch.rb
104
+ - lib/cassandra_model/single_token_unlogged_batch.rb
105
+ - lib/cassandra_model/table_definition.rb
106
+ - lib/cassandra_model/table_descriptor.rb
107
+ - lib/cassandra_model/table_redux.rb
108
+ - lib/cassandra_model/type_guessing.rb
109
+ homepage: https://www.github.com/thomasrogers03/cassandra_model
110
+ licenses:
111
+ - Apache License 2.0
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.4.8
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: Cassandra data modelling framework for Ruby
133
+ test_files: []