dynamoid-edge 1.1.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/CHANGELOG.md +21 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +377 -0
- data/Rakefile +67 -0
- data/dynamoid-edge.gemspec +74 -0
- data/lib/dynamoid/adapter.rb +181 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb +761 -0
- data/lib/dynamoid/associations/association.rb +105 -0
- data/lib/dynamoid/associations/belongs_to.rb +44 -0
- data/lib/dynamoid/associations/has_and_belongs_to_many.rb +40 -0
- data/lib/dynamoid/associations/has_many.rb +39 -0
- data/lib/dynamoid/associations/has_one.rb +39 -0
- data/lib/dynamoid/associations/many_association.rb +191 -0
- data/lib/dynamoid/associations/single_association.rb +69 -0
- data/lib/dynamoid/associations.rb +106 -0
- data/lib/dynamoid/components.rb +37 -0
- data/lib/dynamoid/config/options.rb +78 -0
- data/lib/dynamoid/config.rb +54 -0
- data/lib/dynamoid/criteria/chain.rb +212 -0
- data/lib/dynamoid/criteria.rb +29 -0
- data/lib/dynamoid/dirty.rb +47 -0
- data/lib/dynamoid/document.rb +201 -0
- data/lib/dynamoid/errors.rb +63 -0
- data/lib/dynamoid/fields.rb +156 -0
- data/lib/dynamoid/finders.rb +197 -0
- data/lib/dynamoid/identity_map.rb +92 -0
- data/lib/dynamoid/middleware/identity_map.rb +16 -0
- data/lib/dynamoid/persistence.rb +324 -0
- data/lib/dynamoid/validations.rb +36 -0
- data/lib/dynamoid.rb +50 -0
- metadata +226 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dynamoid #:nodoc:
|
3
|
+
|
4
|
+
# The base association module which all associations include. Every association has two very important components: the source and
|
5
|
+
# the target. The source is the object which is calling the association information. It always has the target_ids inside of an attribute on itself.
|
6
|
+
# The target is the object which is referencing by this association.
|
7
|
+
module Associations
|
8
|
+
module Association
|
9
|
+
attr_accessor :name, :options, :source, :loaded
|
10
|
+
|
11
|
+
# Create a new association.
|
12
|
+
#
|
13
|
+
# @param [Class] source the source record of the association; that is, the record that you already have
|
14
|
+
# @param [Symbol] name the name of the association
|
15
|
+
# @param [Hash] options optional parameters for the association
|
16
|
+
# @option options [Class] :class the target class of the association; that is, the class to which the association objects belong
|
17
|
+
# @option options [Symbol] :class_name the name of the target class of the association; only this or Class is necessary
|
18
|
+
# @option options [Symbol] :inverse_of the name of the association on the target class
|
19
|
+
#
|
20
|
+
# @return [Dynamoid::Association] the actual association instance itself
|
21
|
+
#
|
22
|
+
# @since 0.2.0
|
23
|
+
def initialize(source, name, options)
|
24
|
+
@name = name
|
25
|
+
@options = options
|
26
|
+
@source = source
|
27
|
+
@loaded = false
|
28
|
+
end
|
29
|
+
|
30
|
+
def loaded?
|
31
|
+
@loaded
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_target
|
35
|
+
end
|
36
|
+
|
37
|
+
def target
|
38
|
+
unless loaded?
|
39
|
+
@target = find_target
|
40
|
+
@loaded = true
|
41
|
+
end
|
42
|
+
|
43
|
+
@target
|
44
|
+
end
|
45
|
+
|
46
|
+
def reset
|
47
|
+
@target = nil
|
48
|
+
@loaded = false
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# The target class name, either inferred through the association's name or specified in options.
|
54
|
+
#
|
55
|
+
# @since 0.2.0
|
56
|
+
def target_class_name
|
57
|
+
options[:class_name] || name.to_s.classify
|
58
|
+
end
|
59
|
+
|
60
|
+
# The target class, either inferred through the association's name or specified in options.
|
61
|
+
#
|
62
|
+
# @since 0.2.0
|
63
|
+
def target_class
|
64
|
+
options[:class] || target_class_name.constantize
|
65
|
+
end
|
66
|
+
|
67
|
+
# The target attribute: that is, the attribute on each object of the association that should reference the source.
|
68
|
+
#
|
69
|
+
# @since 0.2.0
|
70
|
+
def target_attribute
|
71
|
+
"#{target_association}_ids".to_sym if target_association
|
72
|
+
end
|
73
|
+
|
74
|
+
# The ids in the target association.
|
75
|
+
#
|
76
|
+
# @since 0.2.0
|
77
|
+
def target_ids
|
78
|
+
target.send(target_attribute) || Set.new
|
79
|
+
end
|
80
|
+
|
81
|
+
# The ids in the target association.
|
82
|
+
#
|
83
|
+
# @since 0.2.0
|
84
|
+
def source_class
|
85
|
+
source.class
|
86
|
+
end
|
87
|
+
|
88
|
+
# The source's association attribute: the name of the association with _ids afterwards, like "users_ids".
|
89
|
+
#
|
90
|
+
# @since 0.2.0
|
91
|
+
def source_attribute
|
92
|
+
"#{name}_ids".to_sym
|
93
|
+
end
|
94
|
+
|
95
|
+
# The ids in the source association.
|
96
|
+
#
|
97
|
+
# @since 0.2.0
|
98
|
+
def source_ids
|
99
|
+
source.send(source_attribute) || Set.new
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dynamoid #:nodoc:
|
3
|
+
|
4
|
+
# The belongs_to association. For belongs_to, we reference only a single target instead of multiple records; that target is the
|
5
|
+
# object to which the association object is associated.
|
6
|
+
module Associations
|
7
|
+
class BelongsTo
|
8
|
+
include SingleAssociation
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Find the target association, either has_many or has_one. Uses either options[:inverse_of] or the source class name and default parsing to
|
13
|
+
# return the most likely name for the target association.
|
14
|
+
#
|
15
|
+
# @since 0.2.0
|
16
|
+
def target_association
|
17
|
+
has_many_key_name = options[:inverse_of] || source.class.to_s.underscore.pluralize.to_sym
|
18
|
+
has_one_key_name = options[:inverse_of] || source.class.to_s.underscore.to_sym
|
19
|
+
if !target_class.associations[has_many_key_name].nil?
|
20
|
+
return has_many_key_name if target_class.associations[has_many_key_name][:type] == :has_many
|
21
|
+
end
|
22
|
+
|
23
|
+
if !target_class.associations[has_one_key_name].nil?
|
24
|
+
return has_one_key_name if target_class.associations[has_one_key_name][:type] == :has_one
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Associate a source object to this association.
|
29
|
+
#
|
30
|
+
# @since 0.2.0
|
31
|
+
def associate_target(object)
|
32
|
+
object.update_attribute(target_attribute, target_ids.merge(Array(source.id)))
|
33
|
+
end
|
34
|
+
|
35
|
+
# Disassociate a source object from this association.
|
36
|
+
#
|
37
|
+
# @since 0.2.0
|
38
|
+
def disassociate_target(object)
|
39
|
+
source.update_attribute(source_attribute, target_ids - Array(source.id))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dynamoid #:nodoc:
|
3
|
+
|
4
|
+
# The has and belongs to many association.
|
5
|
+
module Associations
|
6
|
+
class HasAndBelongsToMany
|
7
|
+
include ManyAssociation
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Find the target association, always another :has_and_belongs_to_many association. Uses either options[:inverse_of] or the source class name
|
12
|
+
# and default parsing to return the most likely name for the target association.
|
13
|
+
#
|
14
|
+
# @since 0.2.0
|
15
|
+
def target_association
|
16
|
+
key_name = options[:inverse_of] || source.class.to_s.pluralize.underscore.to_sym
|
17
|
+
guess = target_class.associations[key_name]
|
18
|
+
return nil if guess.nil? || guess[:type] != :has_and_belongs_to_many
|
19
|
+
key_name
|
20
|
+
end
|
21
|
+
|
22
|
+
# Associate a source object to this association.
|
23
|
+
#
|
24
|
+
# @since 0.2.0
|
25
|
+
def associate_target(object)
|
26
|
+
ids = object.send(target_attribute) || Set.new
|
27
|
+
object.update_attribute(target_attribute, ids.merge(Array(source.id)))
|
28
|
+
end
|
29
|
+
|
30
|
+
# Disassociate a source object from this association.
|
31
|
+
#
|
32
|
+
# @since 0.2.0
|
33
|
+
def disassociate_target(object)
|
34
|
+
ids = object.send(target_attribute) || Set.new
|
35
|
+
object.update_attribute(target_attribute, ids - Array(source.id))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dynamoid #:nodoc:
|
3
|
+
|
4
|
+
# The has_many association.
|
5
|
+
module Associations
|
6
|
+
class HasMany
|
7
|
+
include ManyAssociation
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Find the target association, always a :belongs_to association. Uses either options[:inverse_of] or the source class name
|
12
|
+
# and default parsing to return the most likely name for the target association.
|
13
|
+
#
|
14
|
+
# @since 0.2.0
|
15
|
+
def target_association
|
16
|
+
key_name = options[:inverse_of] || source.class.to_s.singularize.underscore.to_sym
|
17
|
+
guess = target_class.associations[key_name]
|
18
|
+
return nil if guess.nil? || guess[:type] != :belongs_to
|
19
|
+
key_name
|
20
|
+
end
|
21
|
+
|
22
|
+
# Associate a source object to this association.
|
23
|
+
#
|
24
|
+
# @since 0.2.0
|
25
|
+
def associate_target(object)
|
26
|
+
object.update_attribute(target_attribute, Set[source.id])
|
27
|
+
end
|
28
|
+
|
29
|
+
# Disassociate a source object from this association.
|
30
|
+
#
|
31
|
+
# @since 0.2.0
|
32
|
+
def disassociate_target(object)
|
33
|
+
object.update_attribute(target_attribute, nil)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dynamoid #:nodoc:
|
3
|
+
|
4
|
+
# The HasOne association.
|
5
|
+
module Associations
|
6
|
+
class HasOne
|
7
|
+
include Association
|
8
|
+
include SingleAssociation
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Find the target association, always a :belongs_to association. Uses either options[:inverse_of] or the source class name
|
13
|
+
# and default parsing to return the most likely name for the target association.
|
14
|
+
#
|
15
|
+
# @since 0.2.0
|
16
|
+
def target_association
|
17
|
+
key_name = options[:inverse_of] || source.class.to_s.singularize.underscore.to_sym
|
18
|
+
guess = target_class.associations[key_name]
|
19
|
+
return nil if guess.nil? || guess[:type] != :belongs_to
|
20
|
+
key_name
|
21
|
+
end
|
22
|
+
|
23
|
+
# Associate a source object to this association.
|
24
|
+
#
|
25
|
+
# @since 0.2.0
|
26
|
+
def associate_target(object)
|
27
|
+
object.update_attribute(target_attribute, Set[source.id])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Disassociate a source object from this association.
|
31
|
+
#
|
32
|
+
# @since 0.2.0
|
33
|
+
def disassociate_target(object)
|
34
|
+
source.update_attribute(source_attribute, nil)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dynamoid #:nodoc:
|
3
|
+
|
4
|
+
module Associations
|
5
|
+
module ManyAssociation
|
6
|
+
include Association
|
7
|
+
|
8
|
+
attr_accessor :query
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
@query = {}
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
include Enumerable
|
16
|
+
# Delegate methods to the records the association represents.
|
17
|
+
delegate :first, :last, :empty?, :size, :class, :to => :records
|
18
|
+
|
19
|
+
# The records associated to the source.
|
20
|
+
#
|
21
|
+
# @return the association records; depending on which association this is, either a single instance or an array
|
22
|
+
#
|
23
|
+
# @since 0.2.0
|
24
|
+
def find_target
|
25
|
+
Array(target_class.find(source_ids.to_a))
|
26
|
+
end
|
27
|
+
|
28
|
+
def records
|
29
|
+
if query.empty?
|
30
|
+
target
|
31
|
+
else
|
32
|
+
results_with_query(target)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Alias convenience methods for the associations.
|
37
|
+
alias :all :records
|
38
|
+
alias :count :size
|
39
|
+
alias :nil? :empty?
|
40
|
+
|
41
|
+
# Delegate include? to the records.
|
42
|
+
def include?(object)
|
43
|
+
records.include?(object)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Deletes an object or array of objects from the association. This removes their records from the association field on the source,
|
47
|
+
# and attempts to remove the source from the target association if it is detected to exist.
|
48
|
+
#
|
49
|
+
# @param [Dynamoid::Document] object the object (or array of objects) to remove from the association
|
50
|
+
#
|
51
|
+
# @return [Dynamoid::Document] the deleted object
|
52
|
+
#
|
53
|
+
# @since 0.2.0
|
54
|
+
def delete(object)
|
55
|
+
source.update_attribute(source_attribute, source_ids - Array(object).collect(&:id))
|
56
|
+
Array(object).each {|o| self.send(:disassociate_target, o)} if target_association
|
57
|
+
object
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Add an object or array of objects to an association. This preserves the current records in the association (if any)
|
62
|
+
# and adds the object to the target association if it is detected to exist.
|
63
|
+
#
|
64
|
+
# @param [Dynamoid::Document] object the object (or array of objects) to add to the association
|
65
|
+
#
|
66
|
+
# @return [Dynamoid::Document] the added object
|
67
|
+
#
|
68
|
+
# @since 0.2.0
|
69
|
+
def <<(object)
|
70
|
+
source.update_attribute(source_attribute, source_ids.merge(Array(object).collect(&:id)))
|
71
|
+
Array(object).each {|o| self.send(:associate_target, o)} if target_association
|
72
|
+
object
|
73
|
+
end
|
74
|
+
|
75
|
+
# Replace an association with object or array of objects. This removes all of the existing associated records and replaces them with
|
76
|
+
# the passed object(s), and associates the target association if it is detected to exist.
|
77
|
+
#
|
78
|
+
# @param [Dynamoid::Document] object the object (or array of objects) to add to the association
|
79
|
+
#
|
80
|
+
# @return [Dynamoid::Document] the added object
|
81
|
+
#
|
82
|
+
# @since 0.2.0
|
83
|
+
def setter(object)
|
84
|
+
target.each {|o| delete(o)}
|
85
|
+
self << (object)
|
86
|
+
object
|
87
|
+
end
|
88
|
+
|
89
|
+
# Create a new instance of the target class and add it directly to the association. If the create fails an exception will be raised.
|
90
|
+
#
|
91
|
+
# @param [Hash] attribute hash for the new object
|
92
|
+
#
|
93
|
+
# @return [Dynamoid::Document] the newly-created object
|
94
|
+
#
|
95
|
+
# @since 0.2.0
|
96
|
+
def create!(attributes = {})
|
97
|
+
self << target_class.create!(attributes)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Create a new instance of the target class and add it directly to the association.
|
101
|
+
#
|
102
|
+
# @param [Hash] attribute hash for the new object
|
103
|
+
#
|
104
|
+
# @return [Dynamoid::Document] the newly-created object
|
105
|
+
#
|
106
|
+
# @since 0.2.0
|
107
|
+
def create(attributes = {})
|
108
|
+
self << target_class.create(attributes)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Create a new instance of the target class and add it directly to the association. If the create fails an exception will be raised.
|
112
|
+
#
|
113
|
+
# @param [Hash] attribute hash for the new object
|
114
|
+
#
|
115
|
+
# @return [Dynamoid::Document] the newly-created object
|
116
|
+
#
|
117
|
+
# @since 0.2.0
|
118
|
+
def each(&block)
|
119
|
+
records.each(&block)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Destroys all members of the association and removes them from the association.
|
123
|
+
#
|
124
|
+
# @since 0.2.0
|
125
|
+
def destroy_all
|
126
|
+
objs = target
|
127
|
+
source.update_attribute(source_attribute, nil)
|
128
|
+
objs.each(&:destroy)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Deletes all members of the association and removes them from the association.
|
132
|
+
#
|
133
|
+
# @since 0.2.0
|
134
|
+
def delete_all
|
135
|
+
objs = target
|
136
|
+
source.update_attribute(source_attribute, nil)
|
137
|
+
objs.each(&:delete)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Naive association filtering.
|
141
|
+
#
|
142
|
+
# @param [Hash] A hash of attributes; each must match every returned object's attribute exactly.
|
143
|
+
#
|
144
|
+
# @return [Dynamoid::Association] the association this method was called on (for chaining purposes)
|
145
|
+
#
|
146
|
+
# @since 0.2.0
|
147
|
+
def where(args)
|
148
|
+
args.each {|k, v| query[k] = v}
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
# Is this array equal to the association's records?
|
153
|
+
#
|
154
|
+
# @return [Boolean] true/false
|
155
|
+
#
|
156
|
+
# @since 0.2.0
|
157
|
+
def ==(other)
|
158
|
+
records == Array(other)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Delegate methods we don't find directly to the records array.
|
162
|
+
#
|
163
|
+
# @since 0.2.0
|
164
|
+
def method_missing(method, *args)
|
165
|
+
if records.respond_to?(method)
|
166
|
+
records.send(method, *args)
|
167
|
+
else
|
168
|
+
super
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
# If a query exists, filter all existing results based on that query.
|
175
|
+
#
|
176
|
+
# @param [Array] results the raw results for the association
|
177
|
+
#
|
178
|
+
# @return [Array] the filtered results for the query
|
179
|
+
#
|
180
|
+
# @since 0.2.0
|
181
|
+
def results_with_query(results)
|
182
|
+
results.find_all do |result|
|
183
|
+
query.all? do |attribute, value|
|
184
|
+
result.send(attribute) == value
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dynamoid #:nodoc:
|
3
|
+
|
4
|
+
module Associations
|
5
|
+
module SingleAssociation
|
6
|
+
include Association
|
7
|
+
|
8
|
+
delegate :class, :to => :target
|
9
|
+
|
10
|
+
def setter(object)
|
11
|
+
delete
|
12
|
+
source.update_attribute(source_attribute, Set[object.id])
|
13
|
+
self.send(:associate_target, object) if target_association
|
14
|
+
object
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete
|
18
|
+
source.update_attribute(source_attribute, nil)
|
19
|
+
self.send(:disassociate_target, target) if target && target_association
|
20
|
+
target
|
21
|
+
end
|
22
|
+
|
23
|
+
def create!(attributes = {})
|
24
|
+
setter(target_class.create!(attributes))
|
25
|
+
end
|
26
|
+
|
27
|
+
def create(attributes = {})
|
28
|
+
setter(target_class.create!(attributes))
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Is this object equal to the association's target?
|
33
|
+
#
|
34
|
+
# @return [Boolean] true/false
|
35
|
+
#
|
36
|
+
# @since 0.2.0
|
37
|
+
def ==(other)
|
38
|
+
target == other
|
39
|
+
end
|
40
|
+
|
41
|
+
# Delegate methods we don't find directly to the target.
|
42
|
+
#
|
43
|
+
# @since 0.2.0
|
44
|
+
def method_missing(method, *args)
|
45
|
+
if target.respond_to?(method)
|
46
|
+
target.send(method, *args)
|
47
|
+
else
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def nil?
|
53
|
+
target.nil?
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Find the target of the has_one association.
|
59
|
+
#
|
60
|
+
# @return [Dynamoid::Document] the found target (or nil if nothing)
|
61
|
+
#
|
62
|
+
# @since 0.2.0
|
63
|
+
def find_target
|
64
|
+
return if source_ids.empty?
|
65
|
+
target_class.find(source_ids.first)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'dynamoid/associations/association'
|
3
|
+
require 'dynamoid/associations/single_association'
|
4
|
+
require 'dynamoid/associations/many_association'
|
5
|
+
require 'dynamoid/associations/has_many'
|
6
|
+
require 'dynamoid/associations/belongs_to'
|
7
|
+
require 'dynamoid/associations/has_one'
|
8
|
+
require 'dynamoid/associations/has_and_belongs_to_many'
|
9
|
+
|
10
|
+
module Dynamoid
|
11
|
+
|
12
|
+
# Connects models together through the magic of associations. We enjoy four different kinds of associations presently:
|
13
|
+
# * belongs_to
|
14
|
+
# * has_and_belongs_to_many
|
15
|
+
# * has_many
|
16
|
+
# * has_one
|
17
|
+
module Associations
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
|
20
|
+
# Create the association tracking attribute and initialize it to an empty hash.
|
21
|
+
included do
|
22
|
+
class_attribute :associations
|
23
|
+
|
24
|
+
self.associations = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
|
29
|
+
# create a has_many association for this document.
|
30
|
+
#
|
31
|
+
# @param [Symbol] name the name of the association
|
32
|
+
# @param [Hash] options options to pass to the association constructor
|
33
|
+
# @option options [Class] :class the target class of the has_many association; that is, the belongs_to class
|
34
|
+
# @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the belongs_to class
|
35
|
+
# @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a belongs_to association, the name of that association
|
36
|
+
#
|
37
|
+
# @since 0.2.0
|
38
|
+
def has_many(name, options = {})
|
39
|
+
association(:has_many, name, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
# create a has_one association for this document.
|
43
|
+
#
|
44
|
+
# @param [Symbol] name the name of the association
|
45
|
+
# @param [Hash] options options to pass to the association constructor
|
46
|
+
# @option options [Class] :class the target class of the has_one association; that is, the belongs_to class
|
47
|
+
# @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the belongs_to class
|
48
|
+
# @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a belongs_to association, the name of that association
|
49
|
+
#
|
50
|
+
# @since 0.2.0
|
51
|
+
def has_one(name, options = {})
|
52
|
+
association(:has_one, name, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
# create a belongs_to association for this document.
|
56
|
+
#
|
57
|
+
# @param [Symbol] name the name of the association
|
58
|
+
# @param [Hash] options options to pass to the association constructor
|
59
|
+
# @option options [Class] :class the target class of the has_one association; that is, the has_many or has_one class
|
60
|
+
# @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the has_many or has_one class
|
61
|
+
# @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a has_many or has_one association, the name of that association
|
62
|
+
#
|
63
|
+
# @since 0.2.0
|
64
|
+
def belongs_to(name, options = {})
|
65
|
+
association(:belongs_to, name, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
# create a has_and_belongs_to_many association for this document.
|
69
|
+
#
|
70
|
+
# @param [Symbol] name the name of the association
|
71
|
+
# @param [Hash] options options to pass to the association constructor
|
72
|
+
# @option options [Class] :class the target class of the has_and_belongs_to_many association; that is, the belongs_to class
|
73
|
+
# @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the belongs_to class
|
74
|
+
# @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a belongs_to association, the name of that association
|
75
|
+
#
|
76
|
+
# @since 0.2.0
|
77
|
+
def has_and_belongs_to_many(name, options = {})
|
78
|
+
association(:has_and_belongs_to_many, name, options)
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# create getters and setters for an association.
|
84
|
+
#
|
85
|
+
# @param [Symbol] symbol the type (:has_one, :has_many, :has_and_belongs_to_many, :belongs_to) of the association
|
86
|
+
# @param [Symbol] name the name of the association
|
87
|
+
# @param [Hash] options options to pass to the association constructor; see above for all valid options
|
88
|
+
#
|
89
|
+
# @since 0.2.0
|
90
|
+
def association(type, name, options = {})
|
91
|
+
field "#{name}_ids".to_sym, :set
|
92
|
+
self.associations[name] = options.merge(:type => type)
|
93
|
+
define_method(name) do
|
94
|
+
@associations[:"#{name}_ids"] ||= Dynamoid::Associations.const_get(type.to_s.camelcase).new(self, name, options)
|
95
|
+
end
|
96
|
+
define_method("#{name}=".to_sym) do |objects|
|
97
|
+
@associations[:"#{name}_ids"] ||= Dynamoid::Associations.const_get(type.to_s.camelcase).new(self, name, options)
|
98
|
+
@associations[:"#{name}_ids"].setter(objects)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dynamoid
|
3
|
+
|
4
|
+
# All modules that a Document is composed of are defined in this
|
5
|
+
# module, to keep the document class from getting too cluttered.
|
6
|
+
module Components
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
extend ActiveModel::Translation
|
11
|
+
extend ActiveModel::Callbacks
|
12
|
+
|
13
|
+
define_model_callbacks :create, :save, :destroy, :initialize, :update
|
14
|
+
|
15
|
+
before_create :set_created_at
|
16
|
+
before_save :set_updated_at
|
17
|
+
after_initialize :set_type
|
18
|
+
end
|
19
|
+
|
20
|
+
include ActiveModel::AttributeMethods
|
21
|
+
include ActiveModel::Conversion
|
22
|
+
include ActiveModel::MassAssignmentSecurity if defined?(ActiveModel::MassAssignmentSecurity)
|
23
|
+
include ActiveModel::Naming
|
24
|
+
include ActiveModel::Observing if defined?(ActiveModel::Observing)
|
25
|
+
include ActiveModel::Serializers::JSON
|
26
|
+
include ActiveModel::Serializers::Xml
|
27
|
+
include Dynamoid::Fields
|
28
|
+
include Dynamoid::Indexes
|
29
|
+
include Dynamoid::Persistence
|
30
|
+
include Dynamoid::Finders
|
31
|
+
include Dynamoid::Associations
|
32
|
+
include Dynamoid::Criteria
|
33
|
+
include Dynamoid::Validations
|
34
|
+
include Dynamoid::IdentityMap
|
35
|
+
include Dynamoid::Dirty
|
36
|
+
end
|
37
|
+
end
|