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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.travis.yml +23 -0
- data/CHANGELOG +0 -0
- data/Gemfile +17 -0
- data/LICENSE +13 -0
- data/MIT-LICENSE +20 -0
- data/README.md +177 -0
- data/Rakefile +12 -0
- data/extendi-cassandra_object.gemspec +26 -0
- data/lib/cassandra_object.rb +73 -0
- data/lib/cassandra_object/adapters/abstract_adapter.rb +61 -0
- data/lib/cassandra_object/adapters/cassandra_adapter.rb +269 -0
- data/lib/cassandra_object/adapters/cassandra_schemaless_adapter.rb +306 -0
- data/lib/cassandra_object/attribute_methods.rb +96 -0
- data/lib/cassandra_object/attribute_methods/definition.rb +22 -0
- data/lib/cassandra_object/attribute_methods/dirty.rb +36 -0
- data/lib/cassandra_object/attribute_methods/primary_key.rb +25 -0
- data/lib/cassandra_object/attribute_methods/typecasting.rb +59 -0
- data/lib/cassandra_object/base.rb +33 -0
- data/lib/cassandra_object/base_schema.rb +11 -0
- data/lib/cassandra_object/base_schemaless.rb +11 -0
- data/lib/cassandra_object/base_schemaless_dynamic.rb +11 -0
- data/lib/cassandra_object/belongs_to.rb +63 -0
- data/lib/cassandra_object/belongs_to/association.rb +49 -0
- data/lib/cassandra_object/belongs_to/builder.rb +40 -0
- data/lib/cassandra_object/belongs_to/reflection.rb +30 -0
- data/lib/cassandra_object/callbacks.rb +29 -0
- data/lib/cassandra_object/core.rb +63 -0
- data/lib/cassandra_object/errors.rb +10 -0
- data/lib/cassandra_object/identity.rb +26 -0
- data/lib/cassandra_object/inspect.rb +25 -0
- data/lib/cassandra_object/log_subscriber.rb +44 -0
- data/lib/cassandra_object/model.rb +60 -0
- data/lib/cassandra_object/persistence.rb +203 -0
- data/lib/cassandra_object/railtie.rb +33 -0
- data/lib/cassandra_object/railties/controller_runtime.rb +45 -0
- data/lib/cassandra_object/schema.rb +83 -0
- data/lib/cassandra_object/schemaless.rb +83 -0
- data/lib/cassandra_object/scope.rb +86 -0
- data/lib/cassandra_object/scope/finder_methods.rb +54 -0
- data/lib/cassandra_object/scope/query_methods.rb +69 -0
- data/lib/cassandra_object/scoping.rb +27 -0
- data/lib/cassandra_object/serialization.rb +6 -0
- data/lib/cassandra_object/tasks/ks.rake +54 -0
- data/lib/cassandra_object/timestamps.rb +19 -0
- data/lib/cassandra_object/type.rb +16 -0
- data/lib/cassandra_object/types.rb +8 -0
- data/lib/cassandra_object/types/array_type.rb +16 -0
- data/lib/cassandra_object/types/base_type.rb +26 -0
- data/lib/cassandra_object/types/boolean_type.rb +20 -0
- data/lib/cassandra_object/types/date_type.rb +22 -0
- data/lib/cassandra_object/types/float_type.rb +16 -0
- data/lib/cassandra_object/types/integer_type.rb +20 -0
- data/lib/cassandra_object/types/json_type.rb +13 -0
- data/lib/cassandra_object/types/string_type.rb +19 -0
- data/lib/cassandra_object/types/time_type.rb +16 -0
- data/lib/cassandra_object/types/type_helper.rb +39 -0
- data/lib/cassandra_object/validations.rb +44 -0
- data/test/support/cassandra.rb +63 -0
- data/test/support/issue.rb +12 -0
- data/test/support/issue_dynamic.rb +12 -0
- data/test/support/issue_schema.rb +17 -0
- data/test/support/issue_schema_child.rb +17 -0
- data/test/support/issue_schema_father.rb +13 -0
- data/test/test_helper.rb +41 -0
- data/test/unit/active_model_test.rb +18 -0
- data/test/unit/adapters/adapter_test.rb +6 -0
- data/test/unit/attribute_methods/definition_test.rb +13 -0
- data/test/unit/attribute_methods/dirty_test.rb +72 -0
- data/test/unit/attribute_methods/primary_key_test.rb +26 -0
- data/test/unit/attribute_methods/typecasting_test.rb +119 -0
- data/test/unit/attribute_methods_test.rb +51 -0
- data/test/unit/base_test.rb +20 -0
- data/test/unit/belongs_to/reflection_test.rb +12 -0
- data/test/unit/belongs_to_test.rb +63 -0
- data/test/unit/callbacks_test.rb +46 -0
- data/test/unit/connection_test.rb +6 -0
- data/test/unit/connections/connections_test.rb +55 -0
- data/test/unit/core_test.rb +55 -0
- data/test/unit/identity_test.rb +26 -0
- data/test/unit/inspect_test.rb +26 -0
- data/test/unit/log_subscriber_test.rb +25 -0
- data/test/unit/persistence_schema_test.rb +156 -0
- data/test/unit/persistence_test.rb +266 -0
- data/test/unit/railties/controller_runtime_test.rb +48 -0
- data/test/unit/schema/tasks_test.rb +32 -0
- data/test/unit/schema_test.rb +115 -0
- data/test/unit/schemaless_test.rb +100 -0
- data/test/unit/scope/finder_methods_test.rb +117 -0
- data/test/unit/scope/query_methods_test.rb +32 -0
- data/test/unit/scoping_test.rb +7 -0
- data/test/unit/timestamps_test.rb +27 -0
- data/test/unit/types/array_type_test.rb +17 -0
- data/test/unit/types/base_type_test.rb +19 -0
- data/test/unit/types/boolean_type_test.rb +24 -0
- data/test/unit/types/date_type_test.rb +15 -0
- data/test/unit/types/float_type_test.rb +17 -0
- data/test/unit/types/integer_type_test.rb +19 -0
- data/test/unit/types/json_type_test.rb +23 -0
- data/test/unit/types/string_type_test.rb +25 -0
- data/test/unit/types/time_type_test.rb +14 -0
- data/test/unit/validations_test.rb +27 -0
- metadata +202 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module AttributeMethods
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include ActiveModel::AttributeMethods
|
5
|
+
|
6
|
+
included do
|
7
|
+
if ActiveModel::VERSION::STRING < '3.2'
|
8
|
+
attribute_method_suffix("", "=")
|
9
|
+
else
|
10
|
+
attribute_method_suffix("=")
|
11
|
+
end
|
12
|
+
|
13
|
+
# (Alias for the protected read_attribute method).
|
14
|
+
def [](attr_name)
|
15
|
+
read_attribute(attr_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
|
19
|
+
# (Alias for the protected write_attribute method).
|
20
|
+
def []=(attr_name, value)
|
21
|
+
write_attribute(attr_name, value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
def inherited(child_class)
|
27
|
+
child_class.define_attribute_methods
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def define_attribute_methods
|
32
|
+
return if attribute_methods_generated?
|
33
|
+
super(attribute_definitions.keys)
|
34
|
+
@attribute_methods_generated = true
|
35
|
+
end
|
36
|
+
|
37
|
+
def attribute_methods_generated?
|
38
|
+
@attribute_methods_generated ||= false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def write_attribute(name, value)
|
43
|
+
@attributes[name.to_s] = self.class.typecast_attribute(self, name, value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_attribute(name)
|
47
|
+
@attributes[name.to_s]
|
48
|
+
end
|
49
|
+
|
50
|
+
def attribute_exists?(name)
|
51
|
+
@attributes.key?(name.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def attributes
|
55
|
+
results = {}
|
56
|
+
@attributes.each_key do |key|
|
57
|
+
results[key] = read_attribute(key)
|
58
|
+
end
|
59
|
+
results
|
60
|
+
end
|
61
|
+
|
62
|
+
def attributes=(attributes)
|
63
|
+
attributes.each do |(name, value)|
|
64
|
+
send("#{name}=", value)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def method_missing(method_id, *args, &block)
|
69
|
+
if !self.class.attribute_methods_generated?
|
70
|
+
self.class.define_attribute_methods
|
71
|
+
send(method_id, *args, &block)
|
72
|
+
else
|
73
|
+
super
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def respond_to?(*args)
|
78
|
+
self.class.define_attribute_methods unless self.class.attribute_methods_generated?
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
def attribute_method?(name)
|
84
|
+
!!attribute_definitions[name.to_s]
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
def attribute(name)
|
89
|
+
read_attribute(name)
|
90
|
+
end
|
91
|
+
|
92
|
+
def attribute=(name, value)
|
93
|
+
write_attribute(name, value)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module AttributeMethods
|
3
|
+
class Definition
|
4
|
+
attr_reader :name, :coder
|
5
|
+
def initialize(name, coder, options)
|
6
|
+
@name = name.to_s
|
7
|
+
@coder = coder.new(options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def default
|
11
|
+
coder.default
|
12
|
+
end
|
13
|
+
|
14
|
+
def instantiate(record, value)
|
15
|
+
value = value.nil? ? coder.default : value
|
16
|
+
return if value.nil?
|
17
|
+
|
18
|
+
value.kind_of?(String) ? coder.decode(value) : coder.typecast(value)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module AttributeMethods
|
3
|
+
module Dirty
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
include ActiveModel::Dirty
|
6
|
+
|
7
|
+
# Attempts to +save+ the record and clears changed attributes if successful.
|
8
|
+
def save(*) #:nodoc:
|
9
|
+
if status = super
|
10
|
+
@previously_changed = changes
|
11
|
+
@changed_attributes = {}
|
12
|
+
end
|
13
|
+
status
|
14
|
+
end
|
15
|
+
|
16
|
+
# <tt>reload</tt> the record and clears changed attributes.
|
17
|
+
def reload
|
18
|
+
super.tap do
|
19
|
+
@previously_changed.try :clear
|
20
|
+
@changed_attributes.try :clear
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def write_attribute(name, value)
|
25
|
+
name = name.to_s
|
26
|
+
old = read_attribute(name)
|
27
|
+
|
28
|
+
super
|
29
|
+
|
30
|
+
unless attribute_changed?(name) || old == read_attribute(name)
|
31
|
+
changed_attributes[name] = old
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module AttributeMethods
|
3
|
+
module PrimaryKey
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def primary_key
|
8
|
+
'id'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def id
|
13
|
+
@id ||= self.class._generate_key(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def id=(id)
|
17
|
+
@id = id
|
18
|
+
end
|
19
|
+
|
20
|
+
def attributes
|
21
|
+
super.update(self.class.primary_key => id)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module AttributeMethods
|
3
|
+
module Typecasting
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :attribute_definitions
|
8
|
+
self.attribute_definitions = {}
|
9
|
+
|
10
|
+
%w(array boolean date float integer json string time).each do |type|
|
11
|
+
instance_eval <<-EOV, __FILE__, __LINE__ + 1
|
12
|
+
def #{type}(*args)
|
13
|
+
options = args.extract_options!
|
14
|
+
args.each do |name|
|
15
|
+
attribute(name, options.merge(:type => :#{type}))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
EOV
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def inherited(child)
|
24
|
+
super
|
25
|
+
child.attribute_definitions = attribute_definitions.dup
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# attribute :name, type: :string
|
30
|
+
# attribute :ammo, type: Ammo, coder: AmmoCodec
|
31
|
+
#
|
32
|
+
def attribute(name, options)
|
33
|
+
type = options[:type]
|
34
|
+
coder = options[:coder]
|
35
|
+
|
36
|
+
if type.is_a?(Symbol)
|
37
|
+
coder = CassandraObject::Type.get_coder(type) || (raise "Unknown type #{type}")
|
38
|
+
elsif coder.nil?
|
39
|
+
raise "Must supply a :coder for #{name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
attribute_definitions[name.to_s] = AttributeMethods::Definition.new(name, coder, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def typecast_attribute(record, name, value)
|
46
|
+
if attribute_definition = attribute_definitions[name.to_s]
|
47
|
+
attribute_definition.instantiate(record, value)
|
48
|
+
else
|
49
|
+
raise NoMethodError, "Unknown attribute #{name.inspect}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def coder_for(attribute)
|
54
|
+
attribute_definitions[attribute.to_s].coder
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'cassandra_object/log_subscriber'
|
4
|
+
require 'cassandra_object/types'
|
5
|
+
|
6
|
+
module CassandraObject
|
7
|
+
class Base
|
8
|
+
|
9
|
+
extend ActiveModel::Naming
|
10
|
+
include ActiveModel::Conversion
|
11
|
+
extend ActiveSupport::DescendantsTracker
|
12
|
+
|
13
|
+
include Identity
|
14
|
+
include Inspect
|
15
|
+
include Persistence
|
16
|
+
include AttributeMethods
|
17
|
+
include Validations
|
18
|
+
include AttributeMethods::Dirty
|
19
|
+
include AttributeMethods::PrimaryKey
|
20
|
+
include AttributeMethods::Typecasting
|
21
|
+
include BelongsTo
|
22
|
+
include Callbacks
|
23
|
+
include Timestamps
|
24
|
+
include Scoping
|
25
|
+
include Core
|
26
|
+
extend Model
|
27
|
+
|
28
|
+
include Serialization
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
ActiveSupport.run_load_hooks(:cassandra_object, CassandraObject::Base)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module BelongsTo
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :belongs_to_reflections
|
7
|
+
self.belongs_to_reflections = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# === Options
|
12
|
+
# [:class_name]
|
13
|
+
# Use if the class cannot be inferred from the association
|
14
|
+
# [:polymorphic]
|
15
|
+
# Specify if the association is polymorphic
|
16
|
+
# Example:
|
17
|
+
# class Driver < CassandraObject::Base
|
18
|
+
# end
|
19
|
+
# class Truck < CassandraObject::Base
|
20
|
+
# end
|
21
|
+
def belongs_to(name, options = {})
|
22
|
+
CassandraObject::BelongsTo::Builder.build(self, name, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def generated_belongs_to_methods
|
26
|
+
@generated_belongs_to_methods ||= begin
|
27
|
+
mod = const_set(:GeneratedBelongsToMethods, Module.new)
|
28
|
+
include mod
|
29
|
+
mod
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the belongs_to instance for the given name, instantiating it if it doesn't already exist
|
35
|
+
def belongs_to_association(name)
|
36
|
+
association = belongs_to_instance_get(name)
|
37
|
+
|
38
|
+
if association.nil?
|
39
|
+
association = CassandraObject::BelongsTo::Association.new(self, belongs_to_reflections[name])
|
40
|
+
belongs_to_instance_set(name, association)
|
41
|
+
end
|
42
|
+
|
43
|
+
association
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def clear_belongs_to_cache
|
48
|
+
belongs_to_cache.clear if persisted?
|
49
|
+
end
|
50
|
+
|
51
|
+
def belongs_to_cache
|
52
|
+
@belongs_to_cache ||= {}
|
53
|
+
end
|
54
|
+
|
55
|
+
def belongs_to_instance_get(name)
|
56
|
+
belongs_to_cache[name.to_sym]
|
57
|
+
end
|
58
|
+
|
59
|
+
def belongs_to_instance_set(name, association)
|
60
|
+
belongs_to_cache[name.to_sym] = association
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module BelongsTo
|
3
|
+
class Association
|
4
|
+
attr_reader :owner, :reflection
|
5
|
+
attr_accessor :record_variable
|
6
|
+
delegate :options, to: :reflection
|
7
|
+
|
8
|
+
def initialize(owner, reflection)
|
9
|
+
@loaded = false
|
10
|
+
@owner = owner
|
11
|
+
@reflection = reflection
|
12
|
+
end
|
13
|
+
|
14
|
+
def reader
|
15
|
+
unless loaded?
|
16
|
+
if record_id = owner.send(reflection.foreign_key).presence
|
17
|
+
self.record_variable = association_class.find_by_id(record_id)
|
18
|
+
else
|
19
|
+
self.record_variable = nil
|
20
|
+
end
|
21
|
+
@loaded = true
|
22
|
+
end
|
23
|
+
|
24
|
+
record_variable
|
25
|
+
end
|
26
|
+
|
27
|
+
def writer(record)
|
28
|
+
self.record_variable = record
|
29
|
+
@loaded = true
|
30
|
+
owner.send("#{reflection.foreign_key}=", record.try(:id))
|
31
|
+
if reflection.polymorphic?
|
32
|
+
owner.send("#{reflection.polymorphic_column}=", record.class.name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def association_class
|
37
|
+
association_class_name.constantize
|
38
|
+
end
|
39
|
+
|
40
|
+
def association_class_name
|
41
|
+
reflection.polymorphic? ? owner.send(reflection.polymorphic_column) : reflection.class_name
|
42
|
+
end
|
43
|
+
|
44
|
+
def loaded?
|
45
|
+
@loaded
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module BelongsTo
|
3
|
+
class Builder
|
4
|
+
def self.build(model, name, options)
|
5
|
+
new(model, name, options).build
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :model, :name, :options
|
9
|
+
def initialize(model, name, options)
|
10
|
+
@model, @name, @options = model, name, options
|
11
|
+
end
|
12
|
+
|
13
|
+
def build
|
14
|
+
define_writer
|
15
|
+
define_reader
|
16
|
+
|
17
|
+
reflection = CassandraObject::BelongsTo::Reflection.new(model, name, options)
|
18
|
+
model.belongs_to_reflections = model.belongs_to_reflections.merge(name => reflection)
|
19
|
+
end
|
20
|
+
|
21
|
+
def mixin
|
22
|
+
model.generated_belongs_to_methods
|
23
|
+
end
|
24
|
+
|
25
|
+
def define_writer
|
26
|
+
name = self.name
|
27
|
+
mixin.redefine_method("#{name}=") do |records|
|
28
|
+
belongs_to_association(name).writer(records)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def define_reader
|
33
|
+
name = self.name
|
34
|
+
mixin.redefine_method(name) do
|
35
|
+
belongs_to_association(name).reader
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|