dynamoid 2.2.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +53 -0
- data/.rubocop_todo.yml +55 -0
- data/.travis.yml +5 -27
- data/Appraisals +17 -15
- data/CHANGELOG.md +26 -3
- data/Gemfile +4 -2
- data/README.md +95 -77
- data/Rakefile +17 -17
- data/Vagrantfile +5 -3
- data/dynamoid.gemspec +39 -45
- data/gemfiles/rails_4_2.gemfile +7 -5
- data/gemfiles/rails_5_0.gemfile +6 -4
- data/gemfiles/rails_5_1.gemfile +6 -4
- data/gemfiles/rails_5_2.gemfile +6 -4
- data/lib/dynamoid.rb +11 -4
- data/lib/dynamoid/adapter.rb +21 -27
- data/lib/dynamoid/adapter_plugin/{aws_sdk_v2.rb → aws_sdk_v3.rb} +118 -113
- data/lib/dynamoid/application_time_zone.rb +27 -0
- data/lib/dynamoid/associations.rb +3 -6
- data/lib/dynamoid/associations/association.rb +3 -6
- data/lib/dynamoid/associations/belongs_to.rb +4 -5
- data/lib/dynamoid/associations/has_and_belongs_to_many.rb +2 -3
- data/lib/dynamoid/associations/has_many.rb +2 -3
- data/lib/dynamoid/associations/has_one.rb +2 -3
- data/lib/dynamoid/associations/many_association.rb +8 -9
- data/lib/dynamoid/associations/single_association.rb +3 -3
- data/lib/dynamoid/components.rb +2 -2
- data/lib/dynamoid/config.rb +9 -5
- data/lib/dynamoid/config/backoff_strategies/constant_backoff.rb +4 -2
- data/lib/dynamoid/config/backoff_strategies/exponential_backoff.rb +3 -1
- data/lib/dynamoid/config/options.rb +4 -4
- data/lib/dynamoid/criteria.rb +3 -5
- data/lib/dynamoid/criteria/chain.rb +42 -49
- data/lib/dynamoid/dirty.rb +5 -4
- data/lib/dynamoid/document.rb +142 -36
- data/lib/dynamoid/dumping.rb +167 -0
- data/lib/dynamoid/dynamodb_time_zone.rb +16 -0
- data/lib/dynamoid/errors.rb +7 -6
- data/lib/dynamoid/fields.rb +24 -23
- data/lib/dynamoid/finders.rb +101 -59
- data/lib/dynamoid/identity_map.rb +5 -11
- data/lib/dynamoid/indexes.rb +45 -46
- data/lib/dynamoid/middleware/identity_map.rb +2 -0
- data/lib/dynamoid/persistence.rb +67 -307
- data/lib/dynamoid/primary_key_type_mapping.rb +34 -0
- data/lib/dynamoid/railtie.rb +3 -1
- data/lib/dynamoid/tasks/database.rake +11 -11
- data/lib/dynamoid/tasks/database.rb +4 -3
- data/lib/dynamoid/type_casting.rb +193 -0
- data/lib/dynamoid/undumping.rb +188 -0
- data/lib/dynamoid/validations.rb +4 -7
- data/lib/dynamoid/version.rb +3 -1
- metadata +59 -53
- data/gemfiles/rails_4_0.gemfile +0 -9
- data/gemfiles/rails_4_1.gemfile +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9cb9dd0de78473763541261beed167d81d2431b1
|
4
|
+
data.tar.gz: 057eea674112a29e69a55794a2815f2af8b14a7d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b231fdf9a13c129634234b3e01b587bbe52594f4063f28e9b682f55c2941db8c74ffc0d1da72c79911eff228443032c062c8f4430960872f969bdcd5583e2fe
|
7
|
+
data.tar.gz: 692db4e23c132dd5fb4266349c552f0e2561396f1443306380c1a3ae6d775b6a3a289720f3a26619f54332c08a0b0af07c6b9f977a289effb90d01678212fd9b
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# We chose not to make these changes
|
2
|
+
inherit_from: .rubocop_todo.yml
|
3
|
+
|
4
|
+
# It's the lowest supported Ruby version
|
5
|
+
AllCops:
|
6
|
+
TargetRubyVersion: 2.3
|
7
|
+
|
8
|
+
# It's a matter of taste
|
9
|
+
Layout/AlignParameters:
|
10
|
+
EnforcedStyle: with_fixed_indentation
|
11
|
+
Style/GuardClause:
|
12
|
+
Enabled: false
|
13
|
+
Style/FormatStringToken:
|
14
|
+
Enabled: false
|
15
|
+
Style/DoubleNegation:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
# We aren't so brave to tackle all these issues right now
|
19
|
+
Metrics/LineLength:
|
20
|
+
Enabled: false
|
21
|
+
Metrics/BlockLength:
|
22
|
+
Enabled: false
|
23
|
+
Metrics/MethodLength:
|
24
|
+
Enabled: false
|
25
|
+
Metrics/CyclomaticComplexity:
|
26
|
+
Enabled: false
|
27
|
+
Metrics/AbcSize:
|
28
|
+
Enabled: false
|
29
|
+
Metrics/ModuleLength:
|
30
|
+
Enabled: false
|
31
|
+
Metrics/BlockNesting:
|
32
|
+
Enabled: false
|
33
|
+
Metrics/PerceivedComplexity:
|
34
|
+
Enabled: false
|
35
|
+
Metrics/ClassLength:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
# Minor annoying issues
|
39
|
+
Lint/UselessAssignment:
|
40
|
+
Enabled: false
|
41
|
+
Lint/AmbiguousBlockAssociation:
|
42
|
+
Enabled: false
|
43
|
+
Lint/AssignmentInCondition:
|
44
|
+
Enabled: false
|
45
|
+
Style/Documentation:
|
46
|
+
Enabled: false
|
47
|
+
Style/DateTime:
|
48
|
+
Enabled: false
|
49
|
+
Style/MissingRespondToMissing:
|
50
|
+
Enabled: false
|
51
|
+
Naming/PredicateName:
|
52
|
+
Enabled: false
|
53
|
+
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2018-06-18 22:26:49 +0300 using RuboCop version 0.57.2.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 2
|
10
|
+
Lint/HandleExceptions:
|
11
|
+
Exclude:
|
12
|
+
- 'lib/dynamoid/document.rb'
|
13
|
+
|
14
|
+
# Offense count: 1
|
15
|
+
# Cop supports --auto-correct.
|
16
|
+
Security/YAMLLoad:
|
17
|
+
Exclude:
|
18
|
+
- 'lib/dynamoid/persistence.rb'
|
19
|
+
|
20
|
+
# Offense count: 1
|
21
|
+
# Cop supports --auto-correct.
|
22
|
+
# Configuration parameters: EnforcedStyle.
|
23
|
+
# SupportedStyles: braces, no_braces, context_dependent
|
24
|
+
Style/BracesAroundHashParameters:
|
25
|
+
Exclude:
|
26
|
+
- 'spec/dynamoid/adapter_plugin/aws_sdk_v3_spec.rb'
|
27
|
+
|
28
|
+
# Offense count: 2
|
29
|
+
# Cop supports --auto-correct.
|
30
|
+
# Configuration parameters: EnforcedStyle.
|
31
|
+
# SupportedStyles: module_function, extend_self
|
32
|
+
Style/ModuleFunction:
|
33
|
+
Exclude:
|
34
|
+
- 'lib/dynamoid.rb'
|
35
|
+
- 'lib/dynamoid/config.rb'
|
36
|
+
|
37
|
+
# Offense count: 1
|
38
|
+
Style/OptionalArguments:
|
39
|
+
Exclude:
|
40
|
+
- 'lib/dynamoid/document.rb'
|
41
|
+
|
42
|
+
# Offense count: 1
|
43
|
+
# Cop supports --auto-correct.
|
44
|
+
# Configuration parameters: AllowAsExpressionSeparator.
|
45
|
+
Style/Semicolon:
|
46
|
+
Exclude:
|
47
|
+
- 'spec/dynamoid/adapter_plugin/aws_sdk_v3_spec.rb'
|
48
|
+
|
49
|
+
# Offense count: 1
|
50
|
+
# Cop supports --auto-correct.
|
51
|
+
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
|
52
|
+
# Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
|
53
|
+
Style/TrivialAccessors:
|
54
|
+
Exclude:
|
55
|
+
- 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb'
|
data/.travis.yml
CHANGED
@@ -2,38 +2,16 @@ sudo: required
|
|
2
2
|
|
3
3
|
language: ruby
|
4
4
|
rvm:
|
5
|
-
- ruby-2.
|
6
|
-
- ruby-2.
|
7
|
-
- ruby-2.
|
8
|
-
-
|
9
|
-
- ruby-2.4.1
|
10
|
-
- jruby-9.1.9.0
|
5
|
+
- ruby-2.3.7
|
6
|
+
- ruby-2.4.4
|
7
|
+
- ruby-2.5.1
|
8
|
+
- jruby-9.1.17.0
|
11
9
|
gemfile:
|
12
10
|
gemfile:
|
13
|
-
- gemfiles/rails_4_0.gemfile
|
14
|
-
- gemfiles/rails_4_1.gemfile
|
15
11
|
- gemfiles/rails_4_2.gemfile
|
16
12
|
- gemfiles/rails_5_0.gemfile
|
17
13
|
- gemfiles/rails_5_1.gemfile
|
18
14
|
- gemfiles/rails_5_2.gemfile
|
19
|
-
matrix:
|
20
|
-
exclude:
|
21
|
-
- rvm: ruby-2.0.0-p648
|
22
|
-
gemfile: gemfiles/rails_5_0.gemfile
|
23
|
-
- rvm: ruby-2.0.0-p648
|
24
|
-
gemfile: gemfiles/rails_5_1.gemfile
|
25
|
-
- rvm: ruby-2.0.0-p648
|
26
|
-
gemfile: gemfiles/rails_5_2.gemfile
|
27
|
-
- rvm: ruby-2.1.10
|
28
|
-
gemfile: gemfiles/rails_5_0.gemfile
|
29
|
-
- rvm: ruby-2.1.10
|
30
|
-
gemfile: gemfiles/rails_5_1.gemfile
|
31
|
-
- rvm: ruby-2.1.10
|
32
|
-
gemfile: gemfiles/rails_5_2.gemfile
|
33
|
-
- rvm: ruby-2.4.1
|
34
|
-
gemfile: gemfiles/rails_4_0.gemfile
|
35
|
-
- rvm: ruby-2.4.1
|
36
|
-
gemfile: gemfiles/rails_4_1.gemfile
|
37
15
|
|
38
16
|
### BUILD LIFECYCLE STEPS ###
|
39
17
|
|
@@ -47,7 +25,7 @@ before_install:
|
|
47
25
|
- docker ps
|
48
26
|
|
49
27
|
after_install:
|
50
|
-
- gem install bundler -v 1.
|
28
|
+
- gem install bundler -v 1.16.2
|
51
29
|
- bundle install
|
52
30
|
|
53
31
|
before_script:
|
data/Appraisals
CHANGED
@@ -1,26 +1,28 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
appraise 'rails-4-0' do
|
4
|
+
gem 'rails', '~> 4.0.0'
|
5
|
+
gem 'nokogiri', '~> 1.6.8' # can be removed once we drop support for Ruby 2.0.0
|
4
6
|
end
|
5
7
|
|
6
|
-
appraise
|
7
|
-
gem
|
8
|
-
gem
|
8
|
+
appraise 'rails-4-1' do
|
9
|
+
gem 'rails', '~> 4.1.0'
|
10
|
+
gem 'nokogiri', '~> 1.6.8' # can be removed once we drop support for Ruby 2.0.0
|
9
11
|
end
|
10
12
|
|
11
|
-
appraise
|
12
|
-
gem
|
13
|
-
gem
|
13
|
+
appraise 'rails-4-2' do
|
14
|
+
gem 'rails', '~> 4.2.0'
|
15
|
+
gem 'nokogiri', '~> 1.6.8' # can be removed once we drop support for Ruby 2.0.0
|
14
16
|
end
|
15
17
|
|
16
|
-
appraise
|
17
|
-
gem
|
18
|
+
appraise 'rails-5-0' do
|
19
|
+
gem 'rails', '~> 5.0.0'
|
18
20
|
end
|
19
21
|
|
20
|
-
appraise
|
21
|
-
gem
|
22
|
+
appraise 'rails-5-1' do
|
23
|
+
gem 'rails', '~> 5.1.0'
|
22
24
|
end
|
23
25
|
|
24
|
-
appraise
|
25
|
-
gem
|
26
|
+
appraise 'rails-5-2' do
|
27
|
+
gem 'rails', '~> 5.2.0'
|
26
28
|
end
|
data/CHANGELOG.md
CHANGED
@@ -2,15 +2,38 @@
|
|
2
2
|
|
3
3
|
## Breaking
|
4
4
|
|
5
|
-
|
5
|
+
## Improvements
|
6
|
+
|
7
|
+
## Fixes
|
8
|
+
|
9
|
+
|
10
|
+
# 3.0.0
|
11
|
+
|
12
|
+
## Breaking
|
13
|
+
|
14
|
+
* Maintenance: [#267](https://github.com/Dynamoid/dynamoid/pull/267) Upgrade AWS SDK to V3
|
15
|
+
* Maintenance: [#268](https://github.com/Dynamoid/dynamoid/pull/268) Drop support of old Ruby versions. Support Ruby since 2.3 version
|
16
|
+
* Maintenance: [#268](https://github.com/Dynamoid/dynamoid/pull/268) Drop support of old Rails versions. Support Rails since 4.2 version
|
17
|
+
* Improvement: [#278](https://github.com/Dynamoid/dynamoid/pull/278) Add type casting for finders (`find`, `find_by_id` and `find_all`)
|
18
|
+
* Improvement: [#279](https://github.com/Dynamoid/dynamoid/pull/279) Change default value of `application_timezone` config option from `:local` to `:utc`
|
19
|
+
* Feature: [#288](https://github.com/Dynamoid/dynamoid/pull/288) Add `store_boolean_as_native` config option and set it to `true` by default. So all boolean fields are stored not as string `'t'` and `'f'` but as native boolean values now
|
20
|
+
* Feature: [#289](https://github.com/Dynamoid/dynamoid/pull/289) Add `dynamodb_timezone` config option and set it to `:utc` by default. So now all `date` and `datetime` fields stored in string format will be converted to UTC time zone by default
|
6
21
|
|
7
22
|
## Improvements
|
8
23
|
|
9
|
-
*
|
24
|
+
* Improvement: [#261](https://github.com/Dynamoid/Dynamoid/pull/261) Improve documentation (@walkersumida)
|
25
|
+
* Improvement: [#264](https://github.com/Dynamoid/Dynamoid/pull/264) Improve documentation (@xbx)
|
26
|
+
* Improvement: [#278](https://github.com/Dynamoid/Dynamoid/pull/278) Add Rails-like type casting
|
27
|
+
* Maintenance: [#281](https://github.com/Dynamoid/Dynamoid/pull/281) Deprecate dynamic finders, `find_all`, `find_by_id`, `find_by_composite_key`, `find_all_by_composite_key` and `find_all_by_secondary_index`
|
28
|
+
* Improvement: [#285](https://github.com/Dynamoid/Dynamoid/pull/285) Set timestamps (`created_at` and `updated_at`) in `upsert`, `update_fields`, `import` and `update` methods
|
29
|
+
* Improvement: [#286](https://github.com/Dynamoid/Dynamoid/pull/286) Disable scan warning when intentionally loading all items from a collection (@knovoselic)
|
10
30
|
|
11
31
|
## Fixes
|
12
32
|
|
13
|
-
*
|
33
|
+
* Bug: [#275](https://github.com/Dynamoid/Dynamoid/pull/275) Fix custom type serialization/deserialization
|
34
|
+
* Bug: [#283](https://github.com/Dynamoid/Dynamoid/pull/283) Fix using string formats for partition and sort keys of `date`/`datetime` type
|
35
|
+
* Bug: [#283](https://github.com/Dynamoid/Dynamoid/pull/283) Fix type declaration of custom type fields. Returned by `.dynamoid_field_type` value is treated as Dynamoid's type now
|
36
|
+
* Bug: [#287](https://github.com/Dynamoid/Dynamoid/pull/287) Fix logging disabling (@ghiculescu)
|
14
37
|
|
15
38
|
# 2.2.0
|
16
39
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -23,11 +23,11 @@ But if you want a fast, scalable, simple, easy-to-use database (and a Gem that s
|
|
23
23
|
| version | [![Gem Version](https://badge.fury.io/rb/dynamoid.svg)](https://rubygems.org/gems/dynamoid) |
|
24
24
|
| dependencies | [![Dependency Status](https://gemnasium.com/badges/github.com/Dynamoid/Dynamoid.svg)](https://gemnasium.com/github.com/Dynamoid/Dynamoid) [![Depfu](https://badges.depfu.com/badges/6661c063c8e77a5008344fc7283a50aa/status.svg)](https://depfu.com)|
|
25
25
|
| code quality | [![Code Climate](https://codeclimate.com/github/Dynamoid/Dynamoid.svg)](https://codeclimate.com/github/Dynamoid/Dynamoid) |
|
26
|
-
| continuous integration | [![Build Status](https://travis-ci.org/Dynamoid/
|
26
|
+
| continuous integration | [![Build Status](https://travis-ci.org/Dynamoid/dynamoid.svg?branch=master)](https://travis-ci.org/Dynamoid/dynamoid) |
|
27
27
|
| test coverage | [![Coverage Status](https://coveralls.io/repos/github/Dynamoid/Dynamoid/badge.svg?branch=master)](https://coveralls.io/github/Dynamoid/Dynamoid?branch=master) |
|
28
28
|
| triage helpers | [![CodeTriage Helpers](https://www.codetriage.com/dynamoid/dynamoid/badges/users.svg)](https://www.codetriage.com/dynamoid/dynamoid) |
|
29
|
-
| homepage | [https://github.com/Dynamoid/
|
30
|
-
| documentation | [http://rdoc.info/github/Dynamoid/
|
29
|
+
| homepage | [https://github.com/Dynamoid/dynamoid](https://github.com/Dynamoid/dynamoid) |
|
30
|
+
| documentation | [http://rdoc.info/github/Dynamoid/dynamoid/frames](http://rdoc.info/github/Dynamoid/dynamoid/frames) |
|
31
31
|
|
32
32
|
## Installation
|
33
33
|
|
@@ -38,17 +38,9 @@ gem 'dynamoid', '~> 2'
|
|
38
38
|
```
|
39
39
|
## Prerequisities
|
40
40
|
|
41
|
-
Dynamoid depends on the aws-sdk, and this is tested on the current version of aws-sdk (~>
|
41
|
+
Dynamoid depends on the aws-sdk, and this is tested on the current version of aws-sdk (~> 3), rails (>= 4).
|
42
42
|
Hence the configuration as needed for aws to work will be dealt with by aws setup.
|
43
43
|
|
44
|
-
Here are the steps to setup aws-sdk.
|
45
|
-
|
46
|
-
```ruby
|
47
|
-
gem 'aws-sdk', '~>2'
|
48
|
-
```
|
49
|
-
|
50
|
-
(or) include the aws-sdk in your Gemfile.
|
51
|
-
|
52
44
|
### AWS SDK Version Compatibility
|
53
45
|
|
54
46
|
Make sure you are using the version for the right AWS SDK.
|
@@ -58,7 +50,7 @@ Make sure you are using the version for the right AWS SDK.
|
|
58
50
|
| 0.x | 1.x |
|
59
51
|
| 1.x | 2.x |
|
60
52
|
| 2.x | 2.x |
|
61
|
-
| 3.x
|
53
|
+
| 3.x | 3.x |
|
62
54
|
|
63
55
|
### AWS Configuration
|
64
56
|
|
@@ -67,7 +59,7 @@ Configure AWS access:
|
|
67
59
|
|
68
60
|
For example, to configure AWS access:
|
69
61
|
|
70
|
-
Create config/initializers/aws.rb as follows:
|
62
|
+
Create `config/initializers/aws.rb` as follows:
|
71
63
|
|
72
64
|
```ruby
|
73
65
|
|
@@ -97,28 +89,27 @@ Then you need to initialize Dynamoid config to get it going. Put code similar to
|
|
97
89
|
```ruby
|
98
90
|
require 'dynamoid'
|
99
91
|
Dynamoid.configure do |config|
|
100
|
-
config.namespace =
|
92
|
+
config.namespace = 'dynamoid_app_development' # To namespace tables created by Dynamoid from other tables you might have. Set to nil to avoid namespacing.
|
101
93
|
config.endpoint = 'http://localhost:3000' # [Optional]. If provided, it communicates with the DB listening at the endpoint. This is useful for testing with [Amazon Local DB] (http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.DynamoDBLocal.html).
|
102
94
|
end
|
103
|
-
|
104
95
|
```
|
105
96
|
|
106
|
-
### Ruby
|
97
|
+
### Ruby & Rails Compatibility
|
107
98
|
|
108
|
-
|
99
|
+
Dynamoid supports Ruby >= 2.3 and Rails >= 4.2.
|
100
|
+
|
101
|
+
Its compatibility is tested in following way:
|
102
|
+
|
103
|
+
| Ruby / Active Record | 4.2.x | 5.0.x | 5.1.x | 5.2.x |
|
109
104
|
|:---------------------:|:-----:|:-----:|:-----:|:-----:|
|
110
|
-
| 2.
|
111
|
-
| 2.
|
112
|
-
| 2.
|
113
|
-
|
|
114
|
-
| 2.3.x | ✓ | ✓ | ✓ | ✓ |
|
115
|
-
| 2.3.x | ✓ | ✓ | ✓ | ✓ |
|
116
|
-
| 2.4.x | | | ✓ | ✓ |
|
117
|
-
| jruby-9.X | ✓ | ✓ | ✓ | ✓ |
|
105
|
+
| 2.3.7 | ✓ | ✓ | ✓ | ✓ |
|
106
|
+
| 2.4.4 | ✓ | ✓ | ✓ | ✓ |
|
107
|
+
| 2.5.1 | ✓ | ✓ | ✓ | ✓ |
|
108
|
+
| jruby-9.1.17.0 | ✓ | ✓ | ✓ | ✓ |
|
118
109
|
|
119
110
|
## Setup
|
120
111
|
|
121
|
-
You *must* include
|
112
|
+
You *must* include `Dynamoid::Document` in every Dynamoid model.
|
122
113
|
|
123
114
|
```ruby
|
124
115
|
class User
|
@@ -135,34 +126,34 @@ Dynamoid has some sensible defaults for you when you create a new table, includi
|
|
135
126
|
class User
|
136
127
|
include Dynamoid::Document
|
137
128
|
|
138
|
-
table :
|
129
|
+
table name: :awesome_users, key: :user_id, read_capacity: 5, write_capacity: 5
|
139
130
|
end
|
140
131
|
```
|
141
132
|
|
142
|
-
These fields will not change an existing table: so specifying a new read_capacity and write_capacity here only works correctly for entirely new tables. Similarly, while Dynamoid will look for a table named `awesome_users` in your namespace, it won't change any existing tables to use that name; and if it does find a table with the correct name, it won't change its hash key, which it expects will be user_id
|
133
|
+
These fields will not change an existing table: so specifying a new read_capacity and write_capacity here only works correctly for entirely new tables. Similarly, while Dynamoid will look for a table named `awesome_users` in your namespace, it won't change any existing tables to use that name; and if it does find a table with the correct name, it won't change its hash key, which it expects will be `user_id`. If this table doesn't exist yet, however, Dynamoid will create it with these options.
|
143
134
|
|
144
135
|
### Fields
|
145
136
|
|
146
137
|
You'll have to define all the fields on the model and the data type of each field. Every field on the object must be included here; if you miss any they'll be completely bypassed during DynamoDB's initialization and will not appear on the model objects.
|
147
138
|
|
148
|
-
By default, fields are assumed to be of type
|
149
|
-
|
150
|
-
|
139
|
+
By default, fields are assumed to be of type `:string`. Other built-in types are
|
140
|
+
`:integer`, `:number`, `:set`, `:array`, `:datetime`, `date`, `:boolean`, `:raw` and `:serialized`.
|
141
|
+
`raw` type means you can store Ruby Array, Hash, String and numbers.
|
151
142
|
If built-in types do not suit you, you can use a custom field type represented by an arbitrary class, provided that the class supports a compatible serialization interface.
|
152
143
|
The primary use case for using a custom field type is to represent your business logic with high-level types, while ensuring portability or backward-compatibility of the serialized representation.
|
153
144
|
|
154
145
|
#### Note on boolean type
|
155
146
|
|
156
|
-
The boolean fields are stored as
|
157
|
-
|
158
|
-
|
159
|
-
achieve this with `store_as_native_boolean` option:
|
147
|
+
The boolean fields are stored as DynamoDB boolean values by default.
|
148
|
+
Dynamoid can store boolean values as strings as well - `'t'` and `'f'`.
|
149
|
+
So if you want to change default format of boolean field you can easily
|
150
|
+
achieve this with `store_as_native_boolean` field option:
|
160
151
|
|
161
152
|
```ruby
|
162
153
|
class Document
|
163
154
|
include DynamoId::Document
|
164
155
|
|
165
|
-
field :active, :boolean, store_as_native_boolean:
|
156
|
+
field :active, :boolean, store_as_native_boolean: false
|
166
157
|
end
|
167
158
|
```
|
168
159
|
|
@@ -174,13 +165,13 @@ By default date fields are persisted as days count since 1 January 1970 like UNI
|
|
174
165
|
class Document
|
175
166
|
include DynamoId::Document
|
176
167
|
|
177
|
-
field :
|
168
|
+
field :sent_on, :date, store_as_string: true
|
178
169
|
end
|
179
170
|
```
|
180
171
|
|
181
172
|
#### Note on datetime type
|
182
173
|
|
183
|
-
By default datetime fields are persisted as UNIX timestamps with
|
174
|
+
By default datetime fields are persisted as UNIX timestamps with millisecond precision in DynamoDB. If you prefer datetimes to be stored as ISO-8601 formatted strings instead then set `store_as_string` to `true`
|
184
175
|
|
185
176
|
```ruby
|
186
177
|
class Document
|
@@ -190,7 +181,15 @@ class Document
|
|
190
181
|
end
|
191
182
|
```
|
192
183
|
|
193
|
-
|
184
|
+
WARNING: Fields in numeric format are stored with nanoseconds as a fraction part and precision could be lost.
|
185
|
+
That's why `datetime` field in numeric format shouldn't be used as a range key.
|
186
|
+
|
187
|
+
You have two options if you need to use a `datetime` field as a range key:
|
188
|
+
* string format
|
189
|
+
* store `datetime` values without milliseconds e.g. cut them
|
190
|
+
manually with `change` method - `Time.now.change(usec: 0)`
|
191
|
+
|
192
|
+
#### Note on set type
|
194
193
|
|
195
194
|
There is `of` option to declare the type of set elements. You can use
|
196
195
|
`:integer` value only
|
@@ -206,7 +205,7 @@ end
|
|
206
205
|
|
207
206
|
#### Magic Columns
|
208
207
|
|
209
|
-
You get magic columns of id (string), created_at (datetime), and updated_at (datetime) for free.
|
208
|
+
You get magic columns of `id` (`string`), `created_at` (`datetime`), and `updated_at` (`datetime`) for free.
|
210
209
|
|
211
210
|
```ruby
|
212
211
|
class User
|
@@ -227,8 +226,8 @@ end
|
|
227
226
|
You can optionally set a default value on a field using either a plain value or a lambda:
|
228
227
|
|
229
228
|
```ruby
|
230
|
-
field :actions_taken, :integer,
|
231
|
-
field :joined_at, :datetime,
|
229
|
+
field :actions_taken, :integer, default: 0
|
230
|
+
field :joined_at, :datetime, default: -> { Time.now }
|
232
231
|
```
|
233
232
|
|
234
233
|
#### Custom Types
|
@@ -240,7 +239,7 @@ To use a custom type for a field, suppose you have a `Money` type.
|
|
240
239
|
# ... your business logic ...
|
241
240
|
|
242
241
|
def dynamoid_dump
|
243
|
-
|
242
|
+
'serialized representation as a string'
|
244
243
|
end
|
245
244
|
|
246
245
|
def self.dynamoid_load(serialized_str)
|
@@ -284,17 +283,32 @@ add a level of indirection for serializing.) Example:
|
|
284
283
|
|
285
284
|
Lastly, you can control the data type of your custom-class-backed field at the DynamoDB level.
|
286
285
|
This is especially important if you want to use your custom field as a numeric range or for
|
287
|
-
number-oriented queries.
|
286
|
+
number-oriented queries. By default custom fields are persisted as a string attribute, but
|
288
287
|
your custom class can override this with a `.dynamoid_field_type` class method, which would
|
289
288
|
return either `:string` or `:number`.
|
290
289
|
|
291
290
|
DynamoDB may support some other attribute types that are not yet supported by Dynamoid.
|
292
291
|
|
292
|
+
### Sort key
|
293
|
+
|
294
|
+
Along with partition key table may have a sort key. In order to declare it in a model
|
295
|
+
`range` class method should be used:
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
class Post
|
299
|
+
include Dynamoid::Document
|
300
|
+
|
301
|
+
range :posted_at, :datetime
|
302
|
+
end
|
303
|
+
```
|
304
|
+
|
305
|
+
Second argument, type, is optional. Default type is `string`.
|
306
|
+
|
293
307
|
### Associations
|
294
308
|
|
295
309
|
Just like in ActiveRecord (or your other favorite ORM), Dynamoid uses associations to create links between models.
|
296
310
|
|
297
|
-
The only supported associations (so far) are
|
311
|
+
The only supported associations (so far) are `has_many`, `has_one`, `has_and_belongs_to_many`, and `belongs_to`. Associations are very simple to create: just specify the type, the name, and then any options you'd like to pass to the association. If there's an inverse association either inferred or specified directly, Dynamoid will update both objects to point at each other.
|
298
312
|
|
299
313
|
```ruby
|
300
314
|
class User
|
@@ -303,12 +317,12 @@ class User
|
|
303
317
|
# ...
|
304
318
|
|
305
319
|
has_many :addresses
|
306
|
-
has_many :students, :
|
307
|
-
belongs_to :teacher, :
|
320
|
+
has_many :students, class: User
|
321
|
+
belongs_to :teacher, class_name: :user
|
308
322
|
belongs_to :group
|
309
|
-
belongs_to :group, :
|
323
|
+
belongs_to :group, foreign_key: :group_id
|
310
324
|
has_one :role
|
311
|
-
has_and_belongs_to_many :friends, :
|
325
|
+
has_and_belongs_to_many :friends, inverse_of: :friending_users
|
312
326
|
|
313
327
|
end
|
314
328
|
|
@@ -322,7 +336,7 @@ class Address
|
|
322
336
|
end
|
323
337
|
```
|
324
338
|
|
325
|
-
Contrary to what you'd expect, association information is always contained on the object specifying the association, even if it seems like the association has a foreign key. This is a side effect of DynamoDB's structure: it's very difficult to find foreign keys without an index. Usually you won't find this to be a problem, but it does mean that association methods that build new models will not work correctly -- for example,
|
339
|
+
Contrary to what you'd expect, association information is always contained on the object specifying the association, even if it seems like the association has a foreign key. This is a side effect of DynamoDB's structure: it's very difficult to find foreign keys without an index. Usually you won't find this to be a problem, but it does mean that association methods that build new models will not work correctly -- for example, `user.addresses.new` returns an address that is not associated to the user. We'll be correcting this ~soon~ maybe someday, if we get a pull request.
|
326
340
|
|
327
341
|
### Validations
|
328
342
|
|
@@ -335,7 +349,7 @@ class User
|
|
335
349
|
# ...
|
336
350
|
|
337
351
|
validates_presence_of :name
|
338
|
-
validates_format_of :email, :
|
352
|
+
validates_format_of :email, with: /@/
|
339
353
|
end
|
340
354
|
```
|
341
355
|
|
@@ -383,7 +397,6 @@ cat = Cat.create(name: 'Morgan')
|
|
383
397
|
animal = Animal.find(cat.id)
|
384
398
|
animal.class
|
385
399
|
#=> Cat
|
386
|
-
|
387
400
|
```
|
388
401
|
|
389
402
|
## Usage
|
@@ -393,7 +406,7 @@ animal.class
|
|
393
406
|
Dynamoid's syntax is generally very similar to ActiveRecord's. Making new objects is simple:
|
394
407
|
|
395
408
|
```ruby
|
396
|
-
u = User.new(:
|
409
|
+
u = User.new(name: 'Josh')
|
397
410
|
u.email = 'josh@joshsymonds.com'
|
398
411
|
u.save
|
399
412
|
```
|
@@ -401,7 +414,7 @@ u.save
|
|
401
414
|
Save forces persistence to the datastore: a unique ID is also assigned, but it is a string and not an auto-incrementing number.
|
402
415
|
|
403
416
|
```ruby
|
404
|
-
u.id # =>
|
417
|
+
u.id # => '3a9f7216-4726-4aea-9fbc-8554ae9292cb'
|
405
418
|
```
|
406
419
|
|
407
420
|
To use associations, you use association methods very similar to ActiveRecord's:
|
@@ -431,14 +444,14 @@ Querying can be done in one of three ways:
|
|
431
444
|
|
432
445
|
```ruby
|
433
446
|
Address.find(address.id) # Find directly by ID.
|
434
|
-
Address.where(:
|
447
|
+
Address.where(city: 'Chicago').all # Find by any number of matching criteria... though presently only "where" is supported.
|
435
448
|
Address.find_by_city('Chicago') # The same as above, but using ActiveRecord's older syntax.
|
436
449
|
```
|
437
450
|
|
438
451
|
And you can also query on associations:
|
439
452
|
|
440
453
|
```ruby
|
441
|
-
u.addresses.where(:
|
454
|
+
u.addresses.where(city: 'Chicago').all
|
442
455
|
```
|
443
456
|
|
444
457
|
But keep in mind Dynamoid -- and document-based storage systems in general -- are not drop-in replacements for existing relational databases. The above query does not efficiently perform a conditional join, but instead finds all the user's addresses and naively filters them in Ruby. For large associations this is a performance hit compared to relational database engines.
|
@@ -475,7 +488,7 @@ For large queries that return many rows, Dynamoid can use AWS' support for reque
|
|
475
488
|
```ruby
|
476
489
|
# Do some maintenance on the entire table without flooding DynamoDB
|
477
490
|
Address.all(batch_size: 100).each { |address| address.do_some_work; sleep(0.01) }
|
478
|
-
Address.record_limit(10_000).batch(100).
|
491
|
+
Address.record_limit(10_000).batch(100).each { … } # Batch specified as part of a chain
|
479
492
|
```
|
480
493
|
|
481
494
|
The implication of batches is that the underlying requests are done in the batch sizes to make the request and responses
|
@@ -488,21 +501,21 @@ You are able to optimize query with condition for sort key. Following operators
|
|
488
501
|
|
489
502
|
```ruby
|
490
503
|
Address.where(latitude: 10212)
|
491
|
-
Address.where('latitude.gt'
|
492
|
-
Address.where('latitude.lt'
|
493
|
-
Address.where('latitude.gte'
|
494
|
-
Address.where('latitude.lte'
|
495
|
-
Address.where('city.begins_with'
|
496
|
-
Address.where('latitude.between'
|
504
|
+
Address.where('latitude.gt': 10212)
|
505
|
+
Address.where('latitude.lt': 10212)
|
506
|
+
Address.where('latitude.gte': 10212)
|
507
|
+
Address.where('latitude.lte': 10212)
|
508
|
+
Address.where('city.begins_with': 'Lon')
|
509
|
+
Address.where('latitude.between': [10212, 20000])
|
497
510
|
```
|
498
511
|
|
499
512
|
You are able to filter results on the DynamoDB side and specify conditions for non-key fields.
|
500
513
|
Following operators are available: `in`, `contains`, `not_contains`:
|
501
514
|
|
502
515
|
```ruby
|
503
|
-
Address.where('city.in'
|
504
|
-
Address.where('city.contains'
|
505
|
-
Address.where('city.not_contains'
|
516
|
+
Address.where('city.in': ['London', 'Edenburg', 'Birmingham'])
|
517
|
+
Address.where('city.contains': ['on'])
|
518
|
+
Address.where('city.not_contains': ['ing'])
|
506
519
|
```
|
507
520
|
|
508
521
|
### Consistent Reads
|
@@ -510,8 +523,8 @@ Address.where('city.not_contains' => [ing])
|
|
510
523
|
Querying supports consistent reading. By default, DynamoDB reads are eventually consistent: if you do a write and then a read immediately afterwards, the results of the previous write may not be reflected. If you need to do a consistent read (that is, you need to read the results of a write immediately) you can do so, but keep in mind that consistent reads are twice as expensive as regular reads for DynamoDB.
|
511
524
|
|
512
525
|
```ruby
|
513
|
-
Address.find(address.id, :
|
514
|
-
Address.where(:
|
526
|
+
Address.find(address.id, consistent_read: true) # Find an address, ensure the read is consistent.
|
527
|
+
Address.where(city: 'Chicago').consistent.all # Find all addresses where the city is Chicago, with a consistent read.
|
515
528
|
```
|
516
529
|
|
517
530
|
### Range Finding
|
@@ -519,11 +532,11 @@ Address.where(:city => 'Chicago').consistent.all # Find all addresses where t
|
|
519
532
|
If you have a range index, Dynamoid provides a number of additional other convenience methods to make your life a little easier:
|
520
533
|
|
521
534
|
```ruby
|
522
|
-
User.where("created_at.gt"
|
523
|
-
User.where("created_at.lt"
|
535
|
+
User.where("created_at.gt": DateTime.now - 1.day).all
|
536
|
+
User.where("created_at.lt": DateTime.now - 1.day).all
|
524
537
|
```
|
525
538
|
|
526
|
-
It also supports
|
539
|
+
It also supports `gte` and `lte`. Turning those into symbols and allowing a Rails SQL-style string syntax is in the works. You can only have one range argument per query, because of DynamoDB's inherent limitations, so use it sensibly!
|
527
540
|
|
528
541
|
|
529
542
|
### Updating
|
@@ -534,7 +547,7 @@ They run validation and collbacks.
|
|
534
547
|
|
535
548
|
```ruby
|
536
549
|
Address.find(id).update_attributes(city: 'Chicago')
|
537
|
-
Address.find(id).update_attribute(city, 'Chicago')
|
550
|
+
Address.find(id).update_attribute(:city, 'Chicago')
|
538
551
|
Address.update(id, city: 'Chicago')
|
539
552
|
Address.update(id, { city: 'Chicago' }, if: { deliverable: true })
|
540
553
|
```
|
@@ -566,7 +579,7 @@ In order to delete some items `delete_all` method should be used.
|
|
566
579
|
Any callback wont be called. Items delete in efficient way in batch.
|
567
580
|
|
568
581
|
```ruby
|
569
|
-
Address.where(city:
|
582
|
+
Address.where(city: 'London').delete_all
|
570
583
|
```
|
571
584
|
|
572
585
|
### Global Secondary Indexes
|
@@ -613,7 +626,7 @@ find_all_by_secondary_index(
|
|
613
626
|
},
|
614
627
|
# false is the same as DESC in SQL (newest timestamp first)
|
615
628
|
# true is the same as ASC in SQL (oldest timestamp first)
|
616
|
-
:
|
629
|
+
scan_index_forward: false # or true
|
617
630
|
)
|
618
631
|
```
|
619
632
|
|
@@ -658,7 +671,7 @@ the table since a query against GSI then a query on base table is still likely f
|
|
658
671
|
|
659
672
|
Listed below are all configuration options.
|
660
673
|
|
661
|
-
* `adapter` - usefull only for the gem developers to switch to a new adapter. Default and the only available value is `
|
674
|
+
* `adapter` - usefull only for the gem developers to switch to a new adapter. Default and the only available value is `aws_sdk_v3`
|
662
675
|
* `namespace` - prefix for table names, default is `dynamoid_#{application_name}_#{environment}` for Rails application and `dynamoid` otherwise
|
663
676
|
* `logger` - by default it's a `Rails.logger` in Rails application and `stdout` otherwise. You can disable logging by setting `nil` or `false` values. Set `true` value to use defaults
|
664
677
|
* `access_key` - DynamoDb custom credentials for AWS, override global AWS credentials if they present
|
@@ -677,9 +690,14 @@ Listed below are all configuration options.
|
|
677
690
|
* `convert_big_decimal` - if `true` then Dynamoid converts numbers stored in `Hash` in `raw` field to float. Default is `false`
|
678
691
|
* `models_dir` - `dynamoid:create_tables` rake task loads DynamoDb models from this directory. Default is `./app/models`.
|
679
692
|
* `application_timezone` - Dynamoid converts all `datetime` fields to specified time zone when loads data from the storage.
|
680
|
-
Acceptable values -
|
693
|
+
Acceptable values - `:utc`, `:local` (to use system time zone) and time zone name e.g. `Eastern Time (US & Canada)`. Default is `utc`
|
694
|
+
* `dynamodb_timezone` - When a datetime field is stored in string format Dynamoid converts it to specified time zone when saves a value to the storage.
|
695
|
+
Acceptable values - `:utc`, `:local` (to use system time zone) and time zone name e.g. `Eastern Time (US & Canada)`. Default is `utc`
|
681
696
|
* `store_datetime_as_string` - if `true` then Dynamoid stores :datetime fields in ISO 8601 string format. Default is `false`
|
682
697
|
* `store_date_as_string` - if `true` then Dynamoid stores :date fields in ISO 8601 string format. Default is `false`
|
698
|
+
* `store_boolean_as_native` - if `true` Dynamoid stores boolean fields as native DynamoDB
|
699
|
+
boolean values. Otherwise boolean fields are stored as string values
|
700
|
+
`'t'` and `'f'`. Default is true
|
683
701
|
* `backoff` - is a hash: key is a backoff strategy (symbol), value is parameters for the strategy. Is used in batch operations. Default id `nil`
|
684
702
|
* `backoff_strategies`: is a hash and contains all available strategies. Default is { constant: ..., exponential: ...}
|
685
703
|
|