aws-record 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: ded98837103b96b4599121d600cc139054de43637168121bae6a35302ba24ac8
4
- data.tar.gz: 14c7d413a0b108fffd9c118aa05234b7e6d33852121e8b6828e88db6cadd45d7
2
+ SHA1:
3
+ metadata.gz: c0d7d527489fd1a7848279570aefbe37aeee9297
4
+ data.tar.gz: f3234598e3f895c93184a7b283a7064853ad3707
5
5
  SHA512:
6
- metadata.gz: 722b31cd37b441f33cc9993596b7fb92dc360bc280a00d9da9f03419a792669419bd9fa58006e59f09a027bde88444d795951902e3181aa697644a89baf09b17
7
- data.tar.gz: bd7399265054c4483039e432fb4804713428151b3cef0f8e661132e9cf30d0c6876ed5611b09fcd6063c50b0f1baa31976cbfede27aba042457a9df3ac6cdffa
6
+ metadata.gz: afd2c0b89fac562aeaee2fb0f67f25cee31700b29639e52a8281babd769a45b8da8bf2cedf86d396904e1103b4f9e2722445a13bada7cab446c443b460b8e42b
7
+ data.tar.gz: f0dfc0620149bbf63d2b5334dc441f2370e220278a3893f5b84b1e68a6a74acfcfec9f36e67cb4d31696add5e4795a567a4444d4b05f685dcbfbe8dbfbe0df98
@@ -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
@@ -13,6 +13,6 @@
13
13
 
14
14
  module Aws
15
15
  module Record
16
- VERSION = '2.3.0'
16
+ VERSION = '2.4.0'
17
17
  end
18
18
  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.3.0
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-02-08 00:00:00.000000000 Z
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.7.6
84
+ rubygems_version: 2.5.2
84
85
  signing_key:
85
86
  specification_version: 4
86
87
  summary: AWS Record library for Amazon DynamoDB