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
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
|
![GitHub](https://img.shields.io/github/license/Dynamoid/dynamoid.svg)
|
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
|