better-ripple 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,151 @@
|
|
1
|
+
require 'tzinfo'
|
2
|
+
require 'active_support/json'
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
require 'active_support/core_ext/object/to_json'
|
5
|
+
require 'active_support/core_ext/date/conversions'
|
6
|
+
require 'active_support/core_ext/date/zones'
|
7
|
+
require 'active_support/core_ext/date_time/conversions'
|
8
|
+
require 'active_support/core_ext/date_time/zones'
|
9
|
+
require 'active_support/core_ext/time/conversions'
|
10
|
+
require 'active_support/core_ext/time/zones'
|
11
|
+
require 'active_support/core_ext/string/conversions'
|
12
|
+
require 'ripple/property_type_mismatch'
|
13
|
+
require 'set'
|
14
|
+
|
15
|
+
# @private
|
16
|
+
class Object
|
17
|
+
def self.ripple_cast(value)
|
18
|
+
value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @private
|
23
|
+
class Symbol
|
24
|
+
def self.ripple_cast(value)
|
25
|
+
return nil if value.blank?
|
26
|
+
value.respond_to?(:to_s) && value.to_s.intern or raise Ripple::PropertyTypeMismatch.new(self, value)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# @private
|
31
|
+
class Numeric
|
32
|
+
def self.ripple_cast(value)
|
33
|
+
return nil if value.blank?
|
34
|
+
raise Ripple::PropertyTypeMismatch.new(self,value) unless value.respond_to?(:to_i) && value.respond_to?(:to_f)
|
35
|
+
float_value = value.to_f
|
36
|
+
int_value = value.to_i
|
37
|
+
float_value == int_value ? int_value : float_value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @private
|
42
|
+
class Integer
|
43
|
+
def self.ripple_cast(value)
|
44
|
+
return nil if value.nil? || (String === value && value.blank?)
|
45
|
+
!value.is_a?(Symbol) && value.respond_to?(:to_i) && value.to_i or raise Ripple::PropertyTypeMismatch.new(self, value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @private
|
50
|
+
class Float
|
51
|
+
def self.ripple_cast(value)
|
52
|
+
return nil if value.nil? || (String === value && value.blank?)
|
53
|
+
value.respond_to?(:to_f) && value.to_f or raise Ripple::PropertyTypeMismatch.new(self, value)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @private
|
58
|
+
class String
|
59
|
+
def self.ripple_cast(value)
|
60
|
+
return nil if value.nil?
|
61
|
+
value.respond_to?(:to_s) && value.to_s or raise Ripple::PropertyTypeMismatch.new(self, value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
BooleanCast = Module.new do
|
66
|
+
def ripple_cast(value)
|
67
|
+
case value
|
68
|
+
when NilClass
|
69
|
+
nil
|
70
|
+
when Numeric
|
71
|
+
!value.zero?
|
72
|
+
when TrueClass, FalseClass
|
73
|
+
value
|
74
|
+
when /^\s*0/
|
75
|
+
false
|
76
|
+
when /^\s*t/i
|
77
|
+
true
|
78
|
+
when /^\s*f/i
|
79
|
+
false
|
80
|
+
else
|
81
|
+
value.present?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
unless defined?(::Boolean)
|
87
|
+
# Stand-in for true/false property types.
|
88
|
+
module ::Boolean; end
|
89
|
+
end
|
90
|
+
|
91
|
+
::Boolean.send(:extend, BooleanCast)
|
92
|
+
TrueClass.send(:extend, BooleanCast)
|
93
|
+
FalseClass.send(:extend, BooleanCast)
|
94
|
+
|
95
|
+
# @private
|
96
|
+
class Time
|
97
|
+
def as_json(options={})
|
98
|
+
self.utc.send(Ripple.date_format)
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.ripple_cast(value)
|
102
|
+
return nil if value.blank?
|
103
|
+
value.respond_to?(:to_time) && value.to_time or raise Ripple::PropertyTypeMismatch.new(self, value)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# @private
|
108
|
+
class Date
|
109
|
+
def as_json(options={})
|
110
|
+
self.to_s(Ripple.date_format)
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.ripple_cast(value)
|
114
|
+
return nil if value.blank?
|
115
|
+
value.respond_to?(:to_date) && value.to_date or raise Ripple::PropertyTypeMismatch.new(self, value)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# @private
|
120
|
+
class DateTime
|
121
|
+
def as_json(options={})
|
122
|
+
self.utc.to_s(Ripple.date_format)
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.ripple_cast(value)
|
126
|
+
return nil if value.blank?
|
127
|
+
value.respond_to?(:to_datetime) && value.to_datetime or raise Ripple::PropertyTypeMismatch.new(self, value)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# @private
|
132
|
+
module ActiveSupport
|
133
|
+
class TimeWithZone
|
134
|
+
def as_json(options={})
|
135
|
+
self.utc.send(Ripple.date_format)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# @private
|
141
|
+
class Set
|
142
|
+
def as_json(options = {})
|
143
|
+
map { |e| e.as_json(options) }
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.ripple_cast(value)
|
147
|
+
return nil if value.nil?
|
148
|
+
value.is_a?(Enumerable) && new(value) or raise Ripple::PropertyTypeMismatch.new(self, value)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'tzinfo'
|
2
|
+
require 'active_support/core_ext/date/conversions'
|
3
|
+
require 'active_support/core_ext/date/zones'
|
4
|
+
require 'active_support/core_ext/date_time/conversions'
|
5
|
+
require 'active_support/core_ext/date_time/zones'
|
6
|
+
require 'active_support/core_ext/time/conversions'
|
7
|
+
require 'active_support/core_ext/time/zones'
|
8
|
+
require 'active_support/core_ext/string/conversions'
|
9
|
+
require 'ripple/property_type_mismatch'
|
10
|
+
require 'set'
|
11
|
+
|
12
|
+
# @private
|
13
|
+
class Object
|
14
|
+
def to_ripple_index(type)
|
15
|
+
case type
|
16
|
+
when 'bin'
|
17
|
+
to_s
|
18
|
+
when 'int'
|
19
|
+
to_i
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @private
|
25
|
+
class Time
|
26
|
+
def to_ripple_index(type)
|
27
|
+
case type
|
28
|
+
when 'bin'
|
29
|
+
utc.send(Ripple.date_format)
|
30
|
+
when 'int'
|
31
|
+
# Use millisecond-precision
|
32
|
+
(utc.to_f * 1000).round
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @private
|
38
|
+
class Date
|
39
|
+
def to_ripple_index(type)
|
40
|
+
case type
|
41
|
+
when 'bin'
|
42
|
+
to_s(Ripple.date_format)
|
43
|
+
when 'int'
|
44
|
+
to_time(:utc).to_ripple_index(type)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @private
|
50
|
+
class DateTime
|
51
|
+
def to_ripple_index(type)
|
52
|
+
case type
|
53
|
+
when 'bin'
|
54
|
+
utc.to_s(Ripple.date_format)
|
55
|
+
when 'int'
|
56
|
+
(utc.to_f * 1000).round
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# @private
|
62
|
+
module ActiveSupport
|
63
|
+
class TimeWithZone
|
64
|
+
def to_ripple_index(type)
|
65
|
+
utc.to_ripple_index(type)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# @private
|
71
|
+
module Enumerable
|
72
|
+
def to_ripple_index(type)
|
73
|
+
Set.new(map {|v| v.to_ripple_index(type) })
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
if String < Enumerable
|
78
|
+
# Fix for 1.8, in which String is Enumerable
|
79
|
+
class String
|
80
|
+
def to_ripple_index(type)
|
81
|
+
case type
|
82
|
+
when 'bin'
|
83
|
+
to_s
|
84
|
+
when 'int'
|
85
|
+
to_i
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_model/naming'
|
3
|
+
require 'ripple/conflict/document_hooks'
|
4
|
+
require 'ripple/document/bucket_access'
|
5
|
+
require 'ripple/document/key'
|
6
|
+
require 'ripple/document/persistence'
|
7
|
+
require 'ripple/document/finders'
|
8
|
+
require 'ripple/document/link'
|
9
|
+
require 'ripple/properties'
|
10
|
+
require 'ripple/attribute_methods'
|
11
|
+
require 'ripple/indexes'
|
12
|
+
require 'ripple/timestamps'
|
13
|
+
require 'ripple/validations'
|
14
|
+
require 'ripple/associations'
|
15
|
+
require 'ripple/callbacks'
|
16
|
+
require 'ripple/observable'
|
17
|
+
require 'ripple/conversion'
|
18
|
+
require 'ripple/inspection'
|
19
|
+
require 'ripple/nested_attributes'
|
20
|
+
require 'ripple/serialization'
|
21
|
+
|
22
|
+
module Ripple
|
23
|
+
# Represents a model stored in Riak, serialized in JSON object (document).
|
24
|
+
# Ripple::Document models aim to be fully ActiveModel compatible, with a keen
|
25
|
+
# eye toward features that developers expect from ActiveRecord, DataMapper and MongoMapper.
|
26
|
+
#
|
27
|
+
# Example:
|
28
|
+
#
|
29
|
+
# class Email
|
30
|
+
# include Ripple::Document
|
31
|
+
# property :from, String, :presence => true
|
32
|
+
# property :to, String, :presence => true
|
33
|
+
# property :sent, Time, :default => proc { Time.now }
|
34
|
+
# property :body, String
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# email = Email.find("37458abc752f8413e") # GET /riak/emails/37458abc752f8413e
|
38
|
+
# email.from = "someone@nowhere.net"
|
39
|
+
# email.save # PUT /riak/emails/37458abc752f8413e
|
40
|
+
#
|
41
|
+
# reply = Email.new
|
42
|
+
# reply.from = "justin@bashoooo.com"
|
43
|
+
# reply.to = "sean@geeemail.com"
|
44
|
+
# reply.body = "Riak is a good fit for scalable Ruby apps."
|
45
|
+
# reply.save # POST /riak/emails (Riak-assigned key)
|
46
|
+
#
|
47
|
+
module Document
|
48
|
+
extend ActiveSupport::Concern
|
49
|
+
|
50
|
+
included do
|
51
|
+
extend ActiveModel::Naming
|
52
|
+
extend BucketAccess
|
53
|
+
include Ripple::Document::Key
|
54
|
+
include Ripple::Document::Persistence
|
55
|
+
extend Ripple::Properties
|
56
|
+
include Ripple::Document::Finders
|
57
|
+
include Ripple::AttributeMethods
|
58
|
+
include Ripple::Timestamps
|
59
|
+
include Ripple::Indexes
|
60
|
+
include Ripple::Indexes::DocumentMethods
|
61
|
+
include Ripple::Validations
|
62
|
+
include Ripple::Associations
|
63
|
+
include Ripple::Callbacks
|
64
|
+
include Ripple::Observable
|
65
|
+
include Ripple::Conversion
|
66
|
+
include Ripple::Inspection
|
67
|
+
include Ripple::NestedAttributes
|
68
|
+
include Ripple::Serialization
|
69
|
+
include Ripple::Conflict::DocumentHooks
|
70
|
+
end
|
71
|
+
|
72
|
+
module ClassMethods
|
73
|
+
def embeddable?
|
74
|
+
false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def _root_document
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns true if the +comparison_object+ is the same object, or is of the same type and has the same key.
|
83
|
+
def ==(comparison_object)
|
84
|
+
comparison_object.equal?(self) ||
|
85
|
+
(comparison_object.class < Document && (comparison_object.instance_of?(self.class) || comparison_object.class.bucket.name == self.class.bucket.name) &&
|
86
|
+
!new? && comparison_object.key == key && !comparison_object.new?)
|
87
|
+
end
|
88
|
+
|
89
|
+
def eql?(other)
|
90
|
+
return true if other.equal?(self)
|
91
|
+
|
92
|
+
(other.class.equal?(self.class)) &&
|
93
|
+
!other.new? && !new? &&
|
94
|
+
(other.key == key)
|
95
|
+
end
|
96
|
+
|
97
|
+
def hash
|
98
|
+
if new?
|
99
|
+
super # every new document should be treated as a different doc
|
100
|
+
else
|
101
|
+
[self.class, key].hash
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'ripple'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module Document
|
5
|
+
# Similar to ActiveRecord's tables or MongoMapper's collections, we
|
6
|
+
# provide a sane default bucket in which to store your documents.
|
7
|
+
module BucketAccess
|
8
|
+
# @return [String] The bucket name assigned to the document class. Subclasses will inherit their bucket name from their parent class unless they redefine it.
|
9
|
+
def bucket_name
|
10
|
+
superclass.respond_to?(:bucket_name) ? superclass.bucket_name : model_name.plural
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Riak::Bucket] The bucket assigned to this class.
|
14
|
+
def bucket
|
15
|
+
Ripple.client.bucket(bucket_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Set the bucket name for this class and its subclasses.
|
19
|
+
# @param [String] value the new bucket name
|
20
|
+
def bucket_name=(value)
|
21
|
+
(class << self; self; end).send(:define_method, :bucket_name){ value }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'ripple/translation'
|
2
|
+
require 'active_support/concern'
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require 'active_support/core_ext/hash/except'
|
5
|
+
require 'active_support/core_ext/hash/slice'
|
6
|
+
require 'ripple/conflict/resolver'
|
7
|
+
|
8
|
+
module Ripple
|
9
|
+
|
10
|
+
# Raised by <tt>find!</tt> when a document cannot be found with the given key.
|
11
|
+
# begin
|
12
|
+
# Example.find!('badkey')
|
13
|
+
# rescue Ripple::DocumentNotFound
|
14
|
+
# puts 'No Document here!'
|
15
|
+
# end
|
16
|
+
class DocumentNotFound < StandardError
|
17
|
+
include Translation
|
18
|
+
def initialize(keys, found)
|
19
|
+
if keys.empty?
|
20
|
+
super(t("document_not_found.no_key"))
|
21
|
+
elsif keys.size == 1
|
22
|
+
super(t("document_not_found.one_key", :key => keys.first))
|
23
|
+
else
|
24
|
+
missing = keys - found.compact.map(&:key)
|
25
|
+
super(t("document_not_found.many_keys", :keys => missing.join(', ')))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Document
|
31
|
+
module Finders
|
32
|
+
extend ActiveSupport::Concern
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
# Retrieve single or multiple documents from Riak.
|
36
|
+
# @overload find(key)
|
37
|
+
# Find a single document.
|
38
|
+
# @param [String] key the key of a document to find
|
39
|
+
# @return [Document] the found document, or nil
|
40
|
+
# @overload find(key1, key2, ...)
|
41
|
+
# Find a list of documents.
|
42
|
+
# @param [String] key1 the key of a document to find
|
43
|
+
# @param [String] key2 the key of a document to find
|
44
|
+
# @return [Array<Document>] a list of found documents, including nil for missing documents
|
45
|
+
# @overload find(keylist)
|
46
|
+
# Find a list of documents.
|
47
|
+
# @param [Array<String>] keylist an array of keys to find
|
48
|
+
# @return [Array<Document>] a list of found documents, including nil for missing documents
|
49
|
+
def find(*args)
|
50
|
+
if args.first.is_a?(Array)
|
51
|
+
args.flatten.map {|key| find_one(key) }
|
52
|
+
else
|
53
|
+
args.flatten!
|
54
|
+
return nil if args.empty? || args.all?(&:blank?)
|
55
|
+
return find_one(args.first) if args.size == 1
|
56
|
+
args.map {|key| find_one(key) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Retrieve single or multiple documents from Riak
|
61
|
+
# but raise Ripple::DocumentNotFound if a key can
|
62
|
+
# not be found in the bucket.
|
63
|
+
def find!(*args)
|
64
|
+
found = find(*args)
|
65
|
+
raise DocumentNotFound.new(args, found) if !found || Array(found).include?(nil)
|
66
|
+
found
|
67
|
+
end
|
68
|
+
|
69
|
+
# Find the first object using the first key in the
|
70
|
+
# bucket's keys using find. You should not expect to
|
71
|
+
# actually get the first object you added to the bucket.
|
72
|
+
# This is just a convenience method.
|
73
|
+
def first
|
74
|
+
find(bucket.keys.first)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Find the first object using the first key in the
|
78
|
+
# bucket's keys using find!
|
79
|
+
def first!
|
80
|
+
find!(bucket.keys.first)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Find all documents in the Document's bucket and return them.
|
84
|
+
# @overload list()
|
85
|
+
# Get all documents and return them in an array.
|
86
|
+
# @param [Hash] options options to be passed to the
|
87
|
+
# underlying {Bucket#keys} method.
|
88
|
+
# @return [Array<Document>] all found documents in the bucket
|
89
|
+
# @overload list() {|doc| ... }
|
90
|
+
# Stream all documents in the bucket through the block.
|
91
|
+
# @yield [Document] doc a found document
|
92
|
+
# @note This operation is incredibly expensive and should not
|
93
|
+
# be used in production applications.
|
94
|
+
def list
|
95
|
+
if block_given?
|
96
|
+
bucket.keys do |keys|
|
97
|
+
keys.each do |key|
|
98
|
+
obj = find_one(key)
|
99
|
+
yield obj if obj
|
100
|
+
end
|
101
|
+
end
|
102
|
+
[]
|
103
|
+
else
|
104
|
+
bucket.keys.inject([]) do |acc, k|
|
105
|
+
obj = find_one(k)
|
106
|
+
obj ? acc << obj : acc
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
def find_one(key)
|
113
|
+
instantiate(bucket.get(key, quorums.slice(:r)))
|
114
|
+
rescue Riak::FailedRequest => fr
|
115
|
+
raise fr unless fr.not_found?
|
116
|
+
end
|
117
|
+
|
118
|
+
def instantiate(robject)
|
119
|
+
klass = robject.data['_type'].constantize rescue self
|
120
|
+
klass.new.tap do |doc|
|
121
|
+
doc.key = robject.key
|
122
|
+
doc.__send__(:raw_attributes=, robject.data.except("_type")) if robject.data
|
123
|
+
doc.instance_variable_set(:@new, false)
|
124
|
+
doc.instance_variable_set(:@robject, robject)
|
125
|
+
doc.changed_attributes.clear
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|