dynamoid 3.2.0 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 = {})
|