better-ripple 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.
- data/LICENSE +17 -0
- data/README.md +182 -0
- data/RELEASE_NOTES.md +284 -0
- data/better-ripple.gemspec +55 -0
- data/lib/rails/generators/ripple/configuration/configuration_generator.rb +13 -0
- data/lib/rails/generators/ripple/configuration/templates/ripple.yml +25 -0
- data/lib/rails/generators/ripple/js/js_generator.rb +13 -0
- data/lib/rails/generators/ripple/js/templates/js/contrib.js +63 -0
- data/lib/rails/generators/ripple/js/templates/js/iso8601.js +76 -0
- data/lib/rails/generators/ripple/js/templates/js/ripple.js +132 -0
- data/lib/rails/generators/ripple/model/model_generator.rb +20 -0
- data/lib/rails/generators/ripple/model/templates/model.rb.erb +10 -0
- data/lib/rails/generators/ripple/observer/observer_generator.rb +16 -0
- data/lib/rails/generators/ripple/observer/templates/observer.rb.erb +2 -0
- data/lib/rails/generators/ripple/test/templates/cucumber.rb.erb +7 -0
- data/lib/rails/generators/ripple/test/test_generator.rb +44 -0
- data/lib/rails/generators/ripple_generator.rb +79 -0
- data/lib/ripple.rb +86 -0
- data/lib/ripple/associations.rb +380 -0
- data/lib/ripple/associations/embedded.rb +35 -0
- data/lib/ripple/associations/instantiators.rb +26 -0
- data/lib/ripple/associations/linked.rb +65 -0
- data/lib/ripple/associations/many.rb +38 -0
- data/lib/ripple/associations/many_embedded_proxy.rb +39 -0
- data/lib/ripple/associations/many_linked_proxy.rb +66 -0
- data/lib/ripple/associations/many_reference_proxy.rb +95 -0
- data/lib/ripple/associations/many_stored_key_proxy.rb +76 -0
- data/lib/ripple/associations/one.rb +20 -0
- data/lib/ripple/associations/one_embedded_proxy.rb +35 -0
- data/lib/ripple/associations/one_key_proxy.rb +58 -0
- data/lib/ripple/associations/one_linked_proxy.rb +26 -0
- data/lib/ripple/associations/one_stored_key_proxy.rb +43 -0
- data/lib/ripple/associations/proxy.rb +118 -0
- data/lib/ripple/attribute_methods.rb +132 -0
- data/lib/ripple/attribute_methods/dirty.rb +59 -0
- data/lib/ripple/attribute_methods/query.rb +34 -0
- data/lib/ripple/attribute_methods/read.rb +28 -0
- data/lib/ripple/attribute_methods/write.rb +25 -0
- data/lib/ripple/callbacks.rb +71 -0
- data/lib/ripple/conflict/basic_resolver.rb +86 -0
- data/lib/ripple/conflict/document_hooks.rb +46 -0
- data/lib/ripple/conflict/resolver.rb +79 -0
- data/lib/ripple/conflict/test_helper.rb +34 -0
- data/lib/ripple/conversion.rb +29 -0
- data/lib/ripple/core_ext.rb +3 -0
- data/lib/ripple/core_ext/casting.rb +151 -0
- data/lib/ripple/core_ext/indexes.rb +89 -0
- data/lib/ripple/core_ext/object.rb +8 -0
- data/lib/ripple/document.rb +105 -0
- data/lib/ripple/document/bucket_access.rb +25 -0
- data/lib/ripple/document/finders.rb +131 -0
- data/lib/ripple/document/key.rb +35 -0
- data/lib/ripple/document/link.rb +30 -0
- data/lib/ripple/document/persistence.rb +130 -0
- data/lib/ripple/embedded_document.rb +63 -0
- data/lib/ripple/embedded_document/around_callbacks.rb +18 -0
- data/lib/ripple/embedded_document/finders.rb +26 -0
- data/lib/ripple/embedded_document/persistence.rb +75 -0
- data/lib/ripple/i18n.rb +5 -0
- data/lib/ripple/indexes.rb +151 -0
- data/lib/ripple/inspection.rb +32 -0
- data/lib/ripple/locale/en.yml +26 -0
- data/lib/ripple/locale/fr.yml +24 -0
- data/lib/ripple/nested_attributes.rb +275 -0
- data/lib/ripple/observable.rb +28 -0
- data/lib/ripple/properties.rb +74 -0
- data/lib/ripple/property_type_mismatch.rb +12 -0
- data/lib/ripple/railtie.rb +26 -0
- data/lib/ripple/railties/ripple.rake +103 -0
- data/lib/ripple/serialization.rb +82 -0
- data/lib/ripple/test_server.rb +35 -0
- data/lib/ripple/timestamps.rb +25 -0
- data/lib/ripple/translation.rb +18 -0
- data/lib/ripple/validations.rb +65 -0
- data/lib/ripple/validations/associated_validator.rb +43 -0
- data/lib/ripple/version.rb +3 -0
- metadata +310 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module Document
|
5
|
+
module Key
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# Defines the key to be derived from a property.
|
10
|
+
# @param [String,Symbol] prop the property to derive the key from
|
11
|
+
def key_on(prop)
|
12
|
+
prop = prop.to_sym
|
13
|
+
|
14
|
+
define_method(:key) { send(prop).to_s }
|
15
|
+
define_method(:key=) { |v| send(:"#{prop}=", v) }
|
16
|
+
define_method(:key_attr) { prop }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Reads the key for this Document.
|
21
|
+
def key
|
22
|
+
@key
|
23
|
+
end
|
24
|
+
|
25
|
+
# Sets the key for this Document.
|
26
|
+
def key=(value)
|
27
|
+
@key = value.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def key_attr
|
31
|
+
:key
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'riak/link'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module Document
|
5
|
+
# A Link that is tied to a particular document and tag.
|
6
|
+
# The key is fetched from the document lazily when needed.
|
7
|
+
class Link < Riak::Link
|
8
|
+
attr_reader :document
|
9
|
+
private :document
|
10
|
+
|
11
|
+
def initialize(document, tag)
|
12
|
+
@document = document
|
13
|
+
super(document.class.bucket_name, nil, tag)
|
14
|
+
end
|
15
|
+
|
16
|
+
def key
|
17
|
+
document.key
|
18
|
+
end
|
19
|
+
|
20
|
+
def hash
|
21
|
+
document.hash
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_link(tag)
|
26
|
+
Link.new(self, tag)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module Document
|
5
|
+
module Persistence
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
# Instantiates a new record, applies attributes from a block, and saves it
|
11
|
+
def create(*args, &block)
|
12
|
+
new(*args, &block).tap {|s| s.save }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Destroys all records one at a time.
|
16
|
+
# Place holder while :delete to bucket is being developed.
|
17
|
+
def destroy_all
|
18
|
+
list(&:destroy)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_writer :quorums
|
22
|
+
alias_method "set_quorums", "quorums="
|
23
|
+
|
24
|
+
def quorums
|
25
|
+
@quorums ||= {}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @private
|
30
|
+
def initialize
|
31
|
+
super
|
32
|
+
@new = true
|
33
|
+
@deleted = false
|
34
|
+
end
|
35
|
+
|
36
|
+
# Determines whether this document has been deleted or not.
|
37
|
+
def deleted?
|
38
|
+
@deleted
|
39
|
+
end
|
40
|
+
|
41
|
+
# Determines whether this is a new document.
|
42
|
+
def new?
|
43
|
+
@new || false
|
44
|
+
end
|
45
|
+
|
46
|
+
# Updates a single attribute and then saves the document
|
47
|
+
# NOTE: THIS SKIPS VALIDATIONS! Use with caution.
|
48
|
+
# @return [true,false] whether the document succeeded in saving
|
49
|
+
def update_attribute(attribute, value)
|
50
|
+
send("#{attribute}=", value)
|
51
|
+
save(:validate => false)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Writes new attributes and then saves the document
|
55
|
+
# @return [true,false] whether the document succeeded in saving
|
56
|
+
def update_attributes(attrs)
|
57
|
+
self.attributes = attrs
|
58
|
+
save
|
59
|
+
end
|
60
|
+
|
61
|
+
# Saves the document in Riak.
|
62
|
+
# @return [true,false] whether the document succeeded in saving
|
63
|
+
def save(*args)
|
64
|
+
really_save(*args)
|
65
|
+
end
|
66
|
+
|
67
|
+
def really_save(*args)
|
68
|
+
update_robject
|
69
|
+
robject.store(self.class.quorums.slice(:w,:dw))
|
70
|
+
self.key = robject.key
|
71
|
+
@new = false
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
# Reloads the document from Riak
|
76
|
+
# @return self
|
77
|
+
def reload
|
78
|
+
return self if new?
|
79
|
+
@robject = @robject.reload(:force => true)
|
80
|
+
self.__send__(:raw_attributes=, @robject.data.except("_type"))
|
81
|
+
reset_associations
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
# Deletes the document from Riak and freezes this instance
|
86
|
+
def destroy!
|
87
|
+
robject.delete(self.class.quorums.slice(:rw)) unless new?
|
88
|
+
@deleted = true
|
89
|
+
freeze
|
90
|
+
end
|
91
|
+
|
92
|
+
def destroy
|
93
|
+
destroy!
|
94
|
+
true
|
95
|
+
rescue Riak::FailedRequest
|
96
|
+
false
|
97
|
+
end
|
98
|
+
|
99
|
+
# Freeze the attributes hash instead of the record itself to avoid
|
100
|
+
# errors when calling methods on frozen records.
|
101
|
+
def freeze
|
102
|
+
@attributes.freeze
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns +true+ if the attributes hash has been frozen.
|
106
|
+
def frozen?
|
107
|
+
@attributes.frozen?
|
108
|
+
end
|
109
|
+
|
110
|
+
attr_writer :robject
|
111
|
+
|
112
|
+
def robject
|
113
|
+
@robject ||= Riak::RObject.new(self.class.bucket, key).tap do |obj|
|
114
|
+
obj.content_type = "application/json"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def update_robject
|
119
|
+
robject.key = key if robject.key != key
|
120
|
+
robject.content_type = 'application/json'
|
121
|
+
robject.data = attributes_for_persistence
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
def attributes_for_persistence
|
126
|
+
raw_attributes.merge("_type" => self.class.name)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/core_ext/hash/except'
|
3
|
+
require 'ripple/translation'
|
4
|
+
require 'ripple/embedded_document/around_callbacks'
|
5
|
+
require 'ripple/embedded_document/finders'
|
6
|
+
require 'ripple/embedded_document/persistence'
|
7
|
+
require 'ripple/properties'
|
8
|
+
require 'ripple/attribute_methods'
|
9
|
+
require 'ripple/timestamps'
|
10
|
+
require 'ripple/validations'
|
11
|
+
require 'ripple/associations'
|
12
|
+
require 'ripple/callbacks'
|
13
|
+
require 'ripple/conversion'
|
14
|
+
require 'ripple/inspection'
|
15
|
+
require 'ripple/nested_attributes'
|
16
|
+
require 'ripple/serialization'
|
17
|
+
|
18
|
+
module Ripple
|
19
|
+
# Represents a document model that is composed into or stored in a parent
|
20
|
+
# Document. Embedded documents may also embed other documents, have
|
21
|
+
# callbacks and validations, but are solely dependent on the parent Document.
|
22
|
+
module EmbeddedDocument
|
23
|
+
extend ActiveSupport::Concern
|
24
|
+
include Translation
|
25
|
+
|
26
|
+
included do
|
27
|
+
extend ActiveModel::Naming
|
28
|
+
include Persistence
|
29
|
+
extend Ripple::Properties
|
30
|
+
include Ripple::AttributeMethods
|
31
|
+
include Ripple::Indexes
|
32
|
+
include Ripple::Timestamps
|
33
|
+
include Ripple::Validations
|
34
|
+
include Ripple::Associations
|
35
|
+
include Ripple::Callbacks
|
36
|
+
include Ripple::EmbeddedDocument::AroundCallbacks
|
37
|
+
include Ripple::Conversion
|
38
|
+
include Finders
|
39
|
+
include Ripple::Inspection
|
40
|
+
include Ripple::NestedAttributes
|
41
|
+
include Ripple::Serialization
|
42
|
+
end
|
43
|
+
|
44
|
+
module ClassMethods
|
45
|
+
def embeddable?
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def ==(other)
|
51
|
+
self.class == other.class &&
|
52
|
+
_parent_document == other._parent_document &&
|
53
|
+
serializable_hash == other.serializable_hash
|
54
|
+
end
|
55
|
+
alias eql? ==
|
56
|
+
|
57
|
+
def hash
|
58
|
+
hash = self.class.hash ^ _parent_document.class.hash ^ serializable_hash.to_s.hash
|
59
|
+
hash ^= _parent_document.key.hash if _parent_document.respond_to?(:key)
|
60
|
+
hash
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ripple/callbacks'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module EmbeddedDocument
|
5
|
+
module AroundCallbacks
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
extend Translation
|
8
|
+
|
9
|
+
included do
|
10
|
+
Ripple::Callbacks::CALLBACK_TYPES.each do |type|
|
11
|
+
define_singleton_method "around_#{type}" do |*args|
|
12
|
+
raise NotImplementedError.new(t("around_callbacks_not_supported", :type => type))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
|
4
|
+
module Ripple
|
5
|
+
module EmbeddedDocument
|
6
|
+
# @private
|
7
|
+
module Finders
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def instantiate(attrs)
|
12
|
+
begin
|
13
|
+
klass = attrs['_type'].present? ? attrs.delete('_type').constantize : self
|
14
|
+
rescue NameError
|
15
|
+
klass = self
|
16
|
+
end
|
17
|
+
klass.new.tap do |object|
|
18
|
+
object.raw_attributes = attrs
|
19
|
+
object.changed_attributes.clear
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'ripple/translation'
|
3
|
+
|
4
|
+
module Ripple
|
5
|
+
# Exception raised when save is called on an EmbeddedDocument that
|
6
|
+
# is not attached to a root Document.
|
7
|
+
class NoRootDocument < StandardError
|
8
|
+
include Translation
|
9
|
+
def initialize(doc, method)
|
10
|
+
super(t("no_root_document", :doc => doc.inspect, :method => method))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module EmbeddedDocument
|
15
|
+
# Adds methods to {Ripple::EmbeddedDocument} that delegate storage
|
16
|
+
# operations to the parent document.
|
17
|
+
module Persistence
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
# Creates a method that points to the parent document.
|
22
|
+
def embedded_in(parent)
|
23
|
+
define_method(parent) { @_parent_document }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# The parent document to this embedded document. This may be a
|
28
|
+
# {Ripple::Document} or another {Ripple::EmbeddedDocument}.
|
29
|
+
attr_accessor :_parent_document
|
30
|
+
|
31
|
+
# Whether the root document is unsaved.
|
32
|
+
def new?
|
33
|
+
if _root_document
|
34
|
+
_root_document.new?
|
35
|
+
else
|
36
|
+
true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Sets this embedded documents attributes and saves the root document.
|
41
|
+
def update_attributes(attrs)
|
42
|
+
self.attributes = attrs
|
43
|
+
save
|
44
|
+
end
|
45
|
+
|
46
|
+
# Updates this embedded document's attribute and saves the
|
47
|
+
# root document, skipping validations.
|
48
|
+
def update_attribute(attribute, value)
|
49
|
+
send("#{attribute}=", value)
|
50
|
+
save(:validate => false)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Saves this embedded document by delegating to the root document.
|
54
|
+
def save(*args)
|
55
|
+
if _root_document
|
56
|
+
run_save_callbacks do
|
57
|
+
_root_document.save(*args)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
raise NoRootDocument.new(self, :save)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# @private
|
65
|
+
def attributes_for_persistence
|
66
|
+
raw_attributes.merge("_type" => self.class.name)
|
67
|
+
end
|
68
|
+
|
69
|
+
# The root {Ripple::Document} to which this embedded document belongs.
|
70
|
+
def _root_document
|
71
|
+
@_parent_document.try(:_root_document)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/ripple/i18n.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'ripple/translation'
|
2
|
+
require 'active_support/concern'
|
3
|
+
|
4
|
+
module Ripple
|
5
|
+
# Adds secondary-indexes to {Document} properties.
|
6
|
+
module Indexes
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def inherited(subclass)
|
12
|
+
super
|
13
|
+
subclass.indexes = indexes.dup
|
14
|
+
end
|
15
|
+
|
16
|
+
# Indexes defined on the document.
|
17
|
+
def indexes
|
18
|
+
@indexes ||= {}.with_indifferent_access
|
19
|
+
end
|
20
|
+
|
21
|
+
def indexes=(idx)
|
22
|
+
@indexes = idx
|
23
|
+
end
|
24
|
+
|
25
|
+
def property(key, type, options={})
|
26
|
+
if indexed = options.delete(:index)
|
27
|
+
indexes[key] = Index.new(key, type, indexed)
|
28
|
+
end
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def index(key, type, &block)
|
33
|
+
if block_given?
|
34
|
+
indexes[key] = Index.new(key, type, &block)
|
35
|
+
else
|
36
|
+
indexes[key] = Index.new(key, type)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns indexes in a form suitable for persisting to Riak.
|
42
|
+
# @return [Hash] indexes for this document
|
43
|
+
def indexes_for_persistence(prefix = '')
|
44
|
+
Hash.new {|h,k| h[k] = Set.new }.tap do |indexes|
|
45
|
+
# Add embedded associations' indexes
|
46
|
+
self.class.embedded_associations.each do |association|
|
47
|
+
documents = instance_variable_get(association.ivar)
|
48
|
+
unless documents.nil?
|
49
|
+
Array(documents).each do |doc|
|
50
|
+
embedded_indexes = doc.indexes_for_persistence("#{prefix}#{association.name}_")
|
51
|
+
indexes.merge!(embedded_indexes) do |_,original,new|
|
52
|
+
original.merge new
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Add this document's indexes
|
59
|
+
self.class.indexes.each do |key, index|
|
60
|
+
if index.block
|
61
|
+
index_value = index.to_index_value instance_exec(&index.block)
|
62
|
+
else
|
63
|
+
index_value = index.to_index_value send(key)
|
64
|
+
end
|
65
|
+
index_value = Set[index_value] unless index_value.is_a?(Enumerable) && !index_value.is_a?(String)
|
66
|
+
indexes[prefix + index.index_key].merge index_value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Modifies the persistence chain to set indexes on the internal
|
72
|
+
# {Riak::RObject} before saving.
|
73
|
+
module DocumentMethods
|
74
|
+
extend ActiveSupport::Concern
|
75
|
+
def update_robject
|
76
|
+
robject.indexes = indexes_for_persistence
|
77
|
+
super
|
78
|
+
end
|
79
|
+
|
80
|
+
module ClassMethods
|
81
|
+
# Search for a document using an indexed column
|
82
|
+
# @param [Symbol] name of the index
|
83
|
+
# @param [String, Integer, Range] query to search for
|
84
|
+
def find_by_index(index_name, query)
|
85
|
+
if ["$bucket", "$key"].include?(index_name.to_s)
|
86
|
+
self.find(Ripple.client.get_index(self.bucket.name, index_name.to_s, query))
|
87
|
+
else
|
88
|
+
idx = self.indexes[index_name]
|
89
|
+
raise ArgumentError, t('index_undefined', :property => index_name, :type => self.name) if idx.nil?
|
90
|
+
self.find(Ripple.client.get_index(self.bucket.name, idx.index_key, query))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Represents a Secondary Index on a Document
|
98
|
+
class Index
|
99
|
+
include Translation
|
100
|
+
attr_reader :key, :type, :block
|
101
|
+
|
102
|
+
# Creates an index for a Document
|
103
|
+
# @param [Symbol] key the attribute key
|
104
|
+
# @param [Class] property_type the type of the associated property
|
105
|
+
# @param ['bin', 'int', String, Integer] index_type if given, the
|
106
|
+
# type of index
|
107
|
+
# @yield a block that returns the value of the index
|
108
|
+
def initialize(key, property_type, index_type=true, &block)
|
109
|
+
@key, @type, @index, @block = key, property_type, index_type, block
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# The key under which a value will be indexed
|
114
|
+
def index_key
|
115
|
+
"#{key}_#{index_type}"
|
116
|
+
end
|
117
|
+
|
118
|
+
# Converts an attribute to a value appropriate for storing in a
|
119
|
+
# secondary index.
|
120
|
+
# @param [Object] value a value of type {#type}
|
121
|
+
# @return [String, Integer, Set] a value appropriate for storing
|
122
|
+
# in a secondary index
|
123
|
+
def to_index_value(value)
|
124
|
+
value.to_ripple_index(index_type)
|
125
|
+
end
|
126
|
+
|
127
|
+
# @return ["bin", "int", nil] the type of index used for this property
|
128
|
+
# @raise [ArgumentError] if the type cannot be automatically determined
|
129
|
+
def index_type
|
130
|
+
@index_type ||= case @index
|
131
|
+
when /^bin|int$/
|
132
|
+
@index
|
133
|
+
when Class
|
134
|
+
determine_index_type(@index)
|
135
|
+
else
|
136
|
+
determine_index_type(@type)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
def determine_index_type(itype)
|
142
|
+
if String == itype || itype < String
|
143
|
+
'bin'
|
144
|
+
elsif [Integer, Time, Date, ActiveSupport::TimeWithZone].any? {|t| t == itype || itype < t }
|
145
|
+
'int'
|
146
|
+
else
|
147
|
+
raise ArgumentError, t('index_type_unknown', :property => @key, :type => itype.name)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|