extendi-cassandra_object 1.0.0

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 (104) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.travis.yml +23 -0
  4. data/CHANGELOG +0 -0
  5. data/Gemfile +17 -0
  6. data/LICENSE +13 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +177 -0
  9. data/Rakefile +12 -0
  10. data/extendi-cassandra_object.gemspec +26 -0
  11. data/lib/cassandra_object.rb +73 -0
  12. data/lib/cassandra_object/adapters/abstract_adapter.rb +61 -0
  13. data/lib/cassandra_object/adapters/cassandra_adapter.rb +269 -0
  14. data/lib/cassandra_object/adapters/cassandra_schemaless_adapter.rb +306 -0
  15. data/lib/cassandra_object/attribute_methods.rb +96 -0
  16. data/lib/cassandra_object/attribute_methods/definition.rb +22 -0
  17. data/lib/cassandra_object/attribute_methods/dirty.rb +36 -0
  18. data/lib/cassandra_object/attribute_methods/primary_key.rb +25 -0
  19. data/lib/cassandra_object/attribute_methods/typecasting.rb +59 -0
  20. data/lib/cassandra_object/base.rb +33 -0
  21. data/lib/cassandra_object/base_schema.rb +11 -0
  22. data/lib/cassandra_object/base_schemaless.rb +11 -0
  23. data/lib/cassandra_object/base_schemaless_dynamic.rb +11 -0
  24. data/lib/cassandra_object/belongs_to.rb +63 -0
  25. data/lib/cassandra_object/belongs_to/association.rb +49 -0
  26. data/lib/cassandra_object/belongs_to/builder.rb +40 -0
  27. data/lib/cassandra_object/belongs_to/reflection.rb +30 -0
  28. data/lib/cassandra_object/callbacks.rb +29 -0
  29. data/lib/cassandra_object/core.rb +63 -0
  30. data/lib/cassandra_object/errors.rb +10 -0
  31. data/lib/cassandra_object/identity.rb +26 -0
  32. data/lib/cassandra_object/inspect.rb +25 -0
  33. data/lib/cassandra_object/log_subscriber.rb +44 -0
  34. data/lib/cassandra_object/model.rb +60 -0
  35. data/lib/cassandra_object/persistence.rb +203 -0
  36. data/lib/cassandra_object/railtie.rb +33 -0
  37. data/lib/cassandra_object/railties/controller_runtime.rb +45 -0
  38. data/lib/cassandra_object/schema.rb +83 -0
  39. data/lib/cassandra_object/schemaless.rb +83 -0
  40. data/lib/cassandra_object/scope.rb +86 -0
  41. data/lib/cassandra_object/scope/finder_methods.rb +54 -0
  42. data/lib/cassandra_object/scope/query_methods.rb +69 -0
  43. data/lib/cassandra_object/scoping.rb +27 -0
  44. data/lib/cassandra_object/serialization.rb +6 -0
  45. data/lib/cassandra_object/tasks/ks.rake +54 -0
  46. data/lib/cassandra_object/timestamps.rb +19 -0
  47. data/lib/cassandra_object/type.rb +16 -0
  48. data/lib/cassandra_object/types.rb +8 -0
  49. data/lib/cassandra_object/types/array_type.rb +16 -0
  50. data/lib/cassandra_object/types/base_type.rb +26 -0
  51. data/lib/cassandra_object/types/boolean_type.rb +20 -0
  52. data/lib/cassandra_object/types/date_type.rb +22 -0
  53. data/lib/cassandra_object/types/float_type.rb +16 -0
  54. data/lib/cassandra_object/types/integer_type.rb +20 -0
  55. data/lib/cassandra_object/types/json_type.rb +13 -0
  56. data/lib/cassandra_object/types/string_type.rb +19 -0
  57. data/lib/cassandra_object/types/time_type.rb +16 -0
  58. data/lib/cassandra_object/types/type_helper.rb +39 -0
  59. data/lib/cassandra_object/validations.rb +44 -0
  60. data/test/support/cassandra.rb +63 -0
  61. data/test/support/issue.rb +12 -0
  62. data/test/support/issue_dynamic.rb +12 -0
  63. data/test/support/issue_schema.rb +17 -0
  64. data/test/support/issue_schema_child.rb +17 -0
  65. data/test/support/issue_schema_father.rb +13 -0
  66. data/test/test_helper.rb +41 -0
  67. data/test/unit/active_model_test.rb +18 -0
  68. data/test/unit/adapters/adapter_test.rb +6 -0
  69. data/test/unit/attribute_methods/definition_test.rb +13 -0
  70. data/test/unit/attribute_methods/dirty_test.rb +72 -0
  71. data/test/unit/attribute_methods/primary_key_test.rb +26 -0
  72. data/test/unit/attribute_methods/typecasting_test.rb +119 -0
  73. data/test/unit/attribute_methods_test.rb +51 -0
  74. data/test/unit/base_test.rb +20 -0
  75. data/test/unit/belongs_to/reflection_test.rb +12 -0
  76. data/test/unit/belongs_to_test.rb +63 -0
  77. data/test/unit/callbacks_test.rb +46 -0
  78. data/test/unit/connection_test.rb +6 -0
  79. data/test/unit/connections/connections_test.rb +55 -0
  80. data/test/unit/core_test.rb +55 -0
  81. data/test/unit/identity_test.rb +26 -0
  82. data/test/unit/inspect_test.rb +26 -0
  83. data/test/unit/log_subscriber_test.rb +25 -0
  84. data/test/unit/persistence_schema_test.rb +156 -0
  85. data/test/unit/persistence_test.rb +266 -0
  86. data/test/unit/railties/controller_runtime_test.rb +48 -0
  87. data/test/unit/schema/tasks_test.rb +32 -0
  88. data/test/unit/schema_test.rb +115 -0
  89. data/test/unit/schemaless_test.rb +100 -0
  90. data/test/unit/scope/finder_methods_test.rb +117 -0
  91. data/test/unit/scope/query_methods_test.rb +32 -0
  92. data/test/unit/scoping_test.rb +7 -0
  93. data/test/unit/timestamps_test.rb +27 -0
  94. data/test/unit/types/array_type_test.rb +17 -0
  95. data/test/unit/types/base_type_test.rb +19 -0
  96. data/test/unit/types/boolean_type_test.rb +24 -0
  97. data/test/unit/types/date_type_test.rb +15 -0
  98. data/test/unit/types/float_type_test.rb +17 -0
  99. data/test/unit/types/integer_type_test.rb +19 -0
  100. data/test/unit/types/json_type_test.rb +23 -0
  101. data/test/unit/types/string_type_test.rb +25 -0
  102. data/test/unit/types/time_type_test.rb +14 -0
  103. data/test/unit/validations_test.rb +27 -0
  104. metadata +202 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b77415cb2c51774f219ad7ea643874e4186f1f22
4
+ data.tar.gz: 12ee0bc7d6a6f32e2649643966ebd76bd5aa89d3
5
+ SHA512:
6
+ metadata.gz: 5ebe0edf6aca769e39f7cfbf226ebad99aa7cd9d1d26d4d311fce86d530276d050bfe277a71627d1d1a9e8cce1570823668a646ea1aa8e51e40d88e9ee00f974
7
+ data.tar.gz: 1d291cc9b6e5c1c34020effa7372fb11787dfac4aab5c02cc5c8110569c1015cb3bbd7551d207da2a6510c0389ecaef870ecbfe8db78861bcc7434b48e071ee8
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ Gemfile.lock
2
+ *.gem
3
+ .idea
4
+ .byebug_history
5
+ .ruby-version
data/.travis.yml ADDED
@@ -0,0 +1,23 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.3
4
+ - 2.4.0
5
+ env:
6
+ - CASSANDRA_VERSION=2.1.2
7
+ - CASSANDRA_VERSION=3.0.10
8
+ - CASSANDRA_VERSION=3.9
9
+
10
+ jdk:
11
+ - oraclejdk8
12
+
13
+ before_install:
14
+ - sudo apt-get install libjna-java
15
+ - sudo apt-get install python-support
16
+ - sudo easy_install pyYaml
17
+ - sudo easy_install pip
18
+ - sudo pip install ccm
19
+
20
+ install:
21
+ - ccm create -n 1 -v $CASSANDRA_VERSION -i 127.0.0. -s -b test-cluster
22
+ - ccm start
23
+ - bundle install
data/CHANGELOG ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'rake'
5
+ gem 'thin'
6
+
7
+ group :test do
8
+ gem 'rails'
9
+ gem 'mocha', require: false
10
+ gem 'snappy'
11
+ gem 'lz4-ruby'
12
+ gem 'byebug'
13
+ end
14
+
15
+ group :cassandra do
16
+ gem 'cassandra-driver'
17
+ end
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2009 Koziarski Software Ltd
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 [Michael Koziarski]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # Cassandra Object
2
+ [![Build Status](https://secure.travis-ci.org/giovannelli/cassandra_object.png)](http://travis-ci.org/giovannelli/cassandra_object) [![Code Climate](https://codeclimate.com/github/giovannelli/cassandra_object/badges/gpa.svg)](https://codeclimate.com/github/giovannelli/cassandra_object)
3
+
4
+ Cassandra Object uses ActiveModel to mimic much of the behavior in ActiveRecord.
5
+ Use cql3 provided by ruby-driver gem and uses the old thrift structure with the possible option at [this link](https://docs.datastax.com/en/cql/3.1/cql/cql_reference/create_table_r.html?hl=create%2Ctable):
6
+
7
+ ```shell
8
+
9
+ CREATE TABLE keyspace.table (
10
+ key text,
11
+ column1 text,
12
+ value blob,
13
+ PRIMARY KEY (key, column1)
14
+ ) WITH
15
+ COMPACT STORAGE
16
+ AND CLUSTERING ORDER BY (column1 ASC)
17
+ AND bloom_filter_fp_chance = 0.001
18
+ AND caching = '{"keys":"ALL", "rows_per_partition":"NONE"}'
19
+ AND comment = ''
20
+ AND compaction = {'min_sstable_size': '52428800', 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'}
21
+ AND compression = {'chunk_length_kb': '64', 'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'}
22
+ AND dclocal_read_repair_chance = 0.0
23
+ AND default_time_to_live = 0
24
+ AND gc_grace_seconds = 864000
25
+ AND max_index_interval = 2048
26
+ AND memtable_flush_period_in_ms = 0
27
+ AND min_index_interval = 128
28
+ AND read_repair_chance = 1.0
29
+ AND speculative_retry = 'NONE';
30
+ ```
31
+
32
+ You can also use the a custom schema structure with the possible options at [this link](https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlCreateTable.html#tabProp):
33
+
34
+ ```shell
35
+
36
+ CREATE TABLE keyspace.table (
37
+ key text,
38
+ field1 text,
39
+ field2 varchar,
40
+ field3 float,
41
+ PRIMARY KEY (key)
42
+ ) WITH
43
+ bloom_filter_fp_chance = 0.001
44
+ AND caching = {'keys':'ALL', 'rows_per_partition':'NONE'}'
45
+ AND comment = ''
46
+ AND compaction = {'min_sstable_size': '52428800', 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'}
47
+ AND compression = {'chunk_length_kb': '64', 'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'}
48
+ AND dclocal_read_repair_chance = 0.0
49
+ AND default_time_to_live = 0
50
+ AND gc_grace_seconds = 864000
51
+ AND max_index_interval = 2048
52
+ AND memtable_flush_period_in_ms = 0
53
+ AND min_index_interval = 128
54
+ AND read_repair_chance = 1.0
55
+ AND speculative_retry = 'NONE';
56
+ ```
57
+
58
+ ## Installation
59
+
60
+ Add the following to your Gemfile:
61
+ ```ruby
62
+ gem 'extendi-cassandra_object'
63
+ ```
64
+
65
+ Change the version of Cassandra accordingly. Recent versions have not been backward compatible.
66
+
67
+ ## Defining Models
68
+
69
+ Schemaless model:
70
+ ```ruby
71
+ class Widget < CassandraObject::BaseSchemaless
72
+ string :name
73
+ string :description
74
+ integer :price
75
+ array :colors, unique: true
76
+
77
+ validates :name, presence: :true
78
+
79
+ before_create do
80
+ self.description = "#{name} is the best product ever"
81
+ end
82
+ end
83
+ ```
84
+
85
+ Schemaless with dynamic attributes model:
86
+ ```ruby
87
+ class Widget < CassandraObject::BaseSchemalessDynamic
88
+ string :name
89
+ string :description
90
+ integer :price
91
+ array :colors, unique: true
92
+
93
+ validates :name, presence: :true
94
+
95
+ before_create do
96
+ self.description = "#{name} is the best product ever"
97
+ end
98
+ end
99
+ ```
100
+
101
+ Schema model:
102
+ ```ruby
103
+ class Widget < CassandraObject::BaseSchema
104
+ string :name
105
+ string :description
106
+ integer :price
107
+ array :colors, unique: true
108
+
109
+ validates :name, presence: :true
110
+
111
+ before_create do
112
+ self.description = "#{name} is the best product ever"
113
+ end
114
+ end
115
+ ```
116
+ ## Using with Cassandra
117
+
118
+ Add a config/cassandra.yml:
119
+
120
+ ```yaml
121
+ development:
122
+ keyspace: my_app_development
123
+ hosts: ["127.0.0.1"]
124
+ compression: :lz4,
125
+ connect_timeout: 0.1,
126
+ request_timeout: 0.1,
127
+ consistency: :any/:one/:two/:three/:quorum/:all/:local_quorum/:each_quorum/:serial/:local_serial/:local_one,
128
+ protocol_version: 3,
129
+ page_size: 10000,
130
+ trace: true/false
131
+ ```
132
+
133
+ ## Creating and updating records
134
+
135
+ Cassandra Object has equivalent methods as ActiveRecord:
136
+
137
+ ```ruby
138
+ widget = Widget.new
139
+ widget.valid?
140
+ widget = Widget.create(name: 'Acme', price: 100)
141
+ widget.update_attribute(:price, 1200)
142
+ widget.update_attributes(price: 1200, name: 'Acme Corporation')
143
+ widget.attributes = {price: 300}
144
+ widget.price_was
145
+ widget.save
146
+ widget.save!
147
+ ```
148
+
149
+ ## Finding records
150
+
151
+ ```ruby
152
+ widget = Widget.find(uuid)
153
+ widget = Widget.first
154
+ widgets = Widget.all
155
+ Widget.find_each do |widget|
156
+ # Codez
157
+ end
158
+ ```
159
+
160
+ ## Scoping
161
+
162
+ Some lightweight scoping features are available:
163
+ ```ruby
164
+ Widget.where(color: :red)
165
+ Widget.select([:name, :color])
166
+ Widget.limit(10)
167
+ ```
168
+
169
+ ## Plain response scoping
170
+
171
+ cql_response return an hash where the key is the model key and values is an hash where key is the column name and the value is the column value.
172
+
173
+ ```ruby
174
+ Widget.cql_response.where(color: :red)
175
+ Widget.cql_response([:name, :color])
176
+ Widget.cql_response.limit(10)
177
+ ```
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler/setup'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ task default: :test
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << 'lib'
9
+ t.libs << 'test'
10
+ t.pattern = 'test/unit/**/*_test.rb'
11
+ t.verbose = true
12
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'extendi-cassandra_object'
5
+ s.version = '1.0.0'
6
+ s.description = 'Cassandra ActiveModel'
7
+ s.summary = 'Cassandra ActiveModel'
8
+ s.authors = ['Duccio Giovannelli', 'gotime']
9
+ s.email = 'giovannelli@extendi.it'
10
+ s.homepage = 'https://github.com/giovannelli/cassandra_object'
11
+
12
+ s.required_ruby_version = '>= 1.9.2'
13
+ s.required_rubygems_version = '>= 1.3.5'
14
+
15
+ s.extra_rdoc_files = ['README.md']
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_runtime_dependency('activemodel', '>= 3.0')
21
+ s.add_runtime_dependency('cassandra-driver', '>= 3.1.0')
22
+ s.add_runtime_dependency('lz4-ruby', '>= 0.3.3')
23
+
24
+ s.platform = Gem::Platform::RUBY
25
+ s.add_development_dependency('bundler')
26
+ end
@@ -0,0 +1,73 @@
1
+ require 'active_support/all'
2
+ require 'active_model'
3
+ require 'cassandra_object/errors'
4
+
5
+ module CassandraObject
6
+ extend ActiveSupport::Autoload
7
+
8
+ autoload :AttributeMethods
9
+ autoload :Base
10
+ autoload :BaseSchema
11
+ autoload :BaseSchemaless
12
+ autoload :BaseSchemalessDynamic
13
+ autoload :BelongsTo
14
+ autoload :Callbacks
15
+ autoload :Connection
16
+ autoload :Core
17
+ autoload :Identity
18
+ autoload :Inspect
19
+ autoload :Model
20
+ autoload :Persistence
21
+ autoload :Schema
22
+ autoload :Schemaless
23
+ autoload :Scope
24
+ autoload :Scoping
25
+ autoload :Serialization
26
+ autoload :Timestamps
27
+ autoload :Type
28
+ autoload :Validations
29
+
30
+ module AttributeMethods
31
+ extend ActiveSupport::Autoload
32
+
33
+ eager_autoload do
34
+ autoload :Definition
35
+ autoload :Dirty
36
+ autoload :PrimaryKey
37
+ autoload :Typecasting
38
+ end
39
+ end
40
+
41
+ module Adapters
42
+ extend ActiveSupport::Autoload
43
+
44
+ autoload :AbstractAdapter
45
+ autoload :CassandraAdapter
46
+ autoload :CassandraSchemalessAdapter
47
+ end
48
+
49
+ module BelongsTo
50
+ extend ActiveSupport::Autoload
51
+
52
+ autoload :Association
53
+ autoload :Builder
54
+ autoload :Reflection
55
+ end
56
+
57
+ module Types
58
+ extend ActiveSupport::Autoload
59
+
60
+ autoload :BaseType
61
+ autoload :ArrayType
62
+ autoload :BooleanType
63
+ autoload :DateType
64
+ autoload :FloatType
65
+ autoload :IntegerType
66
+ autoload :JsonType
67
+ autoload :StringType
68
+ autoload :TimeType
69
+ autoload :TypeHelper
70
+ end
71
+ end
72
+
73
+ require 'cassandra_object/railtie' if defined?(Rails)
@@ -0,0 +1,61 @@
1
+ module CassandraObject
2
+ module Adapters
3
+ class AbstractAdapter
4
+ attr_reader :config
5
+ def initialize(config)
6
+ @config = config
7
+ end
8
+
9
+ # Read records from a instance of CassandraObject::Scope
10
+ def select(scope) # abstract
11
+ end
12
+
13
+ # Insert a new row
14
+ def insert(table, id, attributes) # abstract
15
+ end
16
+
17
+ # Update an existing row
18
+ def update(table, id, attributes) # abstract
19
+ end
20
+
21
+ # Delete rows by an array of ids
22
+ def delete(table, ids) # abstract
23
+ end
24
+
25
+ def execute_batch(statements) # abstract
26
+ end
27
+
28
+ def batching?
29
+ !@batch_statements.nil?
30
+ end
31
+
32
+ def batch
33
+ @batch_statements = []
34
+ yield
35
+ execute_batch(@batch_statements) if !@batch_statements.nil? && @batch_statements.any?
36
+ ensure
37
+ @batch_statements = nil
38
+ end
39
+
40
+ def statement_with_options(stmt, options)
41
+ if options.present?
42
+ with_stmt = options.split(',').map do |o|
43
+ "#{o}"
44
+ end.join(' AND ')
45
+
46
+ stmt = "#{stmt} WITH #{with_stmt}"
47
+ end
48
+ stmt
49
+ end
50
+
51
+ def execute_batchable(statements)
52
+ if defined?(@batch_statements) && @batch_statements
53
+ @batch_statements += statements
54
+ else
55
+ execute_batch(statements)
56
+ end
57
+ end
58
+ end
59
+
60
+ end
61
+ end