aws-record 2.3.0 → 2.4.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 +5 -5
- data/lib/aws-record.rb +1 -0
- data/lib/aws-record/record/buildable_search.rb +232 -0
- data/lib/aws-record/record/query.rb +48 -0
- data/lib/aws-record/record/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c0d7d527489fd1a7848279570aefbe37aeee9297
|
4
|
+
data.tar.gz: f3234598e3f895c93184a7b283a7064853ad3707
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afd2c0b89fac562aeaee2fb0f67f25cee31700b29639e52a8281babd769a45b8da8bf2cedf86d396904e1103b4f9e2722445a13bada7cab446c443b460b8e42b
|
7
|
+
data.tar.gz: f0dfc0620149bbf63d2b5334dc441f2370e220278a3893f5b84b1e68a6a74acfcfec9f36e67cb4d31696add5e4795a567a4444d4b05f685dcbfbe8dbfbe0df98
|
data/lib/aws-record.rb
CHANGED
@@ -28,6 +28,7 @@ require_relative 'aws-record/record/table_config'
|
|
28
28
|
require_relative 'aws-record/record/table_migration'
|
29
29
|
require_relative 'aws-record/record/version'
|
30
30
|
require_relative 'aws-record/record/transactions'
|
31
|
+
require_relative 'aws-record/record/buildable_search'
|
31
32
|
require_relative 'aws-record/record/marshalers/string_marshaler'
|
32
33
|
require_relative 'aws-record/record/marshalers/boolean_marshaler'
|
33
34
|
require_relative 'aws-record/record/marshalers/integer_marshaler'
|
@@ -0,0 +1,232 @@
|
|
1
|
+
module Aws
|
2
|
+
module Record
|
3
|
+
class BuildableSearch
|
4
|
+
SUPPORTED_OPERATIONS = [:query, :scan]
|
5
|
+
|
6
|
+
# This should never be called directly, rather it is called by the
|
7
|
+
# #build_query or #build_scan methods of your aws-record model class.
|
8
|
+
def initialize(opts)
|
9
|
+
operation = opts[:operation]
|
10
|
+
model = opts[:model]
|
11
|
+
if SUPPORTED_OPERATIONS.include?(operation)
|
12
|
+
@operation = operation
|
13
|
+
else
|
14
|
+
raise ArgumentError.new("Unsupported operation: #{operation}")
|
15
|
+
end
|
16
|
+
@model = model
|
17
|
+
@params = {}
|
18
|
+
@next_name = "BUILDERA"
|
19
|
+
@next_value = "buildera"
|
20
|
+
end
|
21
|
+
|
22
|
+
# If you are querying or scanning on an index, you can specify it with
|
23
|
+
# this builder method. Provide the symbol of your index as defined on your
|
24
|
+
# model class.
|
25
|
+
def on_index(index)
|
26
|
+
@params[:index_name] = index
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# If true, will perform your query or scan as a consistent read. If false,
|
31
|
+
# the query or scan is eventually consistent.
|
32
|
+
def consistent_read(b)
|
33
|
+
@params[:consistent_read] = b
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
# For the scan operation, you can split your scan into multiple segments
|
38
|
+
# to be scanned in parallel. If you wish to do this, you can use this
|
39
|
+
# builder method to provide the :total_segments of your parallel scan and
|
40
|
+
# the :segment number of this scan.
|
41
|
+
def parallel_scan(opts)
|
42
|
+
unless @operation == :scan
|
43
|
+
raise ArgumentError.new("parallel_scan is only supported for scans")
|
44
|
+
end
|
45
|
+
unless opts[:total_segments] && opts[:segment]
|
46
|
+
raise ArgumentError.new("Must specify :total_segments and :segment in a parallel scan.")
|
47
|
+
end
|
48
|
+
@params[:total_segments] = opts[:total_segments]
|
49
|
+
@params[:segment] = opts[:segment]
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# For a query operation, you can use this to set if you query is in
|
54
|
+
# ascending or descending order on your range key. By default, a query is
|
55
|
+
# run in ascending order.
|
56
|
+
def scan_ascending(b)
|
57
|
+
unless @operation == :query
|
58
|
+
raise ArgumentError.new("scan_ascending is only supported for queries.")
|
59
|
+
end
|
60
|
+
@params[:scan_index_forward] = b
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
# If you have an exclusive start key for your query or scan, you can
|
65
|
+
# provide it with this builder method. You should not use this if you are
|
66
|
+
# querying or scanning without a set starting point, as the
|
67
|
+
# {Aws::Record::ItemCollection} class handles pagination automatically
|
68
|
+
# for you.
|
69
|
+
def exclusive_start_key(key)
|
70
|
+
@params[:exclusive_start_key] = key
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
# Provide a key condition expression for your query using a substitution
|
75
|
+
# expression.
|
76
|
+
#
|
77
|
+
# @example Building a simple query with a key expression:
|
78
|
+
# # Example model class
|
79
|
+
# class ExampleTable
|
80
|
+
# include Aws::Record
|
81
|
+
# string_attr :uuid, hash_key: true
|
82
|
+
# integer_attr :id, range_key: true
|
83
|
+
# string_attr :body
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# q = ExampleTable.build_query.key_expr(
|
87
|
+
# ":uuid = ? AND :id > ?", "smpl-uuid", 100
|
88
|
+
# ).complete!
|
89
|
+
# q.to_a # You can use this like any other query result in aws-record
|
90
|
+
def key_expr(statement_str, *subs)
|
91
|
+
unless @operation == :query
|
92
|
+
raise ArgumentError.new("key_expr is only supported for queries.")
|
93
|
+
end
|
94
|
+
names = @params[:expression_attribute_names]
|
95
|
+
if names.nil?
|
96
|
+
@params[:expression_attribute_names] = {}
|
97
|
+
names = @params[:expression_attribute_names]
|
98
|
+
end
|
99
|
+
values = @params[:expression_attribute_values]
|
100
|
+
if values.nil?
|
101
|
+
@params[:expression_attribute_values] = {}
|
102
|
+
values = @params[:expression_attribute_values]
|
103
|
+
end
|
104
|
+
_key_pass(statement_str, names)
|
105
|
+
_apply_values(statement_str, subs, values)
|
106
|
+
@params[:key_condition_expression] = statement_str
|
107
|
+
self
|
108
|
+
end
|
109
|
+
|
110
|
+
# Provide a filter expression for your query or scan using a substitution
|
111
|
+
# expression.
|
112
|
+
#
|
113
|
+
# @example Building a simple scan:
|
114
|
+
# # Example model class
|
115
|
+
# class ExampleTable
|
116
|
+
# include Aws::Record
|
117
|
+
# string_attr :uuid, hash_key: true
|
118
|
+
# integer_attr :id, range_key: true
|
119
|
+
# string_attr :body
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# scan = ExampleTable.build_scan.filter_expr(
|
123
|
+
# "contains(:body, ?)",
|
124
|
+
# "bacon"
|
125
|
+
# ).complete!
|
126
|
+
#
|
127
|
+
def filter_expr(statement_str, *subs)
|
128
|
+
names = @params[:expression_attribute_names]
|
129
|
+
if names.nil?
|
130
|
+
@params[:expression_attribute_names] = {}
|
131
|
+
names = @params[:expression_attribute_names]
|
132
|
+
end
|
133
|
+
values = @params[:expression_attribute_values]
|
134
|
+
if values.nil?
|
135
|
+
@params[:expression_attribute_values] = {}
|
136
|
+
values = @params[:expression_attribute_values]
|
137
|
+
end
|
138
|
+
_key_pass(statement_str, names)
|
139
|
+
_apply_values(statement_str, subs, values)
|
140
|
+
@params[:filter_expression] = statement_str
|
141
|
+
self
|
142
|
+
end
|
143
|
+
|
144
|
+
# Allows you to define a projection expression for the values returned by
|
145
|
+
# a query or scan. See
|
146
|
+
# {https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html the Amazon DynamoDB Developer Guide}
|
147
|
+
# for more details on projection expressions. You can use the symbols from
|
148
|
+
# your aws-record model class in a projection expression. Keys are always
|
149
|
+
# retrieved.
|
150
|
+
#
|
151
|
+
# @example Scan with a projection expression:
|
152
|
+
# # Example model class
|
153
|
+
# class ExampleTable
|
154
|
+
# include Aws::Record
|
155
|
+
# string_attr :uuid, hash_key: true
|
156
|
+
# integer_attr :id, range_key: true
|
157
|
+
# string_attr :body
|
158
|
+
# map_attr :metadata
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
# scan = ExampleTable.build_scan.projection_expr(
|
162
|
+
# ":body"
|
163
|
+
# ).complete!
|
164
|
+
def projection_expr(statement_str)
|
165
|
+
names = @params[:expression_attribute_names]
|
166
|
+
if names.nil?
|
167
|
+
@params[:expression_attribute_names] = {}
|
168
|
+
names = @params[:expression_attribute_names]
|
169
|
+
end
|
170
|
+
_key_pass(statement_str, names)
|
171
|
+
@params[:projection_expression] = statement_str
|
172
|
+
self
|
173
|
+
end
|
174
|
+
|
175
|
+
# Allows you to set a page size limit on each query or scan request.
|
176
|
+
def limit(size)
|
177
|
+
@params[:limit] = size
|
178
|
+
self
|
179
|
+
end
|
180
|
+
|
181
|
+
# You must call this method at the end of any query or scan you build.
|
182
|
+
#
|
183
|
+
# @return [Aws::Record::ItemCollection] The item collection lazy
|
184
|
+
# enumerable.
|
185
|
+
def complete!
|
186
|
+
@model.send(@operation, @params)
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
def _key_pass(statement, names)
|
191
|
+
statement.gsub!(/:(\w+)/) do |match|
|
192
|
+
key = match.gsub!(':','').to_sym
|
193
|
+
key_name = @model.attributes.storage_name_for(key)
|
194
|
+
if key_name
|
195
|
+
sub_name = _next_name
|
196
|
+
raise "Substitution collision!" if names[sub_name]
|
197
|
+
names[sub_name] = key_name
|
198
|
+
sub_name
|
199
|
+
else
|
200
|
+
raise "No such key #{key}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def _apply_values(statement, subs, values)
|
206
|
+
count = 0
|
207
|
+
statement.gsub!(/[?]/) do |match|
|
208
|
+
sub_value = _next_value
|
209
|
+
raise "Substitution collision!" if values[sub_value]
|
210
|
+
values[sub_value] = subs[count]
|
211
|
+
count += 1
|
212
|
+
sub_value
|
213
|
+
end
|
214
|
+
unless count == subs.size
|
215
|
+
raise "Expected #{count} values in the substitution set, but found #{subs.size}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def _next_name
|
220
|
+
ret = "#" + @next_name
|
221
|
+
@next_name.next!
|
222
|
+
ret
|
223
|
+
end
|
224
|
+
|
225
|
+
def _next_value
|
226
|
+
ret = ":" + @next_value
|
227
|
+
@next_value.next!
|
228
|
+
ret
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -102,6 +102,54 @@ module Aws
|
|
102
102
|
scan_opts = opts.merge(table_name: table_name)
|
103
103
|
ItemCollection.new(:scan, scan_opts, self, dynamodb_client)
|
104
104
|
end
|
105
|
+
|
106
|
+
# This method allows you to build a query using the {Aws::Record::BuildableSearch} DSL.
|
107
|
+
#
|
108
|
+
# @example Building a simple query:
|
109
|
+
# # Example model class
|
110
|
+
# class ExampleTable
|
111
|
+
# include Aws::Record
|
112
|
+
# string_attr :uuid, hash_key: true
|
113
|
+
# integer_attr :id, range_key: true
|
114
|
+
# string_attr :body
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# q = ExampleTable.build_query.key_expr(
|
118
|
+
# ":uuid = ? AND :id > ?", "smpl-uuid", 100
|
119
|
+
# ).scan_ascending(false).complete!
|
120
|
+
# q.to_a # You can use this like any other query result in aws-record
|
121
|
+
def build_query
|
122
|
+
BuildableSearch.new(
|
123
|
+
operation: :query,
|
124
|
+
model: self
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
# This method allows you to build a scan using the {Aws::Record::BuildableSearch} DSL.
|
129
|
+
#
|
130
|
+
# @example Building a simple scan:
|
131
|
+
# # Example model class
|
132
|
+
# class ExampleTable
|
133
|
+
# include Aws::Record
|
134
|
+
# string_attr :uuid, hash_key: true
|
135
|
+
# integer_attr :id, range_key: true
|
136
|
+
# string_attr :body
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
# segment_2_scan = ExampleTable.build_scan.filter_expr(
|
140
|
+
# "contains(:body, ?)",
|
141
|
+
# "bacon"
|
142
|
+
# ).scan_ascending(false).parallel_scan(
|
143
|
+
# total_segments: 5,
|
144
|
+
# segment: 2
|
145
|
+
# ).complete!
|
146
|
+
# segment_2_scan.to_a # You can use this like any other query result in aws-record
|
147
|
+
def build_scan
|
148
|
+
BuildableSearch.new(
|
149
|
+
operation: :scan,
|
150
|
+
model: self
|
151
|
+
)
|
152
|
+
end
|
105
153
|
end
|
106
154
|
|
107
155
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amazon Web Services
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-dynamodb
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- lib/aws-record/record.rb
|
36
36
|
- lib/aws-record/record/attribute.rb
|
37
37
|
- lib/aws-record/record/attributes.rb
|
38
|
+
- lib/aws-record/record/buildable_search.rb
|
38
39
|
- lib/aws-record/record/dirty_tracking.rb
|
39
40
|
- lib/aws-record/record/errors.rb
|
40
41
|
- lib/aws-record/record/item_collection.rb
|
@@ -80,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
81
|
version: '0'
|
81
82
|
requirements: []
|
82
83
|
rubyforge_project:
|
83
|
-
rubygems_version: 2.
|
84
|
+
rubygems_version: 2.5.2
|
84
85
|
signing_key:
|
85
86
|
specification_version: 4
|
86
87
|
summary: AWS Record library for Amazon DynamoDB
|