dynamoid 3.2.0 → 3.6.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 +4 -4
- data/CHANGELOG.md +111 -1
- data/README.md +580 -241
- data/lib/dynamoid.rb +2 -0
- data/lib/dynamoid/adapter.rb +15 -15
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +82 -102
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb +108 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +29 -16
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +3 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +2 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +2 -3
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +2 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +15 -6
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +15 -5
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/table.rb +1 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb +5 -3
- data/lib/dynamoid/application_time_zone.rb +1 -0
- data/lib/dynamoid/associations.rb +182 -19
- data/lib/dynamoid/associations/association.rb +4 -2
- data/lib/dynamoid/associations/belongs_to.rb +2 -1
- data/lib/dynamoid/associations/has_and_belongs_to_many.rb +2 -1
- data/lib/dynamoid/associations/has_many.rb +2 -1
- data/lib/dynamoid/associations/has_one.rb +2 -1
- data/lib/dynamoid/associations/many_association.rb +65 -22
- data/lib/dynamoid/associations/single_association.rb +28 -1
- data/lib/dynamoid/components.rb +8 -3
- data/lib/dynamoid/config.rb +16 -3
- data/lib/dynamoid/config/backoff_strategies/constant_backoff.rb +1 -0
- data/lib/dynamoid/config/backoff_strategies/exponential_backoff.rb +1 -0
- data/lib/dynamoid/config/options.rb +1 -0
- data/lib/dynamoid/criteria.rb +2 -1
- data/lib/dynamoid/criteria/chain.rb +418 -46
- data/lib/dynamoid/criteria/ignored_conditions_detector.rb +3 -3
- data/lib/dynamoid/criteria/key_fields_detector.rb +109 -32
- data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +3 -2
- data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +1 -1
- data/lib/dynamoid/dirty.rb +239 -32
- data/lib/dynamoid/document.rb +130 -251
- data/lib/dynamoid/dumping.rb +9 -0
- data/lib/dynamoid/dynamodb_time_zone.rb +1 -0
- data/lib/dynamoid/fields.rb +246 -20
- data/lib/dynamoid/finders.rb +69 -32
- data/lib/dynamoid/identity_map.rb +6 -0
- data/lib/dynamoid/indexes.rb +76 -17
- data/lib/dynamoid/loadable.rb +31 -0
- data/lib/dynamoid/log/formatter.rb +26 -0
- data/lib/dynamoid/middleware/identity_map.rb +1 -0
- data/lib/dynamoid/persistence.rb +592 -122
- data/lib/dynamoid/persistence/import.rb +73 -0
- data/lib/dynamoid/persistence/save.rb +64 -0
- data/lib/dynamoid/persistence/update_fields.rb +63 -0
- data/lib/dynamoid/persistence/upsert.rb +60 -0
- data/lib/dynamoid/primary_key_type_mapping.rb +1 -0
- data/lib/dynamoid/railtie.rb +1 -0
- data/lib/dynamoid/tasks.rb +3 -1
- data/lib/dynamoid/tasks/database.rb +1 -0
- data/lib/dynamoid/type_casting.rb +12 -2
- data/lib/dynamoid/undumping.rb +8 -0
- data/lib/dynamoid/validations.rb +2 -0
- data/lib/dynamoid/version.rb +1 -1
- metadata +49 -71
- data/.coveralls.yml +0 -1
- data/.document +0 -5
- data/.gitignore +0 -74
- data/.rspec +0 -2
- data/.rubocop.yml +0 -71
- data/.rubocop_todo.yml +0 -55
- data/.travis.yml +0 -41
- data/Appraisals +0 -28
- data/Gemfile +0 -8
- data/Rakefile +0 -46
- data/Vagrantfile +0 -29
- data/docker-compose.yml +0 -7
- data/dynamoid.gemspec +0 -57
- data/gemfiles/rails_4_2.gemfile +0 -11
- data/gemfiles/rails_5_0.gemfile +0 -10
- data/gemfiles/rails_5_1.gemfile +0 -10
- data/gemfiles/rails_5_2.gemfile +0 -10
@@ -3,6 +3,7 @@
|
|
3
3
|
require_relative 'until_past_table_status'
|
4
4
|
|
5
5
|
module Dynamoid
|
6
|
+
# @private
|
6
7
|
module AdapterPlugin
|
7
8
|
class AwsSdkV3
|
8
9
|
class CreateTable
|
@@ -16,6 +17,7 @@ module Dynamoid
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def call
|
20
|
+
billing_mode = options[:billing_mode]
|
19
21
|
read_capacity = options[:read_capacity] || Dynamoid::Config.read_capacity
|
20
22
|
write_capacity = options[:write_capacity] || Dynamoid::Config.write_capacity
|
21
23
|
|
@@ -41,14 +43,20 @@ module Dynamoid
|
|
41
43
|
|
42
44
|
client_opts = {
|
43
45
|
table_name: table_name,
|
44
|
-
provisioned_throughput: {
|
45
|
-
read_capacity_units: read_capacity,
|
46
|
-
write_capacity_units: write_capacity
|
47
|
-
},
|
48
46
|
key_schema: key_schema,
|
49
47
|
attribute_definitions: attribute_definitions
|
50
48
|
}
|
51
49
|
|
50
|
+
if billing_mode == :on_demand
|
51
|
+
client_opts[:billing_mode] = 'PAY_PER_REQUEST'
|
52
|
+
else
|
53
|
+
client_opts[:billing_mode] = 'PROVISIONED'
|
54
|
+
client_opts[:provisioned_throughput] = {
|
55
|
+
read_capacity_units: read_capacity,
|
56
|
+
write_capacity_units: write_capacity
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
52
60
|
if ls_indexes.present?
|
53
61
|
client_opts[:local_secondary_indexes] = ls_indexes.map do |index|
|
54
62
|
index_to_aws_hash(index)
|
@@ -62,11 +70,16 @@ module Dynamoid
|
|
62
70
|
end
|
63
71
|
resp = client.create_table(client_opts)
|
64
72
|
options[:sync] = true if !options.key?(:sync) && ls_indexes.present? || gs_indexes.present?
|
65
|
-
|
66
|
-
|
67
|
-
|
73
|
+
|
74
|
+
if options[:sync]
|
75
|
+
status = PARSE_TABLE_STATUS.call(resp, :table_description)
|
76
|
+
if status == TABLE_STATUSES[:creating]
|
77
|
+
UntilPastTableStatus.new(client, table_name, :creating).call
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
68
81
|
# Response to original create_table, which, if options[:sync]
|
69
|
-
#
|
82
|
+
# may have an outdated table_description.table_status of "CREATING"
|
70
83
|
resp
|
71
84
|
end
|
72
85
|
|
@@ -75,9 +88,9 @@ module Dynamoid
|
|
75
88
|
# Builds aws attributes definitions based off of primary hash/range and
|
76
89
|
# secondary indexes
|
77
90
|
#
|
78
|
-
# @param
|
79
|
-
# @option
|
80
|
-
# @option
|
91
|
+
# @param key_schema
|
92
|
+
# @option key_schema [Hash] hash_key_schema - eg: {:id => :string}
|
93
|
+
# @option key_schema [Hash] range_key_schema - eg: {:created_at => :number}
|
81
94
|
# @param [Hash] secondary_indexes
|
82
95
|
# @option secondary_indexes [Array<Dynamoid::Indexes::Index>] :local_secondary_indexes
|
83
96
|
# @option secondary_indexes [Array<Dynamoid::Indexes::Index>] :global_secondary_indexes
|
@@ -118,8 +131,8 @@ module Dynamoid
|
|
118
131
|
end
|
119
132
|
|
120
133
|
# Builds an attribute definitions based on hash key and range key
|
121
|
-
# @
|
122
|
-
# @
|
134
|
+
# @param [Hash] hash_key_schema - eg: {:id => :string}
|
135
|
+
# @param [Hash] range_key_schema - eg: {:created_at => :datetime}
|
123
136
|
# @return [Array]
|
124
137
|
def build_attribute_definitions(hash_key_schema, range_key_schema = nil)
|
125
138
|
attrs = []
|
@@ -140,8 +153,8 @@ module Dynamoid
|
|
140
153
|
end
|
141
154
|
|
142
155
|
# Builds an aws attribute definition based on name and dynamoid type
|
143
|
-
# @
|
144
|
-
# @
|
156
|
+
# @param [Symbol] name - eg: :id
|
157
|
+
# @param [Symbol] dynamoid_type - eg: :string
|
145
158
|
# @return [Hash]
|
146
159
|
def attribute_definition_element(name, dynamoid_type)
|
147
160
|
aws_type = api_type(dynamoid_type)
|
@@ -201,7 +214,7 @@ module Dynamoid
|
|
201
214
|
end
|
202
215
|
|
203
216
|
# Only global secondary indexes have a separate throughput.
|
204
|
-
if index.type == :global_secondary
|
217
|
+
if index.type == :global_secondary && options[:billing_mode] != :on_demand
|
205
218
|
hash[:provisioned_throughput] = {
|
206
219
|
read_capacity_units: index.read_capacity,
|
207
220
|
write_capacity_units: index.write_capacity
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dynamoid
|
4
|
+
# @private
|
4
5
|
module AdapterPlugin
|
5
6
|
class AwsSdkV3
|
6
7
|
# Mimics behavior of the yielded object on DynamoDB's update_item API (high level).
|
@@ -20,8 +21,8 @@ module Dynamoid
|
|
20
21
|
# Adds the given values to the values already stored in the corresponding columns.
|
21
22
|
# The column must contain a Set or a number.
|
22
23
|
#
|
23
|
-
# @param [Hash]
|
24
|
-
#
|
24
|
+
# @param [Hash] values keys of the hash are the columns to update, values
|
25
|
+
# are the values to add. values must be a Set, Array, or Numeric
|
25
26
|
#
|
26
27
|
def add(values)
|
27
28
|
@additions.merge!(sanitize_attributes(values))
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dynamoid
|
4
|
+
# @private
|
4
5
|
module AdapterPlugin
|
5
6
|
class AwsSdkV3
|
6
7
|
module Middleware
|
@@ -14,11 +15,10 @@ module Dynamoid
|
|
14
15
|
response = @next_chain.call(request)
|
15
16
|
@backoff.call if @backoff
|
16
17
|
|
17
|
-
|
18
|
+
response
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
24
|
-
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dynamoid
|
4
|
+
# @private
|
4
5
|
module AdapterPlugin
|
5
6
|
class AwsSdkV3
|
6
7
|
module Middleware
|
@@ -46,12 +47,10 @@ module Dynamoid
|
|
46
47
|
@scan_count += response.scanned_count
|
47
48
|
throw :stop_pagination if @scan_limit && @scan_count >= @scan_limit
|
48
49
|
|
49
|
-
|
50
|
+
response
|
50
51
|
end
|
51
52
|
end
|
52
|
-
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dynamoid
|
4
|
+
# @private
|
4
5
|
module AdapterPlugin
|
5
6
|
class AwsSdkV3
|
6
7
|
module Middleware
|
@@ -18,11 +19,10 @@ module Dynamoid
|
|
18
19
|
throw :stop_pagination
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
+
response
|
22
23
|
end
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
28
|
-
|
@@ -5,12 +5,14 @@ require_relative 'middleware/limit'
|
|
5
5
|
require_relative 'middleware/start_key'
|
6
6
|
|
7
7
|
module Dynamoid
|
8
|
+
# @private
|
8
9
|
module AdapterPlugin
|
9
10
|
class AwsSdkV3
|
10
11
|
class Query
|
11
12
|
OPTIONS_KEYS = %i[
|
12
13
|
limit hash_key hash_value range_key consistent_read scan_index_forward
|
13
14
|
select index_name batch_size exclusive_start_key record_limit scan_limit
|
15
|
+
project
|
14
16
|
].freeze
|
15
17
|
|
16
18
|
attr_reader :client, :table, :options, :conditions
|
@@ -28,8 +30,8 @@ module Dynamoid
|
|
28
30
|
request = build_request
|
29
31
|
|
30
32
|
Enumerator.new do |yielder|
|
31
|
-
api_call =
|
32
|
-
client.query(
|
33
|
+
api_call = lambda do |req|
|
34
|
+
client.query(req).tap do |response|
|
33
35
|
yielder << response
|
34
36
|
end
|
35
37
|
end
|
@@ -63,10 +65,11 @@ module Dynamoid
|
|
63
65
|
batch_size = options[:batch_size]
|
64
66
|
limit = [record_limit, scan_limit, batch_size].compact.min
|
65
67
|
|
66
|
-
request[:limit]
|
67
|
-
request[:table_name]
|
68
|
-
request[:key_conditions]
|
69
|
-
request[:query_filter]
|
68
|
+
request[:limit] = limit if limit
|
69
|
+
request[:table_name] = table.name
|
70
|
+
request[:key_conditions] = key_conditions
|
71
|
+
request[:query_filter] = query_filter
|
72
|
+
request[:attributes_to_get] = attributes_to_get
|
70
73
|
|
71
74
|
request
|
72
75
|
end
|
@@ -117,6 +120,12 @@ module Dynamoid
|
|
117
120
|
result
|
118
121
|
end
|
119
122
|
end
|
123
|
+
|
124
|
+
def attributes_to_get
|
125
|
+
return if options[:project].nil?
|
126
|
+
|
127
|
+
options[:project].map(&:to_s)
|
128
|
+
end
|
120
129
|
end
|
121
130
|
end
|
122
131
|
end
|
@@ -5,6 +5,7 @@ require_relative 'middleware/limit'
|
|
5
5
|
require_relative 'middleware/start_key'
|
6
6
|
|
7
7
|
module Dynamoid
|
8
|
+
# @private
|
8
9
|
module AdapterPlugin
|
9
10
|
class AwsSdkV3
|
10
11
|
class Scan
|
@@ -21,8 +22,8 @@ module Dynamoid
|
|
21
22
|
request = build_request
|
22
23
|
|
23
24
|
Enumerator.new do |yielder|
|
24
|
-
api_call =
|
25
|
-
client.scan(
|
25
|
+
api_call = lambda do |req|
|
26
|
+
client.scan(req).tap do |response|
|
26
27
|
yielder << response
|
27
28
|
end
|
28
29
|
end
|
@@ -54,9 +55,10 @@ module Dynamoid
|
|
54
55
|
batch_size = options[:batch_size]
|
55
56
|
limit = [record_limit, scan_limit, batch_size].compact.min
|
56
57
|
|
57
|
-
request[:limit]
|
58
|
-
request[:table_name]
|
59
|
-
request[:scan_filter]
|
58
|
+
request[:limit] = limit if limit
|
59
|
+
request[:table_name] = table.name
|
60
|
+
request[:scan_filter] = scan_filter
|
61
|
+
request[:attributes_to_get] = attributes_to_get
|
60
62
|
|
61
63
|
request
|
62
64
|
end
|
@@ -75,10 +77,18 @@ module Dynamoid
|
|
75
77
|
comparison_operator: AwsSdkV3::FIELD_MAP[cond.keys[0]],
|
76
78
|
attribute_value_list: AwsSdkV3.attribute_value_list(AwsSdkV3::FIELD_MAP[cond.keys[0]], cond.values[0].freeze)
|
77
79
|
}
|
80
|
+
# nil means operator doesn't require attribute value list
|
81
|
+
conditions.delete(:attribute_value_list) if conditions[:attribute_value_list].nil?
|
78
82
|
result[attr] = condition
|
79
83
|
result
|
80
84
|
end
|
81
85
|
end
|
86
|
+
|
87
|
+
def attributes_to_get
|
88
|
+
return if options[:project].nil?
|
89
|
+
|
90
|
+
options[:project].map(&:to_s)
|
91
|
+
end
|
82
92
|
end
|
83
93
|
end
|
84
94
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dynamoid
|
4
|
+
# @private
|
4
5
|
module AdapterPlugin
|
5
6
|
class AwsSdkV3
|
6
7
|
class UntilPastTableStatus
|
7
|
-
attr_reader :table_name, :status
|
8
|
+
attr_reader :client, :table_name, :status
|
8
9
|
|
9
|
-
def initialize(table_name, status = :creating)
|
10
|
+
def initialize(client, table_name, status = :creating)
|
11
|
+
@client = client
|
10
12
|
@table_name = table_name
|
11
13
|
@status = status
|
12
14
|
end
|
@@ -31,7 +33,7 @@ module Dynamoid
|
|
31
33
|
# See: http://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#describe_table-instance_method
|
32
34
|
rescue Aws::DynamoDB::Errors::ResourceNotFoundException => e
|
33
35
|
case status
|
34
|
-
when :creating
|
36
|
+
when :creating
|
35
37
|
if counter >= Dynamoid::Config.sync_retry_max_times
|
36
38
|
Dynamoid.logger.warn "Waiting on table metadata for #{table_name} (check #{counter})"
|
37
39
|
retry # start over at first line of begin, does not reset counter
|
@@ -25,12 +25,55 @@ module Dynamoid
|
|
25
25
|
end
|
26
26
|
|
27
27
|
module ClassMethods
|
28
|
-
#
|
28
|
+
# Declare a +has_many+ association for this document.
|
29
29
|
#
|
30
|
-
#
|
31
|
-
#
|
30
|
+
# class Category
|
31
|
+
# include Dynamoid::Document
|
32
|
+
#
|
33
|
+
# has_many :posts
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# Association is an enumerable collection and supports following addition
|
37
|
+
# operations:
|
38
|
+
#
|
39
|
+
# * +create+
|
40
|
+
# * +create!+
|
41
|
+
# * +destroy_all+
|
42
|
+
# * +delete_all+
|
43
|
+
# * +delete+
|
44
|
+
# * +<<+
|
45
|
+
# * +where+
|
46
|
+
# * +all+
|
47
|
+
# * +empty?+
|
48
|
+
# * +size+
|
49
|
+
#
|
50
|
+
# When a name of an associated class doesn't match an association name a
|
51
|
+
# class name should be specified explicitly either with +class+ or
|
52
|
+
# +class_name+ option:
|
53
|
+
#
|
54
|
+
# has_many :labels, class: Tag
|
55
|
+
# has_many :labels, class_name: 'Tag'
|
56
|
+
#
|
57
|
+
# When associated class has own +belongs_to+ association to
|
58
|
+
# the current class and the name doesn't match a name of the current
|
59
|
+
# class this name can be specified with +inverse_of+ option:
|
60
|
+
#
|
61
|
+
# class Post
|
62
|
+
# include Dynamoid::Document
|
63
|
+
#
|
64
|
+
# belongs_to :item, class_name: 'Tag'
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# class Tag
|
68
|
+
# include Dynamoid::Document
|
69
|
+
#
|
70
|
+
# has_many :posts, inverse_of: :item
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# @param name [Symbol] the name of the association
|
74
|
+
# @param options [Hash] options to pass to the association constructor
|
32
75
|
# @option options [Class] :class the target class of the has_many association; that is, the belongs_to class
|
33
|
-
# @option options [
|
76
|
+
# @option options [String] :class_name the name of the target class of the association; that is, the name of the belongs_to class
|
34
77
|
# @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
|
35
78
|
#
|
36
79
|
# @since 0.2.0
|
@@ -38,12 +81,47 @@ module Dynamoid
|
|
38
81
|
association(:has_many, name, options)
|
39
82
|
end
|
40
83
|
|
41
|
-
#
|
84
|
+
# Declare a +has_one+ association for this document.
|
85
|
+
#
|
86
|
+
# class Image
|
87
|
+
# include Dynamoid::Document
|
42
88
|
#
|
43
|
-
#
|
44
|
-
#
|
89
|
+
# has_one :post
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# Association supports following operations:
|
93
|
+
#
|
94
|
+
# * +create+
|
95
|
+
# * +create!+
|
96
|
+
# * +delete+
|
97
|
+
#
|
98
|
+
# When a name of an associated class doesn't match an association name a
|
99
|
+
# class name should be specified explicitly either with +class+ or
|
100
|
+
# +class_name+ option:
|
101
|
+
#
|
102
|
+
# has_one :item, class: Post
|
103
|
+
# has_one :item, class_name: 'Post'
|
104
|
+
#
|
105
|
+
# When associated class has own +belong_to+ association to the current
|
106
|
+
# class and the name doesn't match a name of the current class this name
|
107
|
+
# can be specified with +inverse_of+ option:
|
108
|
+
#
|
109
|
+
# class Post
|
110
|
+
# include Dynamoid::Document
|
111
|
+
#
|
112
|
+
# belongs_to :logo, class_name: 'Image'
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# class Image
|
116
|
+
# include Dynamoid::Document
|
117
|
+
#
|
118
|
+
# has_one :post, inverse_of: :logo
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# @param name [Symbol] the name of the association
|
122
|
+
# @param options [Hash] options to pass to the association constructor
|
45
123
|
# @option options [Class] :class the target class of the has_one association; that is, the belongs_to class
|
46
|
-
# @option options [
|
124
|
+
# @option options [String] :class_name the name of the target class of the association; that is, the name of the belongs_to class
|
47
125
|
# @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
|
48
126
|
#
|
49
127
|
# @since 0.2.0
|
@@ -51,25 +129,110 @@ module Dynamoid
|
|
51
129
|
association(:has_one, name, options)
|
52
130
|
end
|
53
131
|
|
54
|
-
#
|
132
|
+
# Declare a +belongs_to+ association for this document.
|
133
|
+
#
|
134
|
+
# class Post
|
135
|
+
# include Dynamoid::Document
|
55
136
|
#
|
56
|
-
#
|
57
|
-
#
|
137
|
+
# belongs_to :categories
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# Association supports following operations:
|
141
|
+
#
|
142
|
+
# * +create+
|
143
|
+
# * +create!+
|
144
|
+
# * +delete+
|
145
|
+
#
|
146
|
+
# When a name of an associated class doesn't match an association name a
|
147
|
+
# class name should be specified explicitly either with +class+ or
|
148
|
+
# +class_name+ option:
|
149
|
+
#
|
150
|
+
# belongs_to :item, class: Post
|
151
|
+
# belongs_to :item, class_name: 'Post'
|
152
|
+
#
|
153
|
+
# When associated class has own +has_many+ or +has_one+ association to
|
154
|
+
# the current class and the name doesn't match a name of the current
|
155
|
+
# class this name can be specified with +inverse_of+ option:
|
156
|
+
#
|
157
|
+
# class Category
|
158
|
+
# include Dynamoid::Document
|
159
|
+
#
|
160
|
+
# has_many :items, class_name: 'Post'
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# class Post
|
164
|
+
# include Dynamoid::Document
|
165
|
+
#
|
166
|
+
# belongs_to :categories, inverse_of: :items
|
167
|
+
# end
|
168
|
+
#
|
169
|
+
# By default a hash key attribute name is +id+. If an associated class
|
170
|
+
# uses another name for a hash key attribute it should be specified in
|
171
|
+
# the +belongs_to+ association:
|
172
|
+
#
|
173
|
+
# belongs_to :categories, foreign_key: :uuid
|
174
|
+
#
|
175
|
+
# @param name [Symbol] the name of the association
|
176
|
+
# @param options [Hash] options to pass to the association constructor
|
58
177
|
# @option options [Class] :class the target class of the has_one association; that is, the has_many or has_one class
|
59
|
-
# @option options [
|
178
|
+
# @option options [String] :class_name the name of the target class of the association; that is, the name of the has_many or has_one class
|
60
179
|
# @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
|
180
|
+
# @option options [Symbol] :foreign_key the name of a hash key attribute in the target class
|
61
181
|
#
|
62
182
|
# @since 0.2.0
|
63
183
|
def belongs_to(name, options = {})
|
64
184
|
association(:belongs_to, name, options)
|
65
185
|
end
|
66
186
|
|
67
|
-
#
|
187
|
+
# Declare a +has_and_belongs_to_many+ association for this document.
|
188
|
+
#
|
189
|
+
# class Post
|
190
|
+
# include Dynamoid::Document
|
191
|
+
#
|
192
|
+
# has_and_belongs_to_many :tags
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# Association is an enumerable collection and supports following addition
|
196
|
+
# operations:
|
197
|
+
#
|
198
|
+
# * +create+
|
199
|
+
# * +create!+
|
200
|
+
# * +destroy_all+
|
201
|
+
# * +delete_all+
|
202
|
+
# * +delete+
|
203
|
+
# * +<<+
|
204
|
+
# * +where+
|
205
|
+
# * +all+
|
206
|
+
# * +empty?+
|
207
|
+
# * +size+
|
208
|
+
#
|
209
|
+
# When a name of an associated class doesn't match an association name a
|
210
|
+
# class name should be specified explicitly either with +class+ or
|
211
|
+
# +class_name+ option:
|
212
|
+
#
|
213
|
+
# has_and_belongs_to_many :labels, class: Tag
|
214
|
+
# has_and_belongs_to_many :labels, class_name: 'Tag'
|
215
|
+
#
|
216
|
+
# When associated class has own +has_and_belongs_to_many+ association to
|
217
|
+
# the current class and the name doesn't match a name of the current
|
218
|
+
# class this name can be specified with +inverse_of+ option:
|
219
|
+
#
|
220
|
+
# class Tag
|
221
|
+
# include Dynamoid::Document
|
222
|
+
#
|
223
|
+
# has_and_belongs_to_many :items, class_name: 'Post'
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# class Post
|
227
|
+
# include Dynamoid::Document
|
228
|
+
#
|
229
|
+
# has_and_belongs_to_many :tags, inverse_of: :items
|
230
|
+
# end
|
68
231
|
#
|
69
|
-
# @param [Symbol]
|
70
|
-
# @param [Hash] options
|
232
|
+
# @param name [Symbol] the name of the association
|
233
|
+
# @param options [Hash] options to pass to the association constructor
|
71
234
|
# @option options [Class] :class the target class of the has_and_belongs_to_many association; that is, the belongs_to class
|
72
|
-
# @option options [
|
235
|
+
# @option options [String] :class_name the name of the target class of the association; that is, the name of the belongs_to class
|
73
236
|
# @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
|
74
237
|
#
|
75
238
|
# @since 0.2.0
|
@@ -81,9 +244,9 @@ module Dynamoid
|
|
81
244
|
|
82
245
|
# create getters and setters for an association.
|
83
246
|
#
|
84
|
-
# @param [Symbol]
|
85
|
-
# @param [Symbol]
|
86
|
-
# @param [Hash] options
|
247
|
+
# @param type [Symbol] the type (:has_one, :has_many, :has_and_belongs_to_many, :belongs_to) of the association
|
248
|
+
# @param name [Symbol] the name of the association
|
249
|
+
# @param options [Hash] options to pass to the association constructor; see above for all valid options
|
87
250
|
#
|
88
251
|
# @since 0.2.0
|
89
252
|
def association(type, name, options = {})
|