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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26990dd042447eeba355601d0c7eb3657bcc482e80d00c1da5602d2f82765504
|
4
|
+
data.tar.gz: 76e1778155fb8a7a1d3135d4886d9e7caf1a07b72263fc38d9162ae946d5dab1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2aadf93639577566ed5dd9dadff596316f3d22384f5d7dabd0e06aa49992d3a58e824a8c150002c3a39d6e42f7b2b17c4f383bda2c145f4d05e1d56bf21a5e54
|
7
|
+
data.tar.gz: 14801f95c8cd1a241d2b1522b05a1e7af307822cef50e4515502f641027ade16aaf750a099801a2f2e4e379b15a4cd96e78f84754278db37d2e6fcdaab57b242
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,120 @@
|
|
1
1
|
# HEAD
|
2
2
|
|
3
|
-
##
|
3
|
+
## Features
|
4
|
+
|
5
|
+
## Improvements
|
6
|
+
|
7
|
+
## Fixes
|
8
|
+
|
9
|
+
|
10
|
+
---
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
# 3.6.0 / 2020-07-13
|
15
|
+
|
16
|
+
|
17
|
+
## Features
|
18
|
+
|
19
|
+
* [#458](https://github.com/Dynamoid/dynamoid/pull/458) Added `binary` field type
|
20
|
+
* [#459](https://github.com/Dynamoid/dynamoid/pull/459) Added `log_formatter` config option and changed default logging format
|
21
|
+
|
22
|
+
## Improvements
|
23
|
+
|
24
|
+
* [#423](https://github.com/Dynamoid/dynamoid/pull/423) Added warning when generated for a field methods override existing ones
|
25
|
+
* [#429](https://github.com/Dynamoid/dynamoid/pull/429) Added `raise_error` option for `find` method
|
26
|
+
* [#440](https://github.com/Dynamoid/dynamoid/pull/440) Optimized performance of `first` method when there are only conditions on key attribute in a query (@mrkamel)
|
27
|
+
* [#445](https://github.com/Dynamoid/dynamoid/pull/445) Support `limit` parameter in `first` method (@mrkamel)
|
28
|
+
* [#450](https://github.com/Dynamoid/dynamoid/pull/450) Got rid of `null-logger` gem to make Dynamoid dependencies license suitable for commercial use (@yakjuly)
|
29
|
+
* [#454](https://github.com/Dynamoid/dynamoid/pull/454) Added block argument to `create`/`create!` methods
|
30
|
+
* [#456](https://github.com/Dynamoid/dynamoid/pull/456) Detect when `find` method requires a range key argument and raise `Dynamoid::Errors::MissingRangeKey` exception if it's missing
|
31
|
+
* YARD documentation:
|
32
|
+
* added missing documentation so now all the public methods are documented
|
33
|
+
* hid all the private methods and classes
|
34
|
+
|
35
|
+
## Fixes
|
36
|
+
|
37
|
+
* [#425](https://github.com/Dynamoid/dynamoid/pull/425) Fixed typos in the README.md file (@omarsotillo)
|
38
|
+
* [#432](https://github.com/Dynamoid/dynamoid/pull/432) Support tables that use "hash_key" as their partition key name (@remomueller)
|
39
|
+
* [#434](https://github.com/Dynamoid/dynamoid/pull/434) Support tables that have attribute with name "range_value"
|
40
|
+
* [#453](https://github.com/Dynamoid/dynamoid/pull/453) Fixed issue with using `type` attribute as a GSI hash key
|
41
|
+
|
42
|
+
---
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
# 3.5.0 / 2020-04-04
|
47
|
+
|
48
|
+
|
49
|
+
## Features
|
50
|
+
* Feature: [#405](https://github.com/Dynamoid/dynamoid/pull/405) Added `update!` class method (@UrsaDK)
|
51
|
+
* Feature: [#408](https://github.com/Dynamoid/dynamoid/pull/408) Added `ActiveSupport` load hook on `Dynamoid` load (@aaronmallen)
|
52
|
+
* Feature: [#422](https://github.com/Dynamoid/dynamoid/pull/422) Added `.pluck` method
|
53
|
+
|
54
|
+
## Fixes:
|
55
|
+
* Fix: [#410](https://github.com/Dynamoid/dynamoid/pull/410) Fixed creating GSI when table uses on-demand capacity provisioning (@icy-arctic-fox)
|
56
|
+
* Fix: [#414](https://github.com/Dynamoid/dynamoid/pull/414) Fixed lazy table creation
|
57
|
+
* Fix: [#415](https://github.com/Dynamoid/dynamoid/pull/415) Fixed RubyDoc comment (@walkersumida)
|
58
|
+
* Fix: [#420](https://github.com/Dynamoid/dynamoid/pull/420) Fixed `#persisted?` for deleted/destroyed models
|
59
|
+
|
60
|
+
## Improvements:
|
61
|
+
* Improvement: [#416](https://github.com/Dynamoid/dynamoid/pull/416) Improved speed of Adapter's `truncate` method. It now uses `#batch_delete_item` method (@TheSmartnik)
|
62
|
+
* Improvement: [#421](https://github.com/Dynamoid/dynamoid/pull/421) Added `touch: false` option of the #save method
|
63
|
+
* Improvement: [#423](https://github.com/Dynamoid/dynamoid/pull/423) Added warning when generated for a field methods override existing ones
|
64
|
+
|
65
|
+
---
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
# 3.4.1
|
70
|
+
|
71
|
+
## Fixes
|
72
|
+
* Fix: [#398](https://github.com/Dynamoid/dynamoid/pull/398) Fix broken configuration
|
73
|
+
|
74
|
+
---
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
# 3.4.0
|
79
|
+
|
80
|
+
## Features
|
81
|
+
* Feature: [#386](https://github.com/Dynamoid/dynamoid/pull/386) Disable timestamps fields on a table level with new
|
82
|
+
table option `timestamps`
|
83
|
+
* Feature: [#387](https://github.com/Dynamoid/dynamoid/pull/387) Add TTL support with table option `expires`
|
84
|
+
* Feature: [#393](https://github.com/Dynamoid/dynamoid/pull/393) Support pre-configured credentials with new config
|
85
|
+
option `credentials` (@emmajhyde)
|
86
|
+
* Feature: [#397](https://github.com/Dynamoid/dynamoid/pull/397) Configure on-demand table capacity mode with `capacity_mode` option
|
4
87
|
|
5
88
|
## Improvements
|
89
|
+
* Improvement: [#388](https://github.com/Dynamoid/dynamoid/pull/388) Minor memory optimization - don't allocate excessive
|
90
|
+
hash (@arjes)
|
91
|
+
|
92
|
+
## Fixes
|
93
|
+
|
94
|
+
* Fix: [#382](https://github.com/Dynamoid/dynamoid/pull/382) Fixed deprecation warning about `Module#parent_name` in Rails 6 (@tmandke)
|
95
|
+
* Fix: Typos in Readme.md (@romeuhcf)
|
96
|
+
|
97
|
+
---
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
# 3.3.0
|
102
|
+
|
103
|
+
## Features
|
104
|
+
|
105
|
+
* Feature: [#374](https://github.com/Dynamoid/dynamoid/pull/374) Add `#project` query method to load only specified fields
|
106
|
+
|
107
|
+
## Improvements
|
108
|
+
|
109
|
+
* Improvement: [#359](https://github.com/Dynamoid/dynamoid/pull/359) Add support of `NULL` and `NOT_NULL` operators
|
110
|
+
* Improvement: [#360](https://github.com/Dynamoid/dynamoid/pull/360) Add `store_attribute_with_nil_value` config option
|
111
|
+
* Improvement: [#368](https://github.com/Dynamoid/dynamoid/pull/368) Support Rails 6 (RC1)
|
6
112
|
|
7
113
|
## Fixes
|
114
|
+
* Fix: [#357](https://github.com/Dynamoid/dynamoid/pull/357) Fix synchronous table creation issue
|
115
|
+
* Fix: [#362](https://github.com/Dynamoid/dynamoid/pull/362) Fix issue with selecting Global Secondary Index (@atyndall)
|
116
|
+
* Fix: [#368](https://github.com/Dynamoid/dynamoid/pull/368) Repair `#previous_changes` method from Dirty API
|
117
|
+
* Fix: [#373](https://github.com/Dynamoid/dynamoid/pull/373) Fix threadsafety of loading `Dynamoid::Adapter` (@tsub)
|
8
118
|
|
9
119
|
---
|
10
120
|
|
data/README.md
CHANGED
@@ -9,26 +9,36 @@
|
|
9
9
|

|
10
10
|
|
11
11
|
Dynamoid is an ORM for Amazon's DynamoDB for Ruby applications. It
|
12
|
-
provides similar functionality to ActiveRecord and improves on
|
13
|
-
|
12
|
+
provides similar functionality to ActiveRecord and improves on Amazon's
|
13
|
+
existing
|
14
14
|
[HashModel](http://docs.amazonwebservices.com/AWSRubySDK/latest/AWS/Record/HashModel.html)
|
15
15
|
by providing better searching tools and native association support.
|
16
16
|
|
17
|
-
DynamoDB is not like other document-based databases you might know, and
|
17
|
+
DynamoDB is not like other document-based databases you might know, and
|
18
|
+
is very different indeed from relational databases. It sacrifices
|
19
|
+
anything beyond the simplest relational queries and transactional
|
20
|
+
support to provide a fast, cost-efficient, and highly durable storage
|
21
|
+
solution. If your database requires complicated relational queries and
|
22
|
+
transaction support, then this modest Gem cannot provide them for you,
|
23
|
+
and neither can DynamoDB. In those cases you would do better to look
|
24
|
+
elsewhere for your database needs.
|
18
25
|
|
19
|
-
But if you want a fast, scalable, simple, easy-to-use database (and a
|
26
|
+
But if you want a fast, scalable, simple, easy-to-use database (and a
|
27
|
+
Gem that supports it) then look no further!
|
20
28
|
|
21
29
|
## Installation
|
22
30
|
|
23
|
-
Installing Dynamoid is pretty simple. First include the Gem in your
|
31
|
+
Installing Dynamoid is pretty simple. First include the Gem in your
|
32
|
+
Gemfile:
|
24
33
|
|
25
34
|
```ruby
|
26
35
|
gem 'dynamoid'
|
27
36
|
```
|
28
|
-
##
|
37
|
+
## Prerequisites
|
29
38
|
|
30
|
-
Dynamoid depends on the aws-sdk, and this is tested on the current
|
31
|
-
|
39
|
+
Dynamoid depends on the aws-sdk, and this is tested on the current
|
40
|
+
version of aws-sdk (~> 3), rails (>= 4). Hence the configuration as
|
41
|
+
needed for aws to work will be dealt with by aws setup.
|
32
42
|
|
33
43
|
### AWS SDK Version Compatibility
|
34
44
|
|
@@ -51,45 +61,73 @@ For example, to configure AWS access:
|
|
51
61
|
Create `config/initializers/aws.rb` as follows:
|
52
62
|
|
53
63
|
```ruby
|
64
|
+
Aws.config.update({
|
65
|
+
region: 'us-west-2',
|
66
|
+
credentials: Aws::Credentials.new('REPLACE_WITH_ACCESS_KEY_ID', 'REPLACE_WITH_SECRET_ACCESS_KEY'),
|
67
|
+
})
|
68
|
+
```
|
54
69
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
})
|
70
|
+
Alternatively, if you don't want Aws connection settings to be
|
71
|
+
overwritten for you entire project, you can specify connection settings
|
72
|
+
for Dynamoid only, by setting those in the `Dynamoid.configure` clause:
|
59
73
|
|
74
|
+
```ruby
|
75
|
+
require 'dynamoid'
|
76
|
+
Dynamoid.configure do |config|
|
77
|
+
config.access_key = 'REPLACE_WITH_ACCESS_KEY_ID'
|
78
|
+
config.secret_key = 'REPLACE_WITH_SECRET_ACCESS_KEY'
|
79
|
+
config.region = 'us-west-2'
|
80
|
+
end
|
60
81
|
```
|
61
82
|
|
62
|
-
|
83
|
+
Additionally, if you would like to pass in pre-configured AWS credentials
|
84
|
+
(e.g. you have an IAM role credential, you configure your credentials
|
85
|
+
elsewhere in your project, etc.), you may do so:
|
63
86
|
|
64
87
|
```ruby
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
88
|
+
require 'dynamoid'
|
89
|
+
|
90
|
+
credentials = Aws::AssumeRoleCredentials.new(
|
91
|
+
region: region,
|
92
|
+
access_key_id: key,
|
93
|
+
secret_access_key: secret,
|
94
|
+
role_arn: role_arn,
|
95
|
+
role_session_name: 'our-session'
|
96
|
+
)
|
97
|
+
|
98
|
+
Dynamoid.configure do |config|
|
99
|
+
config.region = 'us-west-2',
|
100
|
+
config.credentials = credentials
|
101
|
+
end
|
71
102
|
```
|
72
103
|
|
73
104
|
For a full list of the DDB regions, you can go
|
74
105
|
[here](http://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region).
|
75
106
|
|
76
|
-
Then you need to initialize Dynamoid config to get it going. Put code
|
107
|
+
Then you need to initialize Dynamoid config to get it going. Put code
|
108
|
+
similar to this somewhere (a Rails initializer would be a great place
|
109
|
+
for this if you're using Rails):
|
77
110
|
|
78
111
|
```ruby
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
112
|
+
require 'dynamoid'
|
113
|
+
Dynamoid.configure do |config|
|
114
|
+
# To namespace tables created by Dynamoid from other tables you might have.
|
115
|
+
# Set to nil to avoid namespacing.
|
116
|
+
config.namespace = 'dynamoid_app_development'
|
117
|
+
|
118
|
+
# [Optional]. If provided, it communicates with the DB listening at the endpoint.
|
119
|
+
# This is useful for testing with [DynamoDB Local] (http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.DynamoDBLocal.html).
|
120
|
+
config.endpoint = 'http://localhost:3000'
|
121
|
+
end
|
84
122
|
```
|
85
123
|
|
86
124
|
### Ruby & Rails Compatibility
|
87
125
|
|
88
126
|
Dynamoid supports Ruby >= 2.3 and Rails >= 4.2.
|
89
127
|
|
90
|
-
Its compatibility is tested against following Ruby versions: 2.3.
|
91
|
-
2.
|
92
|
-
|
128
|
+
Its compatibility is tested against following Ruby versions: 2.3, 2.4,
|
129
|
+
2.5 and 2.6, JRuby 9.2.8.0 and against Rails versions: 4.2, 5.0, 5.1,
|
130
|
+
5.2 and 6.0.
|
93
131
|
|
94
132
|
## Setup
|
95
133
|
|
@@ -99,12 +137,15 @@ You *must* include `Dynamoid::Document` in every Dynamoid model.
|
|
99
137
|
class User
|
100
138
|
include Dynamoid::Document
|
101
139
|
|
140
|
+
# fields declaration
|
102
141
|
end
|
103
142
|
```
|
104
143
|
|
105
144
|
### Table
|
106
145
|
|
107
|
-
Dynamoid has some sensible defaults for you when you create a new table,
|
146
|
+
Dynamoid has some sensible defaults for you when you create a new table,
|
147
|
+
including the table name and the primary key column. But you can change
|
148
|
+
those if you like on table creation.
|
108
149
|
|
109
150
|
```ruby
|
110
151
|
class User
|
@@ -114,29 +155,85 @@ class User
|
|
114
155
|
end
|
115
156
|
```
|
116
157
|
|
117
|
-
These fields will not change an existing table: so specifying a new
|
158
|
+
These fields will not change an existing table: so specifying a new
|
159
|
+
read_capacity and write_capacity here only works correctly for entirely
|
160
|
+
new tables. Similarly, while Dynamoid will look for a table named
|
161
|
+
`awesome_users` in your namespace, it won't change any existing tables
|
162
|
+
to use that name; and if it does find a table with the correct name, it
|
163
|
+
won't change its hash key, which it expects will be `user_id`. If this
|
164
|
+
table doesn't exist yet, however, Dynamoid will create it with these
|
165
|
+
options.
|
118
166
|
|
119
|
-
|
167
|
+
There is a basic support of DynamoDB's [Time To Live (TTL)
|
168
|
+
mechanism](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html).
|
169
|
+
If you declare a field as TTL field - it will be initialised if doesn't
|
170
|
+
have value yet. Default value is current time + specified seconds.
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
class User
|
174
|
+
include Dynamoid::Document
|
175
|
+
|
176
|
+
table expires: { field: :ttl, after: 60 }
|
177
|
+
|
178
|
+
field :ttl, :integer
|
179
|
+
end
|
180
|
+
```
|
120
181
|
|
121
|
-
|
182
|
+
Field used to store expiration time (e.g. `ttl`) should be declared
|
183
|
+
explicitly and should have numeric type (`integer`, `number`) only.
|
184
|
+
`datetime` type is also possible but only if it's stored as number
|
185
|
+
(there is a way to store time as a string also).
|
122
186
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
187
|
+
It's also possible to override a global option `Dynamoid::Config.timestamps`
|
188
|
+
on a table level:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
table timestamps: false
|
192
|
+
```
|
193
|
+
|
194
|
+
This option controls generation of timestamp fields
|
195
|
+
`created_at`/`updated_at`.
|
196
|
+
|
197
|
+
It's also possible to override table capacity mode configured globally
|
198
|
+
with table level option `capacity_mode`. Valid values are
|
199
|
+
`:provisioned`, `:on_demand` and `nil`:
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
table capacity_mode: :on_demand
|
203
|
+
```
|
204
|
+
|
205
|
+
If table capacity mode is on-demand, another related table-level options
|
206
|
+
`read_capacity` and `write_capacity` will be ignored.
|
207
|
+
|
208
|
+
### Fields
|
209
|
+
|
210
|
+
You'll have to define all the fields on the model and the data type of
|
211
|
+
each field. Every field on the object must be included here; if you miss
|
212
|
+
any they'll be completely bypassed during DynamoDB's initialization and
|
213
|
+
will not appear on the model objects.
|
214
|
+
|
215
|
+
By default, fields are assumed to be of type `string`. Other built-in
|
216
|
+
types are `integer`, `number`, `set`, `array`, `map`, `datetime`,
|
217
|
+
`date`, `boolean`, `binary`, `raw` and `serialized`. `array` and
|
218
|
+
`map` match List and Map DynamoDB types respectively. `raw` type means
|
219
|
+
you can store Ruby Array, Hash, String and numbers. If built-in types do
|
220
|
+
not suit you, you can use a custom field type represented by an
|
221
|
+
arbitrary class, provided that the class supports a compatible
|
222
|
+
serialization interface. The primary use case for using a custom field
|
223
|
+
type is to represent your business logic with high-level types, while
|
224
|
+
ensuring portability or backward-compatibility of the serialized
|
225
|
+
representation.
|
129
226
|
|
130
227
|
#### Note on boolean type
|
131
228
|
|
132
229
|
The boolean fields are stored as DynamoDB boolean values by default.
|
133
230
|
Dynamoid can store boolean values as strings as well - `'t'` and `'f'`.
|
134
|
-
So if you want to change default format of boolean field you can
|
135
|
-
achieve this with `store_as_native_boolean` field option:
|
231
|
+
So if you want to change the default format of boolean field you can
|
232
|
+
easily achieve this with `store_as_native_boolean` field option:
|
136
233
|
|
137
234
|
```ruby
|
138
235
|
class Document
|
139
|
-
include
|
236
|
+
include Dynamoid::Document
|
140
237
|
|
141
238
|
field :active, :boolean, store_as_native_boolean: false
|
142
239
|
end
|
@@ -144,11 +241,13 @@ end
|
|
144
241
|
|
145
242
|
#### Note on date type
|
146
243
|
|
147
|
-
By default date fields are persisted as days count since 1 January 1970
|
244
|
+
By default date fields are persisted as days count since 1 January 1970
|
245
|
+
like UNIX time. If you prefer dates to be stored as ISO-8601 formatted
|
246
|
+
strings instead then set `store_as_string` to `true`
|
148
247
|
|
149
248
|
```ruby
|
150
249
|
class Document
|
151
|
-
include
|
250
|
+
include Dynamoid::Document
|
152
251
|
|
153
252
|
field :sent_on, :date, store_as_string: true
|
154
253
|
end
|
@@ -156,51 +255,58 @@ end
|
|
156
255
|
|
157
256
|
#### Note on datetime type
|
158
257
|
|
159
|
-
By default datetime fields are persisted as UNIX timestamps with
|
258
|
+
By default datetime fields are persisted as UNIX timestamps with
|
259
|
+
millisecond precision in DynamoDB. If you prefer datetimes to be stored
|
260
|
+
as ISO-8601 formatted strings instead then set `store_as_string` to
|
261
|
+
`true`
|
160
262
|
|
161
263
|
```ruby
|
162
264
|
class Document
|
163
|
-
include
|
265
|
+
include Dynamoid::Document
|
164
266
|
|
165
267
|
field :sent_at, :datetime, store_as_string: true
|
166
268
|
end
|
167
269
|
```
|
168
270
|
|
169
|
-
**WARNING:** Fields in numeric format are stored with nanoseconds as a
|
170
|
-
That's why `datetime` field
|
271
|
+
**WARNING:** Fields in numeric format are stored with nanoseconds as a
|
272
|
+
fraction part and precision could be lost. That's why `datetime` field
|
273
|
+
in numeric format shouldn't be used as a range key.
|
171
274
|
|
172
|
-
You have two options if you need to use a `datetime` field as a range
|
275
|
+
You have two options if you need to use a `datetime` field as a range
|
276
|
+
key:
|
173
277
|
* string format
|
174
|
-
* store `datetime` values without milliseconds e.g. cut
|
175
|
-
manually with `change` method - `Time.now.change(usec: 0)`
|
278
|
+
* store `datetime` values without milliseconds (e.g. cut
|
279
|
+
them manually with `change` method - `Time.now.change(usec: 0)`
|
176
280
|
|
177
281
|
#### Note on set type
|
178
282
|
|
179
283
|
`Dynamoid`'s type `set` is stored as DynamoDB's Set attribute type.
|
180
|
-
DynamoDB supports only Set of strings, numbers and binary.
|
181
|
-
|
284
|
+
DynamoDB supports only Set of strings, numbers and binary. Moreover Set
|
285
|
+
*must* contain elements of the same type only.
|
182
286
|
|
183
|
-
In order to use some other `Dynamoid`'s types you can specify `of`
|
184
|
-
to declare the type of set elements.
|
287
|
+
In order to use some other `Dynamoid`'s types you can specify `of`
|
288
|
+
option to declare the type of set elements.
|
185
289
|
|
186
290
|
As a result of that DynamoDB limitation, in Dynamoid only the following
|
187
291
|
scalar types are supported (note: does not support `boolean`):
|
188
|
-
`integer`, `number`, `date`, `datetime`, `serializable` and custom
|
292
|
+
`integer`, `number`, `date`, `datetime`, `serializable` and custom
|
293
|
+
types.
|
189
294
|
|
190
295
|
```ruby
|
191
296
|
class Document
|
192
|
-
include
|
297
|
+
include Dynamoid::Document
|
193
298
|
|
194
299
|
field :tags, :set, of: :integer
|
195
300
|
end
|
196
301
|
```
|
197
302
|
|
198
|
-
It's possible to specify field options like `store_as_string` for
|
199
|
-
or `serializer` for `serializable` field for `set`
|
303
|
+
It's possible to specify field options like `store_as_string` for
|
304
|
+
`datetime` field or `serializer` for `serializable` field for `set`
|
305
|
+
elements type:
|
200
306
|
|
201
307
|
```ruby
|
202
308
|
class Document
|
203
|
-
include
|
309
|
+
include Dynamoid::Document
|
204
310
|
|
205
311
|
field :values, :set, of: { serialized: { serializer: JSON } }
|
206
312
|
field :dates, :set, of: { date: { store_as_string: true } }
|
@@ -209,12 +315,14 @@ end
|
|
209
315
|
```
|
210
316
|
|
211
317
|
DynamoDB doesn't allow empty strings in fields configured as `set`.
|
212
|
-
Abiding by this restriction, when `Dynamoid` saves a document it removes
|
318
|
+
Abiding by this restriction, when `Dynamoid` saves a document it removes
|
319
|
+
all empty strings in set fields.
|
213
320
|
|
214
321
|
#### Note on array type
|
215
322
|
|
216
323
|
`Dynamoid`'s type `array` is stored as DynamoDB's List attribute type.
|
217
|
-
It can contain elements of different types (in contrast to Set attribute
|
324
|
+
It can contain elements of different types (in contrast to Set attribute
|
325
|
+
type).
|
218
326
|
|
219
327
|
If you need to store in array field elements of `datetime`, `date`,
|
220
328
|
`serializable` or some custom type, which DynamoDB doesn't support
|
@@ -222,7 +330,7 @@ natively, you should specify element type with `of` option:
|
|
222
330
|
|
223
331
|
```ruby
|
224
332
|
class Document
|
225
|
-
include
|
333
|
+
include Dynamoid::Document
|
226
334
|
|
227
335
|
field :dates, :array, of: :date
|
228
336
|
end
|
@@ -230,7 +338,8 @@ end
|
|
230
338
|
|
231
339
|
#### Magic Columns
|
232
340
|
|
233
|
-
You get magic columns of `id` (`string`), `created_at` (`datetime`), and
|
341
|
+
You get magic columns of `id` (`string`), `created_at` (`datetime`), and
|
342
|
+
`updated_at` (`datetime`) for free.
|
234
343
|
|
235
344
|
```ruby
|
236
345
|
class User
|
@@ -248,11 +357,12 @@ end
|
|
248
357
|
|
249
358
|
#### Default Values
|
250
359
|
|
251
|
-
You can optionally set a default value on a field using either a plain
|
360
|
+
You can optionally set a default value on a field using either a plain
|
361
|
+
value or a lambda:
|
252
362
|
|
253
363
|
```ruby
|
254
|
-
|
255
|
-
|
364
|
+
field :actions_taken, :integer, default: 0
|
365
|
+
field :joined_at, :datetime, default: -> { Time.now }
|
256
366
|
```
|
257
367
|
|
258
368
|
#### Custom Types
|
@@ -260,64 +370,68 @@ You can optionally set a default value on a field using either a plain value or
|
|
260
370
|
To use a custom type for a field, suppose you have a `Money` type.
|
261
371
|
|
262
372
|
```ruby
|
263
|
-
|
264
|
-
|
373
|
+
class Money
|
374
|
+
# ... your business logic ...
|
265
375
|
|
266
|
-
|
267
|
-
|
268
|
-
|
376
|
+
def dynamoid_dump
|
377
|
+
'serialized representation as a string'
|
378
|
+
end
|
269
379
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
end
|
380
|
+
def self.dynamoid_load(serialized_str)
|
381
|
+
# parse serialized representation and return a Money instance
|
382
|
+
Money.new(1.23)
|
274
383
|
end
|
384
|
+
end
|
275
385
|
|
276
|
-
|
277
|
-
|
386
|
+
class User
|
387
|
+
include Dynamoid::Document
|
278
388
|
|
279
|
-
|
280
|
-
|
389
|
+
field :balance, Money
|
390
|
+
end
|
281
391
|
```
|
282
392
|
|
283
|
-
If you want to use a third-party class (which does not support
|
284
|
-
as your field type, you can use
|
285
|
-
|
286
|
-
|
393
|
+
If you want to use a third-party class (which does not support
|
394
|
+
`#dynamoid_dump` and `.dynamoid_load`) as your field type, you can use
|
395
|
+
an adapter class providing `.dynamoid_dump` and `.dynamoid_load` class
|
396
|
+
methods for your third-party class. `.dynamoid_load` can remain the same
|
397
|
+
from the previous example; here we just add a level of indirection for
|
398
|
+
serializing. Example:
|
287
399
|
|
288
400
|
```ruby
|
289
|
-
|
290
|
-
|
401
|
+
# Third-party Money class
|
402
|
+
class Money; end
|
291
403
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
404
|
+
class MoneyAdapter
|
405
|
+
def self.dynamoid_load(money_serialized_str)
|
406
|
+
Money.new(1.23)
|
407
|
+
end
|
296
408
|
|
297
|
-
|
298
|
-
|
299
|
-
end
|
409
|
+
def self.dynamoid_dump(money_obj)
|
410
|
+
money_obj.value.to_s
|
300
411
|
end
|
412
|
+
end
|
301
413
|
|
302
|
-
|
303
|
-
|
414
|
+
class User
|
415
|
+
include Dynamoid::Document
|
304
416
|
|
305
|
-
|
306
|
-
|
417
|
+
field :balance, MoneyAdapter
|
418
|
+
end
|
307
419
|
```
|
308
420
|
|
309
|
-
Lastly, you can control the data type of your custom-class-backed field
|
310
|
-
This is especially important if you want to use
|
311
|
-
|
312
|
-
|
313
|
-
|
421
|
+
Lastly, you can control the data type of your custom-class-backed field
|
422
|
+
at the DynamoDB level. This is especially important if you want to use
|
423
|
+
your custom field as a numeric range or for number-oriented queries. By
|
424
|
+
default custom fields are persisted as a string attribute, but your
|
425
|
+
custom class can override this with a `.dynamoid_field_type` class
|
426
|
+
method, which would return either `:string` or `:number`.
|
314
427
|
|
315
|
-
DynamoDB may support some other attribute types that are not yet
|
428
|
+
DynamoDB may support some other attribute types that are not yet
|
429
|
+
supported by Dynamoid.
|
316
430
|
|
317
431
|
### Sort key
|
318
432
|
|
319
|
-
Along with partition key table may have a sort key. In order to declare
|
320
|
-
`range` class method should be used:
|
433
|
+
Along with partition key table may have a sort key. In order to declare
|
434
|
+
it in a model `range` class method should be used:
|
321
435
|
|
322
436
|
```ruby
|
323
437
|
class Post
|
@@ -331,9 +445,15 @@ Second argument, type, is optional. Default type is `string`.
|
|
331
445
|
|
332
446
|
### Associations
|
333
447
|
|
334
|
-
Just like in ActiveRecord (or your other favorite ORM), Dynamoid uses
|
448
|
+
Just like in ActiveRecord (or your other favorite ORM), Dynamoid uses
|
449
|
+
associations to create links between models.
|
335
450
|
|
336
|
-
The only supported associations (so far) are `has_many`, `has_one`,
|
451
|
+
The only supported associations (so far) are `has_many`, `has_one`,
|
452
|
+
`has_and_belongs_to_many`, and `belongs_to`. Associations are very
|
453
|
+
simple to create: just specify the type, the name, and then any options
|
454
|
+
you'd like to pass to the association. If there's an inverse association
|
455
|
+
either inferred or specified directly, Dynamoid will update both objects
|
456
|
+
to point at each other.
|
337
457
|
|
338
458
|
```ruby
|
339
459
|
class User
|
@@ -348,7 +468,6 @@ class User
|
|
348
468
|
belongs_to :group, foreign_key: :group_id
|
349
469
|
has_one :role
|
350
470
|
has_and_belongs_to_many :friends, inverse_of: :friending_users
|
351
|
-
|
352
471
|
end
|
353
472
|
|
354
473
|
class Address
|
@@ -357,11 +476,18 @@ class Address
|
|
357
476
|
# ...
|
358
477
|
|
359
478
|
belongs_to :user # Automatically links up with the user model
|
360
|
-
|
361
479
|
end
|
362
480
|
```
|
363
481
|
|
364
|
-
Contrary to what you'd expect, association information is always
|
482
|
+
Contrary to what you'd expect, association information is always
|
483
|
+
contained on the object specifying the association, even if it seems
|
484
|
+
like the association has a foreign key. This is a side effect of
|
485
|
+
DynamoDB's structure: it's very difficult to find foreign keys without
|
486
|
+
an index. Usually you won't find this to be a problem, but it does mean
|
487
|
+
that association methods that build new models will not work correctly -
|
488
|
+
for example, `user.addresses.new` returns an address that is not
|
489
|
+
associated to the user. We'll be correcting this ~soon~ maybe someday,
|
490
|
+
if we get a pull request.
|
365
491
|
|
366
492
|
### Validations
|
367
493
|
|
@@ -378,9 +504,12 @@ class User
|
|
378
504
|
end
|
379
505
|
```
|
380
506
|
|
381
|
-
To see more usage and examples of ActiveModel validations, check out the
|
507
|
+
To see more usage and examples of ActiveModel validations, check out the
|
508
|
+
[ActiveModel validation
|
509
|
+
documentation](http://api.rubyonrails.org/classes/ActiveModel/Validations.html).
|
382
510
|
|
383
|
-
If you want to bypass model validation, pass `validate: false` to `save`
|
511
|
+
If you want to bypass model validation, pass `validate: false` to `save`
|
512
|
+
call:
|
384
513
|
|
385
514
|
```ruby
|
386
515
|
model.save(validate: false)
|
@@ -388,7 +517,9 @@ model.save(validate: false)
|
|
388
517
|
|
389
518
|
### Callbacks
|
390
519
|
|
391
|
-
Dynamoid also employs ActiveModel callbacks. Right now, callbacks are
|
520
|
+
Dynamoid also employs ActiveModel callbacks. Right now, callbacks are
|
521
|
+
defined on `save`, `update`, `destroy`, which allows you to do `before_`
|
522
|
+
or `after_` any of those.
|
392
523
|
|
393
524
|
```ruby
|
394
525
|
class User
|
@@ -404,7 +535,8 @@ end
|
|
404
535
|
|
405
536
|
### STI
|
406
537
|
|
407
|
-
Dynamoid supports STI (Single Table Inheritance) like Active Record
|
538
|
+
Dynamoid supports STI (Single Table Inheritance) like Active Record
|
539
|
+
does. You need just specify `type` field in a base class. Example:
|
408
540
|
|
409
541
|
```ruby
|
410
542
|
class Animal
|
@@ -421,12 +553,13 @@ end
|
|
421
553
|
cat = Cat.create(name: 'Morgan')
|
422
554
|
animal = Animal.find(cat.id)
|
423
555
|
animal.class
|
424
|
-
#=>
|
556
|
+
#=> Cat
|
425
557
|
```
|
426
558
|
|
427
|
-
If you already have DynamoDB tables and `type` field already exists and
|
428
|
-
|
429
|
-
instead of `type` one
|
559
|
+
If you already have DynamoDB tables and `type` field already exists and
|
560
|
+
has its own semantic it leads to conflict. It's possible to tell
|
561
|
+
Dynamoid to use another field (even not existing) instead of `type` one
|
562
|
+
with `inheritance_field` table option:
|
430
563
|
|
431
564
|
```ruby
|
432
565
|
class Car
|
@@ -443,8 +576,9 @@ c.my_new_type
|
|
443
576
|
|
444
577
|
### Type casting
|
445
578
|
|
446
|
-
Dynamid supports type casting and
|
447
|
-
Values for all fields (except custom type) are coerced to declared
|
579
|
+
Dynamid supports type casting and tries to do it in the most convenient
|
580
|
+
way. Values for all fields (except custom type) are coerced to declared
|
581
|
+
field types.
|
448
582
|
|
449
583
|
Some obvious rules are used, e.g.:
|
450
584
|
|
@@ -468,18 +602,29 @@ document.integer_field = true
|
|
468
602
|
# => 1
|
469
603
|
```
|
470
604
|
|
471
|
-
If time zone isn't specified for `datetime` value - application time
|
605
|
+
If time zone isn't specified for `datetime` value - application time
|
606
|
+
zone is used.
|
472
607
|
|
473
608
|
To access field value before type casting following method could be
|
474
|
-
used: `attributes_before_type_cast` and
|
609
|
+
used: `attributes_before_type_cast` and
|
610
|
+
`read_attribute_before_type_cast`.
|
475
611
|
|
476
|
-
There is `<name>_before_type_cast` method for every field in a model as
|
612
|
+
There is `<name>_before_type_cast` method for every field in a model as
|
613
|
+
well.
|
614
|
+
|
615
|
+
### Dirty API
|
616
|
+
|
617
|
+
Dynamoid supports Dirty API which equivalents to [Rails 5.2
|
618
|
+
`ActiveModel::Dirty`](https://api.rubyonrails.org/v5.2/classes/ActiveModel/Dirty.html).
|
619
|
+
There is only one limitation - change in place of field isn't detected
|
620
|
+
automatically.
|
477
621
|
|
478
622
|
## Usage
|
479
623
|
|
480
624
|
### Object Creation
|
481
625
|
|
482
|
-
Dynamoid's syntax is generally very similar to ActiveRecord's. Making
|
626
|
+
Dynamoid's syntax is generally very similar to ActiveRecord's. Making
|
627
|
+
new objects is simple:
|
483
628
|
|
484
629
|
```ruby
|
485
630
|
u = User.new(name: 'Josh')
|
@@ -487,13 +632,15 @@ u.email = 'josh@joshsymonds.com'
|
|
487
632
|
u.save
|
488
633
|
```
|
489
634
|
|
490
|
-
Save forces persistence to the datastore: a unique ID is also assigned,
|
635
|
+
Save forces persistence to the datastore: a unique ID is also assigned,
|
636
|
+
but it is a string and not an auto-incrementing number.
|
491
637
|
|
492
638
|
```ruby
|
493
639
|
u.id # => '3a9f7216-4726-4aea-9fbc-8554ae9292cb'
|
494
640
|
```
|
495
641
|
|
496
|
-
To use associations, you use association methods very similar to
|
642
|
+
To use associations, you use association methods very similar to
|
643
|
+
ActiveRecord's:
|
497
644
|
|
498
645
|
```ruby
|
499
646
|
address = u.addresses.create
|
@@ -520,7 +667,8 @@ Querying can be done in one of three ways:
|
|
520
667
|
|
521
668
|
```ruby
|
522
669
|
Address.find(address.id) # Find directly by ID.
|
523
|
-
Address.where(city: 'Chicago').all # Find by any number of matching criteria...
|
670
|
+
Address.where(city: 'Chicago').all # Find by any number of matching criteria...
|
671
|
+
# Though presently only "where" is supported.
|
524
672
|
Address.find_by_city('Chicago') # The same as above, but using ActiveRecord's older syntax.
|
525
673
|
```
|
526
674
|
|
@@ -530,11 +678,16 @@ And you can also query on associations:
|
|
530
678
|
u.addresses.where(city: 'Chicago').all
|
531
679
|
```
|
532
680
|
|
533
|
-
But keep in mind Dynamoid
|
681
|
+
But keep in mind Dynamoid - and document-based storage systems in
|
682
|
+
general - are not drop-in replacements for existing relational
|
683
|
+
databases. The above query does not efficiently perform a conditional
|
684
|
+
join, but instead finds all the user's addresses and naively filters
|
685
|
+
them in Ruby. For large associations this is a performance hit compared
|
686
|
+
to relational database engines.
|
534
687
|
|
535
688
|
**WARNING:** There is a limitation of conditions passed to `where`
|
536
689
|
method. Only one condition for some particular field could be specified.
|
537
|
-
The last one only will be
|
690
|
+
The last one only will be applied and others will be ignored. E.g. in
|
538
691
|
examples:
|
539
692
|
|
540
693
|
```ruby
|
@@ -544,64 +697,102 @@ User.where(name: 'Mike').where('name.begins_with': 'Ed')
|
|
544
697
|
|
545
698
|
the first one will be ignored and the last one will be used.
|
546
699
|
|
700
|
+
**Warning:** There is a caveat with filtering documents by `nil` value
|
701
|
+
attribute. By default Dynamoid ignores attributes with `nil` value and
|
702
|
+
doesn't store them in a DynamoDB document. This behavior could be
|
703
|
+
changed with `store_attribute_with_nil_value` config option.
|
704
|
+
|
705
|
+
If Dynamoid ignores `nil` value attributes `null`/`not_null` operators
|
706
|
+
should be used in query:
|
707
|
+
|
708
|
+
```ruby
|
709
|
+
Address.where('postcode.null': true)
|
710
|
+
Address.where('postcode.not_null': true)
|
711
|
+
```
|
712
|
+
|
713
|
+
If Dynamoid keeps `nil` value attributes `eq`/`ne` operators should be
|
714
|
+
used instead:
|
715
|
+
|
716
|
+
```ruby
|
717
|
+
Address.where('postcode': nil)
|
718
|
+
Address.where('postcode.ne': nil)
|
719
|
+
```
|
720
|
+
|
547
721
|
#### Limits
|
548
722
|
|
549
723
|
There are three types of limits that you can query with:
|
550
724
|
|
551
|
-
1. `record_limit` - The number of evaluated records that are returned by
|
552
|
-
|
553
|
-
|
725
|
+
1. `record_limit` - The number of evaluated records that are returned by
|
726
|
+
the query.
|
727
|
+
2. `scan_limit` - The number of scanned records that DynamoDB will look
|
728
|
+
at before returning.
|
729
|
+
3. `batch_size` - The number of records requested to DynamoDB per
|
730
|
+
underlying request, good for large queries!
|
554
731
|
|
555
|
-
Using these in various combinations results in the underlying requests
|
556
|
-
|
732
|
+
Using these in various combinations results in the underlying requests
|
733
|
+
to be made in the smallest size possible and the query returns once
|
734
|
+
`record_limit` or `scan_limit` is satisfied. It will attempt to batch
|
735
|
+
whenever possible.
|
557
736
|
|
558
|
-
You can thus limit the number of evaluated records, or select a record
|
737
|
+
You can thus limit the number of evaluated records, or select a record
|
738
|
+
from which to start in order to support pagination.
|
559
739
|
|
560
740
|
```ruby
|
561
741
|
Address.record_limit(5).start(address) # Only 5 addresses starting at `address`
|
562
742
|
```
|
563
|
-
Where `address` is an instance of the model or a hash
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
743
|
+
Where `address` is an instance of the model or a hash
|
744
|
+
`{the_model_hash_key: 'value', the_model_range_key: 'value'}`. Keep in
|
745
|
+
mind that if you are passing a hash to `.start()` you need to explicitly
|
746
|
+
define all required keys in it including range keys, depending on table
|
747
|
+
or secondary indexes signatures, otherwise you'll get an
|
748
|
+
`Aws::DynamoDB::Errors::ValidationException` either for `Exclusive Start
|
749
|
+
Key must have same size as table's key schema` or `The provided starting
|
750
|
+
key is invalid`
|
751
|
+
|
752
|
+
If you are potentially running over a large data set and this is
|
753
|
+
especially true when using certain filters, you may want to consider
|
754
|
+
limiting the number of scanned records (the number of records DynamoDB
|
755
|
+
infrastructure looks through when evaluating data to return):
|
569
756
|
|
570
757
|
```ruby
|
571
758
|
Address.scan_limit(5).start(address) # Only scan at most 5 records and return what's found starting from `address`
|
572
759
|
```
|
573
760
|
|
574
|
-
For large queries that return many rows, Dynamoid can use AWS' support
|
761
|
+
For large queries that return many rows, Dynamoid can use AWS' support
|
762
|
+
for requesting documents in batches:
|
575
763
|
|
576
764
|
```ruby
|
577
765
|
# Do some maintenance on the entire table without flooding DynamoDB
|
578
|
-
Address.
|
766
|
+
Address.batch(100).each { |address| address.do_some_work; sleep(0.01) }
|
579
767
|
Address.record_limit(10_000).batch(100).each { … } # Batch specified as part of a chain
|
580
768
|
```
|
581
769
|
|
582
|
-
The implication of batches is that the underlying requests are done in
|
583
|
-
|
770
|
+
The implication of batches is that the underlying requests are done in
|
771
|
+
the batch sizes to make the request and responses more manageable. Note
|
772
|
+
that this batching is for `Query` and `Scans` and not `BatchGetItem`
|
773
|
+
commands.
|
584
774
|
|
585
775
|
#### DynamoDB pagination
|
586
776
|
|
587
|
-
At times it can be useful to rely on DynamoDB [low-level
|
588
|
-
|
589
|
-
|
777
|
+
At times it can be useful to rely on DynamoDB [low-level
|
778
|
+
pagination](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.Pagination)
|
779
|
+
instead of fixed pages sizes. Each page results in a single Query or
|
780
|
+
Scan call to DynamoDB, but returns an unknown number of records.
|
590
781
|
|
591
|
-
Access to the native DynamoDB pages can be obtained via the
|
592
|
-
method, which yields arrays of records.
|
782
|
+
Access to the native DynamoDB pages can be obtained via the
|
783
|
+
`find_by_pages` method, which yields arrays of records.
|
593
784
|
|
594
785
|
```ruby
|
595
786
|
Address.find_by_pages do |addresses, metadata|
|
596
787
|
end
|
597
788
|
```
|
598
789
|
|
599
|
-
Each yielded pages returns page metadata as the second argument, which
|
600
|
-
including a key `:last_evaluated_key`. The value of this key
|
601
|
-
the `start` method to fetch the next page of records.
|
790
|
+
Each yielded pages returns page metadata as the second argument, which
|
791
|
+
is a hash including a key `:last_evaluated_key`. The value of this key
|
792
|
+
can be used for the `start` method to fetch the next page of records.
|
602
793
|
|
603
|
-
This way it can be used for instance to implement efficiently
|
604
|
-
|
794
|
+
This way it can be used for instance to implement efficiently pagination
|
795
|
+
in web-applications:
|
605
796
|
|
606
797
|
```ruby
|
607
798
|
class UserController < ApplicationController
|
@@ -620,8 +811,9 @@ end
|
|
620
811
|
|
621
812
|
#### Sort Conditions and Filters
|
622
813
|
|
623
|
-
You are able to optimize query with condition for sort key. Following
|
624
|
-
`
|
814
|
+
You are able to optimize query with condition for sort key. Following
|
815
|
+
operators are available: `gt`, `lt`, `gte`, `lte`, `begins_with`,
|
816
|
+
`between` as well as equality:
|
625
817
|
|
626
818
|
```ruby
|
627
819
|
Address.where(latitude: 10212)
|
@@ -633,18 +825,57 @@ Address.where('city.begins_with': 'Lon')
|
|
633
825
|
Address.where('latitude.between': [10212, 20000])
|
634
826
|
```
|
635
827
|
|
636
|
-
You are able to filter results on the DynamoDB side and specify
|
637
|
-
|
828
|
+
You are able to filter results on the DynamoDB side and specify
|
829
|
+
conditions for non-key fields. Following additional operators are
|
830
|
+
available: `in`, `contains`, `not_contains`, `null`, `not_null`:
|
638
831
|
|
639
832
|
```ruby
|
640
833
|
Address.where('city.in': ['London', 'Edenburg', 'Birmingham'])
|
641
834
|
Address.where('city.contains': ['on'])
|
642
835
|
Address.where('city.not_contains': ['ing'])
|
836
|
+
Address.where('postcode.null': false)
|
837
|
+
Address.where('postcode.not_null': true)
|
838
|
+
```
|
839
|
+
|
840
|
+
**WARNING:** Please take into account that `NULL` and `NOT_NULL`
|
841
|
+
operators check attribute presence in a document, not value. So if
|
842
|
+
attribute `postcode`'s value is `NULL`, `NULL` operator will return
|
843
|
+
false because attribute exists even if has `NULL` value.
|
844
|
+
|
845
|
+
#### Selecting some specific fields only
|
846
|
+
|
847
|
+
It could be done with `project` method:
|
848
|
+
|
849
|
+
```ruby
|
850
|
+
class User
|
851
|
+
include Dynamoid::Document
|
852
|
+
field :name
|
853
|
+
end
|
854
|
+
|
855
|
+
User.create(name: 'Alex')
|
856
|
+
user = User.project(:name).first
|
857
|
+
|
858
|
+
user.id # => nil
|
859
|
+
user.name # => 'Alex'
|
860
|
+
user.created_at # => nil
|
861
|
+
```
|
862
|
+
|
863
|
+
Returned models with have filled specified fields only.
|
864
|
+
|
865
|
+
Several fields could be specified:
|
866
|
+
|
867
|
+
```ruby
|
868
|
+
user = User.project(:name, :created_at)
|
643
869
|
```
|
644
870
|
|
645
871
|
### Consistent Reads
|
646
872
|
|
647
|
-
Querying supports consistent reading. By default, DynamoDB reads are
|
873
|
+
Querying supports consistent reading. By default, DynamoDB reads are
|
874
|
+
eventually consistent: if you do a write and then a read immediately
|
875
|
+
afterwards, the results of the previous write may not be reflected. If
|
876
|
+
you need to do a consistent read (that is, you need to read the results
|
877
|
+
of a write immediately) you can do so, but keep in mind that consistent
|
878
|
+
reads are twice as expensive as regular reads for DynamoDB.
|
648
879
|
|
649
880
|
```ruby
|
650
881
|
Address.find(address.id, consistent_read: true) # Find an address, ensure the read is consistent.
|
@@ -653,21 +884,25 @@ Address.where(city: 'Chicago').consistent.all # Find all addresses where the
|
|
653
884
|
|
654
885
|
### Range Finding
|
655
886
|
|
656
|
-
If you have a range index, Dynamoid provides a number of additional
|
887
|
+
If you have a range index, Dynamoid provides a number of additional
|
888
|
+
other convenience methods to make your life a little easier:
|
657
889
|
|
658
890
|
```ruby
|
659
891
|
User.where("created_at.gt": DateTime.now - 1.day).all
|
660
892
|
User.where("created_at.lt": DateTime.now - 1.day).all
|
661
893
|
```
|
662
894
|
|
663
|
-
It also supports `gte` and `lte`. Turning those into symbols and
|
895
|
+
It also supports `gte` and `lte`. Turning those into symbols and
|
896
|
+
allowing a Rails SQL-style string syntax is in the works. You can only
|
897
|
+
have one range argument per query, because of DynamoDB inherent
|
898
|
+
limitations, so use it sensibly!
|
664
899
|
|
665
900
|
|
666
901
|
### Updating
|
667
902
|
|
668
903
|
In order to update document you can use high level methods
|
669
|
-
`#update_attributes`, `#update_attribute` and `.update`.
|
670
|
-
|
904
|
+
`#update_attributes`, `#update_attribute` and `.update`. They run
|
905
|
+
validation and callbacks.
|
671
906
|
|
672
907
|
```ruby
|
673
908
|
Address.find(id).update_attributes(city: 'Chicago')
|
@@ -677,18 +912,18 @@ Address.update(id, { city: 'Chicago' }, if: { deliverable: true })
|
|
677
912
|
```
|
678
913
|
|
679
914
|
There are also some low level methods `#update`, `.update_fields` and
|
680
|
-
`.upsert`. They don't run validation and callbacks (except `#update` -
|
681
|
-
runs `update` callbacks). All of them support conditional updates.
|
915
|
+
`.upsert`. They don't run validation and callbacks (except `#update` -
|
916
|
+
it runs `update` callbacks). All of them support conditional updates.
|
682
917
|
`#upsert` will create new document if document with specified `id`
|
683
918
|
doesn't exist.
|
684
919
|
|
685
920
|
```ruby
|
686
|
-
|
921
|
+
Address.find(id).update do |i|
|
687
922
|
i.set city: 'Chicago'
|
688
923
|
i.add latitude: 100
|
689
924
|
i.delete set_of_numbers: 10
|
690
925
|
end
|
691
|
-
|
926
|
+
Address.find(id).update(if: { deliverable: true }) do |i|
|
692
927
|
i.set city: 'Chicago'
|
693
928
|
end
|
694
929
|
Address.update_fields(id, city: 'Chicago')
|
@@ -699,8 +934,8 @@ Address.upsert(id, { city: 'Chicago' }, if: { deliverable: true })
|
|
699
934
|
|
700
935
|
### Deleting
|
701
936
|
|
702
|
-
In order to delete some items `delete_all` method should be used.
|
703
|
-
|
937
|
+
In order to delete some items `delete_all` method should be used. Any
|
938
|
+
callback won't be called. Items delete in efficient way in batch.
|
704
939
|
|
705
940
|
```ruby
|
706
941
|
Address.where(city: 'London').delete_all
|
@@ -721,17 +956,24 @@ class User
|
|
721
956
|
end
|
722
957
|
```
|
723
958
|
|
724
|
-
There are following options:
|
959
|
+
There are the following options:
|
725
960
|
* `hash_key` - is used as hash key of an index,
|
726
961
|
* `range_key` - is used as range key of an index,
|
727
|
-
* `projected_attributes` - list of fields to store in an index or has a
|
728
|
-
|
729
|
-
* `
|
730
|
-
|
962
|
+
* `projected_attributes` - list of fields to store in an index or has a
|
963
|
+
predefined value `:keys_only`, `:all`; `:keys_only` is a default,
|
964
|
+
* `name` - an index will be created with this name when a table is
|
965
|
+
created; by default name is generated and contains table name and keys
|
966
|
+
names,
|
967
|
+
* `read_capacity` - is used when table created and used as an index
|
968
|
+
capacity; by default equals `Dynamoid::Config.read_capacity`,
|
969
|
+
* `write_capacity` - is used when table created and used as an index
|
970
|
+
capacity; by default equals `Dynamoid::Config.write_capacity`
|
731
971
|
|
732
972
|
The only mandatory option is `name`.
|
733
973
|
|
734
|
-
**WARNING:** In order to use global secondary index in `Document.where`
|
974
|
+
**WARNING:** In order to use global secondary index in `Document.where`
|
975
|
+
implicitly you need to have all the attributes of the original table in
|
976
|
+
the index and declare it with option `projected_attributes: :all`:
|
735
977
|
|
736
978
|
```ruby
|
737
979
|
class User
|
@@ -741,13 +983,16 @@ class User
|
|
741
983
|
end
|
742
984
|
```
|
743
985
|
|
744
|
-
There is only one implicit way to query Global and Local Secondary
|
986
|
+
There is only one implicit way to query Global and Local Secondary
|
987
|
+
Indexes (GSI/LSI).
|
745
988
|
|
746
989
|
#### Implicit
|
747
990
|
|
748
|
-
The second way implicitly uses your GSI through the `where` clauses and
|
749
|
-
|
750
|
-
|
991
|
+
The second way implicitly uses your GSI through the `where` clauses and
|
992
|
+
deduces the index based on the query fields provided. Another added
|
993
|
+
benefit is that it is built into query chaining so you can use all the
|
994
|
+
methods used in normal querying. The explicit way from above would be
|
995
|
+
rewritten as follows:
|
751
996
|
|
752
997
|
```ruby
|
753
998
|
where(dynamo_primary_key_column_name => dynamo_primary_key_value,
|
@@ -755,57 +1000,118 @@ where(dynamo_primary_key_column_name => dynamo_primary_key_value,
|
|
755
1000
|
.scan_index_forward(false)
|
756
1001
|
```
|
757
1002
|
|
758
|
-
The only caveat with this method is that because it is also used for
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
1003
|
+
The only caveat with this method is that because it is also used for
|
1004
|
+
general querying, it WILL NOT use a GSI unless it explicitly has defined
|
1005
|
+
`projected_attributes: :all` on the GSI in your model. This is because
|
1006
|
+
GSIs that do not have all attributes projected will only contain the
|
1007
|
+
index keys and therefore will not return objects with fully resolved
|
1008
|
+
field values. It currently opts to provide the complete results rather
|
1009
|
+
than partial results unless you've explicitly looked up the data.
|
763
1010
|
|
764
|
-
*Future TODO could involve implementing `select` in chaining as well as
|
765
|
-
the
|
1011
|
+
*Future TODO could involve implementing `select` in chaining as well as
|
1012
|
+
resolving the fields with a second query against the table since a query
|
1013
|
+
against GSI then a query on base table is still likely faster than scan
|
1014
|
+
on the base table*
|
766
1015
|
|
767
1016
|
## Configuration
|
768
1017
|
|
769
1018
|
Listed below are all configuration options.
|
770
1019
|
|
771
|
-
* `adapter` -
|
772
|
-
|
773
|
-
* `
|
774
|
-
|
775
|
-
|
776
|
-
* `
|
777
|
-
|
778
|
-
|
779
|
-
* `
|
1020
|
+
* `adapter` - useful only for the gem developers to switch to a new
|
1021
|
+
adapter. Default and the only available value is `aws_sdk_v3`
|
1022
|
+
* `namespace` - prefix for table names, default is
|
1023
|
+
`dynamoid_#{application_name}_#{environment}` for Rails application
|
1024
|
+
and `dynamoid` otherwise
|
1025
|
+
* `logger` - by default it's a `Rails.logger` in Rails application and
|
1026
|
+
`stdout` otherwise. You can disable logging by setting `nil` or
|
1027
|
+
`false` values. Set `true` value to use defaults
|
1028
|
+
* `access_key` - DynamoDb custom access key for AWS credentials, override global
|
1029
|
+
AWS credentials if they're present
|
1030
|
+
* `secret_key` - DynamoDb custom secret key for AWS credentials, override global
|
1031
|
+
AWS credentials if they're present
|
1032
|
+
* `credentials` - DynamoDb custom pre-configured credentials, override global
|
1033
|
+
AWS credentials if they're present
|
1034
|
+
* `region` - DynamoDb custom credentials for AWS, override global AWS
|
1035
|
+
credentials if they're present
|
1036
|
+
* `batch_size` - when you try to load multiple items at once with
|
1037
|
+
* `batch_get_item` call Dynamoid loads them not with one api call but
|
1038
|
+
piece by piece. Default is 100 items
|
1039
|
+
* `capacity_mode` - used at a table creation and means whether a table
|
1040
|
+
read/write capacity mode will be on-demand or provisioned. Allowed
|
1041
|
+
values are `:on_demand` and `:provisioned`. Default value is `nil` which
|
1042
|
+
means provisioned mode will be used.
|
1043
|
+
* `read_capacity` - is used at table or indices creation. Default is 100
|
1044
|
+
(units)
|
1045
|
+
* `write_capacity` - is used at table or indices creation. Default is 20
|
1046
|
+
(units)
|
780
1047
|
* `warn_on_scan` - log warnings when scan table. Default is `true`
|
781
|
-
* `endpoint` - if provided, it communicates with the DynamoDB listening
|
782
|
-
|
1048
|
+
* `endpoint` - if provided, it communicates with the DynamoDB listening
|
1049
|
+
at the endpoint. This is useful for testing with
|
1050
|
+
[DynamoDB Local](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.DynamoDBLocal.html)
|
1051
|
+
* `identity_map` - ensures that each object gets loaded only once by
|
1052
|
+
keeping every loaded object in a map. Looks up objects using the map
|
1053
|
+
when referring to them. Isn't thread safe. Default is `false`.
|
783
1054
|
`Use Dynamoid::Middleware::IdentityMap` to clear identity map for each HTTP request
|
784
|
-
* `timestamps` - by default Dynamoid sets `created_at` and `updated_at`
|
785
|
-
|
786
|
-
|
787
|
-
* `
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
* `
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
* `
|
799
|
-
|
800
|
-
* `
|
801
|
-
|
802
|
-
|
803
|
-
|
1055
|
+
* `timestamps` - by default Dynamoid sets `created_at` and `updated_at`
|
1056
|
+
fields for model creation and updating. You can disable this
|
1057
|
+
behavior by setting `false` value
|
1058
|
+
* `sync_retry_max_times` - when Dynamoid creates or deletes table
|
1059
|
+
synchronously it checks for completion specified times. Default is 60
|
1060
|
+
(times). It's a bit over 2 minutes by default
|
1061
|
+
* `sync_retry_wait_seconds` - time to wait between retries. Default is 2
|
1062
|
+
(seconds)
|
1063
|
+
* `convert_big_decimal` - if `true` then Dynamoid converts numbers
|
1064
|
+
stored in `Hash` in `raw` field to float. Default is `false`
|
1065
|
+
* `store_attribute_with_nil_value` - if `true` Dynamoid keeps attribute
|
1066
|
+
with `nil` value in a document. Otherwise Dynamoid removes it while
|
1067
|
+
saving a document. Default is `nil` which equals behaviour with `false`
|
1068
|
+
value.
|
1069
|
+
* `models_dir` - `dynamoid:create_tables` rake task loads DynamoDb
|
1070
|
+
models from this directory. Default is `./app/models`.
|
1071
|
+
* `application_timezone` - Dynamoid converts all `datetime` fields to
|
1072
|
+
specified time zone when loads data from the storage.
|
1073
|
+
Acceptable values - `:utc`, `:local` (to use system time zone) and
|
1074
|
+
time zone name e.g. `Eastern Time (US & Canada)`. Default is `utc`
|
1075
|
+
* `dynamodb_timezone` - When a datetime field is stored in string format
|
1076
|
+
Dynamoid converts it to specified time zone when saves a value to the
|
1077
|
+
storage. Acceptable values - `:utc`, `:local` (to use system time
|
1078
|
+
zone) and time zone name e.g. `Eastern Time (US & Canada)`. Default is
|
1079
|
+
`utc`
|
1080
|
+
* `store_datetime_as_string` - if `true` then Dynamoid stores :datetime
|
1081
|
+
fields in ISO 8601 string format. Default is `false`
|
1082
|
+
* `store_date_as_string` - if `true` then Dynamoid stores :date fields
|
1083
|
+
in ISO 8601 string format. Default is `false`
|
1084
|
+
* `store_boolean_as_native` - if `true` Dynamoid stores boolean fields
|
1085
|
+
as native DynamoDB boolean values. Otherwise boolean fields are stored
|
1086
|
+
as string values `'t'` and `'f'`. Default is true
|
1087
|
+
* `backoff` - is a hash: key is a backoff strategy (symbol), value is
|
1088
|
+
parameters for the strategy. Is used in batch operations. Default id
|
1089
|
+
`nil`
|
1090
|
+
* `backoff_strategies`: is a hash and contains all available strategies.
|
1091
|
+
Default is { constant: ..., exponential: ...}
|
1092
|
+
* `log_formatter`: overrides default AWS SDK formatter. There are
|
1093
|
+
several canned formatters: `Aws::Log::Formatter.default`,
|
1094
|
+
`Aws::Log::Formatter.colored` and `Aws::Log::Formatter.short`. Please
|
1095
|
+
look into `Aws::Log::Formatter` AWS SDK documentation in order to
|
1096
|
+
provide own formatter.
|
1097
|
+
* `http_continue_timeout`: The number of seconds to wait for a
|
1098
|
+
100-continue HTTP response before sending the request body. Default
|
1099
|
+
option value is `nil`. If not specified effected value is `1`
|
1100
|
+
* `http_idle_timeout`: The number of seconds an HTTP connection is
|
1101
|
+
allowed to sit idle before it is considered stale. Default option
|
1102
|
+
value is `nil`. If not specified effected value is `5`
|
1103
|
+
* `http_open_timeout`: The number of seconds to wait when opening a HTTP
|
1104
|
+
session. Default option value is `nil`. If not specified effected
|
1105
|
+
value is `15`
|
1106
|
+
* `http_read_timeout`:The number of seconds to wait for HTTP response
|
1107
|
+
data. Default option value is `nil`. If not specified effected value
|
1108
|
+
is `60`
|
804
1109
|
|
805
1110
|
|
806
1111
|
## Concurrency
|
807
1112
|
|
808
|
-
Dynamoid supports basic, ActiveRecord-like optimistic locking on save
|
1113
|
+
Dynamoid supports basic, ActiveRecord-like optimistic locking on save
|
1114
|
+
operations. Simply add a `lock_version` column to your table like so:
|
809
1115
|
|
810
1116
|
```ruby
|
811
1117
|
class MyTable
|
@@ -817,23 +1123,38 @@ class MyTable
|
|
817
1123
|
end
|
818
1124
|
```
|
819
1125
|
|
820
|
-
In this example, all saves to `MyTable` will raise an
|
1126
|
+
In this example, all saves to `MyTable` will raise an
|
1127
|
+
`Dynamoid::Errors::StaleObjectError` if a concurrent process loaded,
|
1128
|
+
edited, and saved the same row. Your code should trap this exception,
|
1129
|
+
reload the row (so that it will pick up the newest values), and try the
|
1130
|
+
save again.
|
821
1131
|
|
822
|
-
Calls to `update` and `update!` also increment the `lock_version`,
|
1132
|
+
Calls to `update` and `update!` also increment the `lock_version`,
|
1133
|
+
however, they do not check the existing value. This guarantees that a
|
1134
|
+
update operation will raise an exception in a concurrent save operation,
|
1135
|
+
however a save operation will never cause an update to fail. Thus,
|
1136
|
+
`update` is useful & safe only for doing atomic operations (e.g.
|
1137
|
+
increment a value, add/remove from a set, etc), but should not be used
|
1138
|
+
in a read-modify-write pattern.
|
823
1139
|
|
824
1140
|
|
825
1141
|
### Backoff strategies
|
826
1142
|
|
827
1143
|
|
828
|
-
You can use several methods that run efficiently in batch mode like
|
1144
|
+
You can use several methods that run efficiently in batch mode like
|
1145
|
+
`.find_all` and `.import`. It affects `Query` and `Scan` operations as
|
1146
|
+
well.
|
829
1147
|
|
830
|
-
The backoff strategy will be used when, for any reason, some items could
|
831
|
-
|
1148
|
+
The backoff strategy will be used when, for any reason, some items could
|
1149
|
+
not be processed as part of a batch mode command. Operations will be
|
1150
|
+
re-run to process these items.
|
832
1151
|
|
833
|
-
Exponential backoff is the recommended way to handle throughput limits
|
1152
|
+
Exponential backoff is the recommended way to handle throughput limits
|
1153
|
+
exceeding and throttling on the table.
|
834
1154
|
|
835
|
-
There are two built-in strategies - constant delay and truncated binary
|
836
|
-
By default no backoff is used but you can specify
|
1155
|
+
There are two built-in strategies - constant delay and truncated binary
|
1156
|
+
exponential backoff. By default no backoff is used but you can specify
|
1157
|
+
one of the built-in ones:
|
837
1158
|
|
838
1159
|
```ruby
|
839
1160
|
Dynamoid.configure do |config|
|
@@ -846,7 +1167,8 @@ end
|
|
846
1167
|
|
847
1168
|
```
|
848
1169
|
|
849
|
-
You can just specify strategy without any arguments to use default
|
1170
|
+
You can just specify strategy without any arguments to use default
|
1171
|
+
presets:
|
850
1172
|
|
851
1173
|
```ruby
|
852
1174
|
Dynamoid.configure do |config|
|
@@ -854,7 +1176,7 @@ Dynamoid.configure do |config|
|
|
854
1176
|
end
|
855
1177
|
```
|
856
1178
|
|
857
|
-
You can use your own strategy in following way:
|
1179
|
+
You can use your own strategy in the following way:
|
858
1180
|
|
859
1181
|
```ruby
|
860
1182
|
Dynamoid.configure do |config|
|
@@ -871,10 +1193,11 @@ end
|
|
871
1193
|
|
872
1194
|
There are a few Rake tasks available out of the box:
|
873
1195
|
|
874
|
-
|
875
|
-
|
1196
|
+
* `rake dynamoid:create_tables`
|
1197
|
+
* `rake dynamoid:ping`
|
876
1198
|
|
877
|
-
In order to use them in non-Rails application they should be required
|
1199
|
+
In order to use them in non-Rails application they should be required
|
1200
|
+
explicitly:
|
878
1201
|
|
879
1202
|
```ruby
|
880
1203
|
# Rakefile
|
@@ -883,12 +1206,14 @@ Rake::Task.define_task(:environment)
|
|
883
1206
|
require 'dynamoid/tasks'
|
884
1207
|
```
|
885
1208
|
|
886
|
-
The Rake tasks depend on `:environment` task so it should be declared
|
887
|
-
|
1209
|
+
The Rake tasks depend on `:environment` task so it should be declared as
|
1210
|
+
well.
|
888
1211
|
|
889
1212
|
## Test Environment
|
890
1213
|
|
891
|
-
In test environment you will most likely want to clean the database
|
1214
|
+
In test environment you will most likely want to clean the database
|
1215
|
+
between test runs to keep tests completely isolated. This can be
|
1216
|
+
achieved like so
|
892
1217
|
|
893
1218
|
```ruby
|
894
1219
|
module DynamoidReset
|
@@ -919,7 +1244,8 @@ RSpec.configure do |config|
|
|
919
1244
|
end
|
920
1245
|
```
|
921
1246
|
|
922
|
-
In Rails, you may also want to ensure you do not delete non-test data
|
1247
|
+
In Rails, you may also want to ensure you do not delete non-test data
|
1248
|
+
accidentally by adding the following to your test environment setup:
|
923
1249
|
|
924
1250
|
```ruby
|
925
1251
|
raise "Tests should be run in 'test' environment only" if Rails.env != 'test'
|
@@ -956,9 +1282,14 @@ timing (231.28 ms).
|
|
956
1282
|
|
957
1283
|
## Credits
|
958
1284
|
|
959
|
-
Dynamoid borrows code, structure, and even its name very liberally from
|
1285
|
+
Dynamoid borrows code, structure, and even its name very liberally from
|
1286
|
+
the truly amazing [Mongoid](https://github.com/mongoid/mongoid). Without
|
1287
|
+
Mongoid to crib from none of this would have been possible, and I hope
|
1288
|
+
they don't mind me reusing their very awesome ideas to make DynamoDB
|
1289
|
+
just as accessible to the Ruby world as MongoDB.
|
960
1290
|
|
961
|
-
Also, without contributors the project wouldn't be nearly as awesome. So
|
1291
|
+
Also, without contributors the project wouldn't be nearly as awesome. So
|
1292
|
+
many thanks to:
|
962
1293
|
|
963
1294
|
* [Logan Bowers](https://github.com/loganb)
|
964
1295
|
* [Lane LaRue](https://github.com/luxx)
|
@@ -979,9 +1310,12 @@ Also, without contributors the project wouldn't be nearly as awesome. So many th
|
|
979
1310
|
|
980
1311
|
## Running the tests
|
981
1312
|
|
982
|
-
Running the tests is fairly simple. You should have an instance of
|
1313
|
+
Running the tests is fairly simple. You should have an instance of
|
1314
|
+
DynamoDB running locally. Follow these steps to setup your test
|
1315
|
+
environment.
|
983
1316
|
|
984
|
-
* First download and unpack the latest version of DynamoDB.
|
1317
|
+
* First download and unpack the latest version of DynamoDB. We have a
|
1318
|
+
script that will do this for you if you use homebrew on a Mac.
|
985
1319
|
|
986
1320
|
```shell
|
987
1321
|
bin/setup
|
@@ -999,13 +1333,18 @@ Running the tests is fairly simple. You should have an instance of DynamoDB runn
|
|
999
1333
|
rake
|
1000
1334
|
```
|
1001
1335
|
|
1002
|
-
* When you are done, remember to stop the local test instance of
|
1336
|
+
* When you are done, remember to stop the local test instance of
|
1337
|
+
dynamodb
|
1003
1338
|
|
1004
1339
|
```shell
|
1005
1340
|
bin/stop_dynamodblocal
|
1006
1341
|
```
|
1007
1342
|
|
1008
|
-
If you want to run all the specs that travis runs, use `bundle exec
|
1343
|
+
If you want to run all the specs that travis runs, use `bundle exec
|
1344
|
+
wwtd`, but first you will need to setup all the rubies, for each of `%w(
|
1345
|
+
2.0.0-p648 2.1.10 2.2.6 2.3.3 2.4.1 jruby-9.1.8.0 )`. When you run
|
1346
|
+
`bundle exec wwtd` it will take care of starting and stopping the local
|
1347
|
+
dynamodb instance.
|
1009
1348
|
|
1010
1349
|
```shell
|
1011
1350
|
rvm use 2.0.0-p648
|