dynamoid_advanced_where 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.circleci/config.yml +100 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +19 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Appraisals +8 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +119 -0
- data/README.md +375 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/dynamoid_advanced_where.gemspec +41 -0
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/dynamoid_3.4.gemfile +8 -0
- data/gemfiles/dynamoid_3.4.gemfile.lock +118 -0
- data/gemfiles/dynamoid_latest.gemfile +8 -0
- data/gemfiles/dynamoid_latest.gemfile.lock +118 -0
- data/lib/dynamoid_advanced_where.rb +8 -0
- data/lib/dynamoid_advanced_where/batched_updater.rb +229 -0
- data/lib/dynamoid_advanced_where/filter_builder.rb +136 -0
- data/lib/dynamoid_advanced_where/integrations/model.rb +34 -0
- data/lib/dynamoid_advanced_where/nodes.rb +15 -0
- data/lib/dynamoid_advanced_where/nodes/and_node.rb +43 -0
- data/lib/dynamoid_advanced_where/nodes/base_node.rb +18 -0
- data/lib/dynamoid_advanced_where/nodes/equality_node.rb +37 -0
- data/lib/dynamoid_advanced_where/nodes/exists_node.rb +44 -0
- data/lib/dynamoid_advanced_where/nodes/field_node.rb +186 -0
- data/lib/dynamoid_advanced_where/nodes/greater_than_node.rb +25 -0
- data/lib/dynamoid_advanced_where/nodes/includes.rb +29 -0
- data/lib/dynamoid_advanced_where/nodes/less_than_node.rb +27 -0
- data/lib/dynamoid_advanced_where/nodes/literal_node.rb +28 -0
- data/lib/dynamoid_advanced_where/nodes/not.rb +35 -0
- data/lib/dynamoid_advanced_where/nodes/null_node.rb +25 -0
- data/lib/dynamoid_advanced_where/nodes/operation_node.rb +44 -0
- data/lib/dynamoid_advanced_where/nodes/or_node.rb +41 -0
- data/lib/dynamoid_advanced_where/nodes/root_node.rb +47 -0
- data/lib/dynamoid_advanced_where/nodes/subfield.rb +17 -0
- data/lib/dynamoid_advanced_where/query_builder.rb +47 -0
- data/lib/dynamoid_advanced_where/query_materializer.rb +73 -0
- data/lib/dynamoid_advanced_where/version.rb +3 -0
- metadata +216 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 92ed86764764bc4cb565a2499dcbb686dcc82c043e2e6739d5e9a43a508096e7
|
4
|
+
data.tar.gz: ab2b862945f23e4289b7231346ad81a457fba65c222b0c1b4bd0f219f4ca2d8c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1ea844c390551ebfb5813ac4c6c4f66a5acd31699fbe964e10fa08b912d464f46ff1685397f29c0dc1aed951432ffa03e1040b9d82cc25fdc692941447688f6c
|
7
|
+
data.tar.gz: 964bcf57c3c19b94853d711b3bdfda1141a6ee113f9532d86452435372959beeb9c58ca81940c34520e03a32c4d9af2f3e5d91f4991bc027d6a8a94dd23dfce4
|
@@ -0,0 +1,100 @@
|
|
1
|
+
version: 2.0
|
2
|
+
|
3
|
+
workflows:
|
4
|
+
version: 2
|
5
|
+
build:
|
6
|
+
jobs:
|
7
|
+
- "ruby-2.5"
|
8
|
+
- "ruby-2.6"
|
9
|
+
- "ruby-2.7"
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
"ruby-2.5":
|
13
|
+
docker:
|
14
|
+
- image: ruby:2.5
|
15
|
+
- image: amazon/dynamodb-local
|
16
|
+
environment:
|
17
|
+
MAX_HEAP_SIZE: 1024m
|
18
|
+
HEAP_NEWSIZE: 512m
|
19
|
+
|
20
|
+
steps:
|
21
|
+
- checkout
|
22
|
+
- restore_cache:
|
23
|
+
keys:
|
24
|
+
- v1-dependencies-{{ checksum "Gemfile.lock" }}-{{ checksum "Appraisals" }}
|
25
|
+
# fallback to using the latest cache if no exact match is found
|
26
|
+
- v1-dependencies-
|
27
|
+
|
28
|
+
- run:
|
29
|
+
name: install dependencies
|
30
|
+
command: |
|
31
|
+
gem update bundler
|
32
|
+
bundle install
|
33
|
+
bundle exec appraisal install
|
34
|
+
- save_cache:
|
35
|
+
paths:
|
36
|
+
- ./vendor/bundle
|
37
|
+
key: v1-dependencies-{{ checksum "Gemfile.lock" }}-{{ checksum "Appraisals" }}
|
38
|
+
- run: bundle exec appraisal rspec --format progress
|
39
|
+
|
40
|
+
"ruby-2.6":
|
41
|
+
docker:
|
42
|
+
- image: ruby:2.6
|
43
|
+
- image: amazon/dynamodb-local
|
44
|
+
environment:
|
45
|
+
MAX_HEAP_SIZE: 1024m
|
46
|
+
HEAP_NEWSIZE: 512m
|
47
|
+
|
48
|
+
steps:
|
49
|
+
- checkout
|
50
|
+
- restore_cache:
|
51
|
+
keys:
|
52
|
+
- v1-dependencies-{{ checksum "Gemfile.lock" }}-{{ checksum "Appraisals" }}
|
53
|
+
# fallback to using the latest cache if no exact match is found
|
54
|
+
- v1-dependencies-
|
55
|
+
|
56
|
+
- run:
|
57
|
+
name: install dependencies
|
58
|
+
command: |
|
59
|
+
gem update bundler
|
60
|
+
bundle install
|
61
|
+
bundle exec appraisal install
|
62
|
+
- save_cache:
|
63
|
+
paths:
|
64
|
+
- ./vendor/bundle
|
65
|
+
key: v1-dependencies-{{ checksum "Gemfile.lock" }}-{{ checksum "Appraisals" }}
|
66
|
+
- run: bundle exec appraisal rspec --format progress
|
67
|
+
|
68
|
+
"ruby-2.7":
|
69
|
+
docker:
|
70
|
+
- image: ruby:2.7
|
71
|
+
- image: amazon/dynamodb-local
|
72
|
+
environment:
|
73
|
+
MAX_HEAP_SIZE: 1024m
|
74
|
+
HEAP_NEWSIZE: 512m
|
75
|
+
|
76
|
+
steps:
|
77
|
+
- checkout
|
78
|
+
- restore_cache:
|
79
|
+
keys:
|
80
|
+
- v1-dependencies-{{ checksum "Gemfile.lock" }}-{{ checksum "Appraisals" }}
|
81
|
+
# fallback to using the latest cache if no exact match is found
|
82
|
+
- v1-dependencies-
|
83
|
+
|
84
|
+
- run:
|
85
|
+
name: install dependencies
|
86
|
+
command: |
|
87
|
+
gem update bundler
|
88
|
+
bundle install
|
89
|
+
bundle exec appraisal install
|
90
|
+
- save_cache:
|
91
|
+
paths:
|
92
|
+
- ./vendor/bundle
|
93
|
+
key: v1-dependencies-{{ checksum "Gemfile.lock" }}-{{ checksum "Appraisals" }}
|
94
|
+
- run: bundle exec appraisal rspec --format progress
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- bin/*
|
4
|
+
- spec/**/*.rb
|
5
|
+
- vendor/**/*
|
6
|
+
|
7
|
+
Style/Documentation:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Style/TrailingCommaInArguments:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Metrics/LineLength:
|
14
|
+
Exclude:
|
15
|
+
- 'lib/protobufs/**/*.rb'
|
16
|
+
|
17
|
+
Metrics/BlockLength:
|
18
|
+
Exclude:
|
19
|
+
- 'spec/**/*_spec.rb'
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.3
|
data/.travis.yml
ADDED
data/Appraisals
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
dynamoid_advanced_where (1.0.0)
|
5
|
+
dynamoid (>= 3.2, < 4)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activemodel (6.0.2.1)
|
11
|
+
activesupport (= 6.0.2.1)
|
12
|
+
activesupport (6.0.2.1)
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
|
+
i18n (>= 0.7, < 2)
|
15
|
+
minitest (~> 5.1)
|
16
|
+
tzinfo (~> 1.1)
|
17
|
+
zeitwerk (~> 2.2)
|
18
|
+
appraisal (2.2.0)
|
19
|
+
bundler
|
20
|
+
rake
|
21
|
+
thor (>= 0.14.0)
|
22
|
+
ast (2.4.0)
|
23
|
+
aws-eventstream (1.0.3)
|
24
|
+
aws-partitions (1.270.0)
|
25
|
+
aws-sdk-core (3.89.1)
|
26
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
27
|
+
aws-partitions (~> 1, >= 1.239.0)
|
28
|
+
aws-sigv4 (~> 1.1)
|
29
|
+
jmespath (~> 1.0)
|
30
|
+
aws-sdk-dynamodb (1.41.0)
|
31
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
32
|
+
aws-sigv4 (~> 1.1)
|
33
|
+
aws-sigv4 (1.1.0)
|
34
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
35
|
+
bundler-audit (0.6.1)
|
36
|
+
bundler (>= 1.2.0, < 3)
|
37
|
+
thor (~> 0.18)
|
38
|
+
childprocess (3.0.0)
|
39
|
+
coderay (1.1.2)
|
40
|
+
colorize (0.8.1)
|
41
|
+
concurrent-ruby (1.1.5)
|
42
|
+
diff-lcs (1.3)
|
43
|
+
dynamoid (3.4.1)
|
44
|
+
activemodel (>= 4)
|
45
|
+
aws-sdk-dynamodb (~> 1)
|
46
|
+
concurrent-ruby (>= 1.0)
|
47
|
+
null-logger
|
48
|
+
fasterer (0.8.2)
|
49
|
+
colorize (~> 0.7)
|
50
|
+
ruby_parser (>= 3.14.1)
|
51
|
+
i18n (1.8.2)
|
52
|
+
concurrent-ruby (~> 1.0)
|
53
|
+
iniparse (1.4.4)
|
54
|
+
jaro_winkler (1.5.4)
|
55
|
+
jmespath (1.4.0)
|
56
|
+
method_source (0.9.2)
|
57
|
+
minitest (5.14.0)
|
58
|
+
null-logger (0.1.5)
|
59
|
+
overcommit (0.52.1)
|
60
|
+
childprocess (>= 0.6.3, < 4)
|
61
|
+
iniparse (~> 1.4)
|
62
|
+
parallel (1.19.1)
|
63
|
+
parser (2.7.0.2)
|
64
|
+
ast (~> 2.4.0)
|
65
|
+
pry (0.12.2)
|
66
|
+
coderay (~> 1.1.0)
|
67
|
+
method_source (~> 0.9.0)
|
68
|
+
rainbow (3.0.0)
|
69
|
+
rake (10.5.0)
|
70
|
+
rspec (3.9.0)
|
71
|
+
rspec-core (~> 3.9.0)
|
72
|
+
rspec-expectations (~> 3.9.0)
|
73
|
+
rspec-mocks (~> 3.9.0)
|
74
|
+
rspec-core (3.9.1)
|
75
|
+
rspec-support (~> 3.9.1)
|
76
|
+
rspec-expectations (3.9.0)
|
77
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
78
|
+
rspec-support (~> 3.9.0)
|
79
|
+
rspec-mocks (3.9.1)
|
80
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
81
|
+
rspec-support (~> 3.9.0)
|
82
|
+
rspec-support (3.9.2)
|
83
|
+
rubocop (0.79.0)
|
84
|
+
jaro_winkler (~> 1.5.1)
|
85
|
+
parallel (~> 1.10)
|
86
|
+
parser (>= 2.7.0.1)
|
87
|
+
rainbow (>= 2.2.2, < 4.0)
|
88
|
+
ruby-progressbar (~> 1.7)
|
89
|
+
unicode-display_width (>= 1.4.0, < 1.7)
|
90
|
+
ruby-progressbar (1.10.1)
|
91
|
+
ruby_parser (3.14.2)
|
92
|
+
sexp_processor (~> 4.9)
|
93
|
+
sexp_processor (4.14.0)
|
94
|
+
thor (0.20.3)
|
95
|
+
thread_safe (0.3.6)
|
96
|
+
tzinfo (1.2.6)
|
97
|
+
thread_safe (~> 0.1)
|
98
|
+
unicode-display_width (1.6.1)
|
99
|
+
zeitwerk (2.2.2)
|
100
|
+
|
101
|
+
PLATFORMS
|
102
|
+
ruby
|
103
|
+
x86_64-darwin-17
|
104
|
+
x86_64-darwin-18
|
105
|
+
|
106
|
+
DEPENDENCIES
|
107
|
+
appraisal
|
108
|
+
bundler (>= 1.16)
|
109
|
+
bundler-audit
|
110
|
+
dynamoid_advanced_where!
|
111
|
+
fasterer
|
112
|
+
overcommit
|
113
|
+
pry
|
114
|
+
rake (~> 10.0)
|
115
|
+
rspec (~> 3.0)
|
116
|
+
rubocop
|
117
|
+
|
118
|
+
BUNDLED WITH
|
119
|
+
2.1.4
|
data/README.md
ADDED
@@ -0,0 +1,375 @@
|
|
1
|
+
# Dynamoid Advanced Where (DAW)
|
2
|
+
|
3
|
+
Dynamoid Advanced where provides a more advanced query structure for selecting,
|
4
|
+
and updating records. This is very much a work in progress and functionality is
|
5
|
+
being added as it is needed.
|
6
|
+
|
7
|
+
This gem is tested against:
|
8
|
+
* MRI 2.5, 2.6, and 2.7
|
9
|
+
* Dynamoid 3.4
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'dynamoid_advanced_where'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
## Upgrading
|
24
|
+
From pre 1.0
|
25
|
+
|
26
|
+
New where block format:
|
27
|
+
```
|
28
|
+
# Previously you had to do this to get access to certain scoped variables
|
29
|
+
local = getValue(123)
|
30
|
+
Model.where do
|
31
|
+
field == local
|
32
|
+
end
|
33
|
+
|
34
|
+
# This is annoying, the new search block has deprecated the argument-less block, and now should be called
|
35
|
+
# with a single argument
|
36
|
+
|
37
|
+
Model.where do |r|
|
38
|
+
r.field == getValue(123)
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
Existence checks have been changed:
|
43
|
+
```ruby
|
44
|
+
# Old
|
45
|
+
Model.where{|r| r.field }
|
46
|
+
|
47
|
+
# New
|
48
|
+
Model.where{|r| r.field.exists? }
|
49
|
+
```
|
50
|
+
|
51
|
+
## Usage
|
52
|
+
|
53
|
+
The HellowWorld usage for this app is basic search and retrieval. You can
|
54
|
+
invoke DAW by calling `where` on a Dynamoid::Document (No relations yet) using
|
55
|
+
a new block form.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class Foo
|
59
|
+
include Dynamoid::Document
|
60
|
+
|
61
|
+
field :bar
|
62
|
+
field :baz
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns all records with `bar` equal to 'hello'
|
66
|
+
Foo.where{|r| r.bar == 'hello' }.all
|
67
|
+
|
68
|
+
# Advanced boolean logic is also supported
|
69
|
+
|
70
|
+
# Returns all records with `bar` equal to 'hello' and `baz` equal to 'dude'
|
71
|
+
x = Foo.where{|r| (r.baz == 'dude') & (r.bar == 'hello') }.all
|
72
|
+
```
|
73
|
+
|
74
|
+
**Note:** Those `()` are required, you do remember your [operator precedence](https://ruby-doc.org/core-2.2.0/doc/syntax/precedence_rdoc.html)
|
75
|
+
right?
|
76
|
+
|
77
|
+
## Filtering
|
78
|
+
Filter can be applied to Queries (Searches by hash key), Scans, and update
|
79
|
+
actions provided by this gem. Not all persistence actions make sense at the end
|
80
|
+
of a filtering query, such as `create`.
|
81
|
+
|
82
|
+
### Field Existence
|
83
|
+
Checks to see if a field is defined. See [attribute_exists](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)
|
84
|
+
|
85
|
+
Valid on field types: `any`
|
86
|
+
|
87
|
+
#### Example
|
88
|
+
`where{|r| r.foo }` or `where{|r| r.foo.exists! }`
|
89
|
+
|
90
|
+
### Value Equality
|
91
|
+
The equality of a field can be tested using `==` and not equals tested using `!=`
|
92
|
+
|
93
|
+
Valid on field types: `string`
|
94
|
+
|
95
|
+
#### Example
|
96
|
+
`where{|r| r.foo == 'bar' }` and `where{|r| r.foo != 'bar' }`
|
97
|
+
|
98
|
+
### Less than
|
99
|
+
The less than for a field can be tested using `<`
|
100
|
+
|
101
|
+
Valid on field types: `numeric`, and `datetime` (only when stored as a number)
|
102
|
+
|
103
|
+
#### Example
|
104
|
+
`where{|r| r.foo < 123 }` and `where{|r| r.foo < Date.today }`
|
105
|
+
|
106
|
+
### Includes
|
107
|
+
This operator may be used to check if:
|
108
|
+
|
109
|
+
* A string contains another substring
|
110
|
+
* A set of String or Integers contain a given value
|
111
|
+
|
112
|
+
Valid on field types: `string`, or `set` of `String` / `Integer`
|
113
|
+
|
114
|
+
#### Example
|
115
|
+
`where{|r| r.foo.includes?(123) }` and `where{|r| r.foo.includes?('foo') }`
|
116
|
+
|
117
|
+
### Working with Map and Raw types
|
118
|
+
When it comes to map and raw attribute types, DAW takes the approach of
|
119
|
+
trusting you, since the exact format is not explicitly defined or enforced.
|
120
|
+
You may specify the path to the value, as well as the value type and it will
|
121
|
+
behave like any other top level attribute.
|
122
|
+
|
123
|
+
```
|
124
|
+
where do |r|
|
125
|
+
(r.ratings.dig(:verified_reviews, :review_count, type: :number) > 100) &
|
126
|
+
(r.ratings.dig(:verified_reviews, :average_review, type: :number) > 4) &
|
127
|
+
(r.metadata.dig(:keywords, type: :set, of: :string).includes?('foo'))
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
If you have a nested array, you may access the elements by index by passing an integer into the `dig` command.
|
132
|
+
|
133
|
+
#### Custom Classes
|
134
|
+
The subfield dig works with CustomClasses if the classes store their data as a hash.
|
135
|
+
|
136
|
+
**Example**
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
CustomAttribute = Struct.new(:sub_field_a) do
|
140
|
+
def self.dynamoid_dump(item)
|
141
|
+
item.to_h
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.dynamoid_load(data)
|
145
|
+
new(**data.transform_keys(&:to_sym))
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class Foo
|
150
|
+
include Dynamoid::Document
|
151
|
+
field :bar, CustomAttribute
|
152
|
+
end
|
153
|
+
|
154
|
+
x = Foo.create(bar: CustomAttribute.new('b'))
|
155
|
+
Foo.where{|r| r.bar.dig(:sub_field_a, type: string).inclues?('b') }.all
|
156
|
+
# => [x]
|
157
|
+
```
|
158
|
+
|
159
|
+
### Boolean Operators
|
160
|
+
|
161
|
+
| Logical Operator | Behavior | Example
|
162
|
+
| ------------- | ------------- | --------
|
163
|
+
| `&` | and | <code>where{|r| (r.foo == 'bar') & (r.baz == 'nitch') }</code>
|
164
|
+
| <code>|</code> | or | <code> where{|r| (r.foo == 'bar') | (r.baz == 'nitch') } </code>
|
165
|
+
| `!` | negation | <code>where{|r| !( (r.foo == 'bar') & (r.baz == 'nitch')) }</code>
|
166
|
+
|
167
|
+
## Retrieving Records
|
168
|
+
Retrieving a pre-filtered set of records is a fairly obvious use case for the
|
169
|
+
filtering abilities provided by DAW. Only a subset of what you may expect is
|
170
|
+
provided, but enumerable is mixed in, and each provides an Enumerator.
|
171
|
+
|
172
|
+
Provided methods
|
173
|
+
* `all`
|
174
|
+
* `first`
|
175
|
+
* `each` (and related enumerable methods)
|
176
|
+
|
177
|
+
### Scan vs Query
|
178
|
+
DAW will automatically preform a query when it determines it is possible,
|
179
|
+
however if a query is determined to not be appropriate, a scan will be conduced
|
180
|
+
instead. When ever possible, query do not scan. See the DynamoDB docs for why.
|
181
|
+
|
182
|
+
DAW will also extract filters on the range key whenever possible. In order to
|
183
|
+
filter on a range key to be used for a query, it must be one of the allowed
|
184
|
+
range key filters and at the top level of filters.
|
185
|
+
|
186
|
+
|
187
|
+
**NOTE:** Global Secondary Indices are not yet supported
|
188
|
+
|
189
|
+
#### How a query-able filter is identified
|
190
|
+
A scan will be performed when the search is not done via the hash key, with
|
191
|
+
exact equality. DAW will examine the boolean logic to determine if a key
|
192
|
+
condition may be extracted. For example, a query will be performed in the
|
193
|
+
following examples:
|
194
|
+
|
195
|
+
* `where{|r| r.id == '123' }`
|
196
|
+
* `where{|r| (r.id == '123') & (r.bar == 'baz') }`
|
197
|
+
|
198
|
+
But it will not be performed in these scenarios
|
199
|
+
|
200
|
+
* `where{|r| r.id != '123' }`
|
201
|
+
* `where{|r| !(r.id == '123') }`
|
202
|
+
* <code>where{ (r.id == '123') | (r.bar == 'baz') }</code>
|
203
|
+
|
204
|
+
## Combination of Filters
|
205
|
+
Multiple DAW filters can be combined. This will provides the ability to compose
|
206
|
+
filtering conditions to keep your code more readable and DRY.
|
207
|
+
|
208
|
+
### Combining conditions with AND
|
209
|
+
```ruby
|
210
|
+
class Foo
|
211
|
+
include Dynamoid::Document
|
212
|
+
|
213
|
+
field :bar
|
214
|
+
field :baz
|
215
|
+
end
|
216
|
+
|
217
|
+
filter1 = Foo.where{|r| r.bar == 'abcd' }
|
218
|
+
filter2 = Foo.where{|r| r.baz == 'dude' }
|
219
|
+
|
220
|
+
# All of these produce the same results
|
221
|
+
combination1 = filter1.where(filter2)
|
222
|
+
combination2 = filter1.and(filter2)
|
223
|
+
combination3 = filter1.where{|r| r.baz == 'dude' }
|
224
|
+
```
|
225
|
+
|
226
|
+
## Mutating Records
|
227
|
+
DAW provides the ability to modify records only if they meet the criteria defined
|
228
|
+
by the where block.
|
229
|
+
|
230
|
+
Changes are also provided in batch form, so you may change multiple values with a single call.
|
231
|
+
There may also be singleton methods provided for easy of use.
|
232
|
+
|
233
|
+
## Batch Updates
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
Model.where{ conditions }.batch_update
|
237
|
+
.set_values(field_name1: 'value', field_name2: 123)
|
238
|
+
.append_to(arr_field_name: [1,2,3], set_field_name: %w[a b c])
|
239
|
+
.apply(hash_key, range_key)
|
240
|
+
```
|
241
|
+
|
242
|
+
Like all conditional updates it will return the full record with the new data
|
243
|
+
if it successfully updates. If it fails to update, it will return nil.
|
244
|
+
|
245
|
+
If the specified hash key, or hash/range key combination is not already present
|
246
|
+
it will be inserted with the desired mutations (if possible).
|
247
|
+
|
248
|
+
### Setting a single field
|
249
|
+
The batch updated method `set_values(attr_name: new_attr_value, other_atter: val)`
|
250
|
+
|
251
|
+
#### Shortcut Method
|
252
|
+
You map perform an upsert using the `.upsert` method. This method performs a
|
253
|
+
simple set on the provided hash and range key.
|
254
|
+
|
255
|
+
For example, consider the following example for conditionally updating a string
|
256
|
+
field.
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
class Foo
|
260
|
+
include Dynamoid::Document
|
261
|
+
field :a_string
|
262
|
+
field :a_number, number
|
263
|
+
end
|
264
|
+
|
265
|
+
item = Foo.create(a_number: 5, a_string: 'bar')
|
266
|
+
|
267
|
+
Foo.where{|r| r.a_number > 5 }.upsert(item.id, a_string: 'dude')
|
268
|
+
|
269
|
+
item.reload.a_string # => 'bar'
|
270
|
+
|
271
|
+
Foo.where{|r| r.a_number > 4 }.upsert(item.id, a_string: 'wassup')
|
272
|
+
|
273
|
+
item.reload.a_string # => 'wassup'
|
274
|
+
```
|
275
|
+
|
276
|
+
`upsert` can also create a record if an existing one is not found, if the hash
|
277
|
+
key can be specified. By requiring the hash key be set, you can prevent an insert
|
278
|
+
and force an update to occur.
|
279
|
+
|
280
|
+
**Note:** Upsert must be called with the hash as the first parameter, and
|
281
|
+
the range key as the second parameter if required for the model.
|
282
|
+
|
283
|
+
*Note:** Upsert will return nil if no records were found that matched the provided
|
284
|
+
parameters
|
285
|
+
|
286
|
+
### Appending values to a List or Set
|
287
|
+
You can append a set of values to an existing set or array by using the
|
288
|
+
|
289
|
+
```ruby
|
290
|
+
append_to(
|
291
|
+
array_field: [1,2,3],
|
292
|
+
set_field: %w[foo bar],
|
293
|
+
)
|
294
|
+
```
|
295
|
+
|
296
|
+
If the fields are unset, it will still apply the changes to am empty array.
|
297
|
+
|
298
|
+
### Increment / Decrement a value
|
299
|
+
|
300
|
+
You may increment or decrement a numeric value by using `increment` or `decrement`
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
increment(:field_one, :field_two)
|
304
|
+
```
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
decrement(:field_one, :field_two)
|
308
|
+
```
|
309
|
+
|
310
|
+
You may also provide an optional `by:` config to increment by more than one.
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
increment(:field_one, :field_two, by: 3)
|
314
|
+
```
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
decrement(:field_one, :field_two, by: 3)
|
318
|
+
```
|
319
|
+
|
320
|
+
If the value of the field is currently unset, it will initialize to zero
|
321
|
+
|
322
|
+
## Development
|
323
|
+
|
324
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
325
|
+
|
326
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
327
|
+
|
328
|
+
### TODO:
|
329
|
+
|
330
|
+
#### Known issues
|
331
|
+
* If you specify multiple term nodes for a query it will generate an invalid
|
332
|
+
query
|
333
|
+
* No support for [custom types](https://github.com/Dynamoid/Dynamoid#custom-types)
|
334
|
+
|
335
|
+
#### Enhancements
|
336
|
+
* Support Global Secondary Index
|
337
|
+
* Conditions:
|
338
|
+
* Equality
|
339
|
+
* Partially implemented
|
340
|
+
* Not Equals
|
341
|
+
* less than
|
342
|
+
* Implemented for numerics, datetimes, dates stored as integer
|
343
|
+
* less than or equal to
|
344
|
+
* greater than
|
345
|
+
* greater than or equal to
|
346
|
+
* between
|
347
|
+
* in
|
348
|
+
* attribute_not_exists
|
349
|
+
* attribute_type
|
350
|
+
* begins with
|
351
|
+
* contains
|
352
|
+
* size
|
353
|
+
* Query enhancements
|
354
|
+
* Range key conditions:
|
355
|
+
* equality
|
356
|
+
* less than
|
357
|
+
* less than or equal to
|
358
|
+
* greater than
|
359
|
+
* greater than or equal to
|
360
|
+
* between
|
361
|
+
* begins with
|
362
|
+
* convert to bulk query if multiple hash key terms are specified
|
363
|
+
* Item mutation [Docs](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET)
|
364
|
+
* Update (without insert)
|
365
|
+
* Upserting
|
366
|
+
* Increment / Decrement number
|
367
|
+
* Append item(s) to list
|
368
|
+
* Prepend item(s) to list
|
369
|
+
* Adding nested map attribute (low priority)
|
370
|
+
* Set value if not set
|
371
|
+
* Remove attributes
|
372
|
+
|
373
|
+
## Contributing
|
374
|
+
|
375
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/dynamoid-advanced-where.
|