Class: Lotus::Model::Adapters::Dynamodb::Query
- Inherits:
-
Object
- Object
- Lotus::Model::Adapters::Dynamodb::Query
- Extended by:
- Forwardable
- Includes:
- Enumerable
- Defined in:
- lib/lotus/model/adapters/dynamodb/query.rb
Overview
Query DynamoDB table with a powerful API.
All the methods are chainable, it allows advanced composition of options.
This works as a lazy filtering mechanism: the records are fetched from the DynamoDB only when needed.
It implements Ruby’s ‘Enumerable` and borrows some methods from `Array`. Expect a query to act like them.
Instance Attribute Summary collapse
- #operation ⇒ Object readonly private
- #options ⇒ Object readonly private
Instance Method Summary collapse
-
#all ⇒ Array
Resolves the query by fetching records from the database and translating them into entities.
-
#average(column) ⇒ Object
(also: #avg)
This method is not implemented.
-
#begins_with(condition) ⇒ Object
Perform BEGINS_WITH comparison.
-
#comparison(condition, operator) ⇒ Object
private
Perform comparison operation.
-
#consistent ⇒ Object
Tells DynamoDB to use consistent reads.
-
#contains(condition) ⇒ Object
Perform CONTAINS comparison.
-
#count ⇒ Fixnum
Returns a count of the records for the current conditions.
-
#desc(*columns) ⇒ Object
Specify the descending order of the records, sorted by the range key.
-
#each ⇒ Integer
Iterates over fetched records.
-
#exclude(condition) ⇒ Object
(also: #not, #ne)
Logical negation of a #where condition.
-
#exists? ⇒ TrueClass, FalseClass
(also: #exist?)
Checks if at least one record exists for the current conditions.
-
#ge(condition) ⇒ Object
Perform GE comparison.
-
#gt(condition) ⇒ Object
Perform GT comparison.
-
#index(name) ⇒ Object
Tells DynamoDB which index to use.
-
#initialize(dataset, collection, &blk) ⇒ Query
constructor
private
Initialize a query.
-
#interval(column) ⇒ Object
This method is not implemented.
-
#key_for_condition(condition) ⇒ Symbol
private
private
Return proper options key for a given condition.
-
#le(condition) ⇒ Object
Perform LE comparison.
-
#limit(number) ⇒ Object
Limit the number of records to return.
-
#lt(condition) ⇒ Object
Perform LT comparison.
-
#max(column) ⇒ Object
This method is not implemented.
-
#min(column) ⇒ Object
This method is not implemented.
-
#negate! ⇒ Object
This method is not implemented.
-
#not_contains(condition) ⇒ Object
Perform NOT_CONTAINS comparison.
-
#not_null(column) ⇒ Object
Perform NOT_NULL comparison.
-
#null(column) ⇒ Object
Perform NULL comparison.
-
#offset(number) ⇒ Object
This method is not implemented.
-
#or ⇒ Object
Sets DynamoDB ConditionalOperator to ‘OR`.
-
#order(*columns) ⇒ Object
(also: #asc)
Specify the ascending order of the records, sorted by the range key.
-
#query ⇒ Object
Set operation to be query instead of scan.
-
#range(column) ⇒ Object
This method is not implemented.
-
#run(previous_response = nil) ⇒ Array
private
private
Apply all the options and return a filtered collection.
-
#select(*columns) ⇒ Object
Select only the specified columns.
-
#serialize_condition(condition, operator: nil, negate: false) ⇒ Hash
private
private
Serialize given condition for DynamoDB API.
-
#sum(column) ⇒ Object
This method is not implemented.
-
#where(condition) ⇒ Object
(also: #eq, #in, #between)
Adds a condition that behaves like SQL ‘WHERE`.
Constructor Details
#initialize(dataset, collection, &blk) ⇒ Query
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Initialize a query
67 68 69 70 71 72 73 74 75 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 67 def initialize(dataset, collection, &blk) @dataset = dataset @collection = collection @operation = :scan @options = {} instance_eval(&blk) if block_given? end |
Instance Attribute Details
#operation ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
50 51 52 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 50 def operation @operation end |
#options ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
56 57 58 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 56 def @options end |
Instance Method Details
#all ⇒ Array
Resolves the query by fetching records from the database and translating them into entities.
83 84 85 86 87 88 89 90 91 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 83 def all response = run while !@options[:limit] && response.last_evaluated_key @options[:exclusive_start_key] = response.last_evaluated_key response = run(response) end @collection.deserialize(response.entities) end |
#average(column) ⇒ Object Also known as: avg
This method is not implemented. DynamoDB does not provide average.
397 398 399 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 397 def average(column) raise NotImplementedError end |
#begins_with(condition) ⇒ Object
Perform BEGINS_WITH comparison.
263 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 263 def begins_with(condition); comparison(condition, 'BEGINS_WITH'); end |
#comparison(condition, operator) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Perform comparison operation.
285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 285 def comparison(condition, operator) key = key_for_condition(condition) serialized = serialize_condition(condition, operator: operator) if serialized @options[key] ||= {} @options[key].merge!(serialized) end self end |
#consistent ⇒ Object
Tells DynamoDB to use consistent reads.
499 500 501 502 503 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 499 def consistent query @options[:consistent_read] = true self end |
#contains(condition) ⇒ Object
Perform CONTAINS comparison.
249 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 249 def contains(condition); comparison(condition, 'CONTAINS'); end |
#count ⇒ Fixnum
Returns a count of the records for the current conditions.
471 472 473 474 475 476 477 478 479 480 481 482 483 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 471 def count @options[:select] = "COUNT" @options.delete(:attributes_to_get) response = run while !@options[:limit] && response.last_evaluated_key @options[:exclusive_start_key] = response.last_evaluated_key response = run(response) end response.count end |
#desc(*columns) ⇒ Object
Specify the descending order of the records, sorted by the range key.
344 345 346 347 348 349 350 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 344 def desc(*columns) warn "DynamoDB only supports order by range_key" if columns.any? query @options[:scan_index_forward] = false self end |
#each ⇒ Integer
Iterates over fetched records.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 98 def each response = run entities = @collection.deserialize(response.entities) entities.each { |x| yield(x) } while !@options[:limit] && response.last_evaluated_key response.entities = [] @options[:exclusive_start_key] = response.last_evaluated_key response = run(response) entities = @collection.deserialize(response.entities) entities.each { |x| yield(x) } end response.count end |
#exclude(condition) ⇒ Object Also known as: not, ne
Logical negation of a #where condition.
It accepts a ‘Hash` with only one pair. The key must be the name of the column expressed as a `Symbol`. The value is the one used by the internal filtering logic.
201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 201 def exclude(condition) key = key_for_condition(condition) serialized = serialize_condition(condition, negate: true) if serialized @options[key] ||= {} @options[key].merge!(serialized) end self end |
#exists? ⇒ TrueClass, FalseClass Also known as: exist?
Checks if at least one record exists for the current conditions.
456 457 458 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 456 def exists? !count.zero? end |
#ge(condition) ⇒ Object
Perform GE comparison.
235 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 235 def ge(condition); comparison(condition, 'GE'); end |
#gt(condition) ⇒ Object
Perform GT comparison.
242 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 242 def gt(condition); comparison(condition, 'GT'); end |
#index(name) ⇒ Object
Tells DynamoDB which index to use.
510 511 512 513 514 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 510 def index(name) query @options[:index_name] = name.to_s self end |
#interval(column) ⇒ Object
This method is not implemented. DynamoDB does not provide interval.
432 433 434 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 432 def interval(column) raise NotImplementedError end |
#key_for_condition(condition) ⇒ Symbol (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Return proper options key for a given condition.
525 526 527 528 529 530 531 532 533 534 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 525 def key_for_condition(condition) if @dataset.key?(condition.keys.first, @options[:index_name]) query :key_conditions elsif operation == :scan :scan_filter else :query_filter end end |
#le(condition) ⇒ Object
Perform LE comparison.
221 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 221 def le(condition); comparison(condition, 'LE'); end |
#limit(number) ⇒ Object
Limit the number of records to return.
363 364 365 366 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 363 def limit(number) @options[:limit] = number self end |
#lt(condition) ⇒ Object
Perform LT comparison.
228 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 228 def lt(condition); comparison(condition, 'LT'); end |
#max(column) ⇒ Object
This method is not implemented. DynamoDB does not provide max.
410 411 412 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 410 def max(column) raise NotImplementedError end |
#min(column) ⇒ Object
This method is not implemented. DynamoDB does not provide min.
421 422 423 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 421 def min(column) raise NotImplementedError end |
#negate! ⇒ Object
This method is not implemented.
490 491 492 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 490 def negate! raise NotImplementedError end |
#not_contains(condition) ⇒ Object
Perform NOT_CONTAINS comparison.
256 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 256 def not_contains(condition); comparison(condition, 'NOT_CONTAINS'); end |
#not_null(column) ⇒ Object
Perform NOT_NULL comparison.
277 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 277 def not_null(column); comparison({ column => '' }, 'NOT_NULL'); end |
#null(column) ⇒ Object
Perform NULL comparison.
270 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 270 def null(column); comparison({ column => '' }, 'NULL'); end |
#offset(number) ⇒ Object
This method is not implemented. DynamoDB does not provide offset.
375 376 377 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 375 def offset(number) raise NotImplementedError end |
#or ⇒ Object
Sets DynamoDB ConditionalOperator to ‘OR`. This works query-wide so this method has no arguments.
176 177 178 179 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 176 def or @options[:conditional_operator] = "OR" self end |
#order(*columns) ⇒ Object Also known as: asc
Specify the ascending order of the records, sorted by the range key.
327 328 329 330 331 332 333 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 327 def order(*columns) warn "DynamoDB only supports order by range_key" if columns.any? query @options[:scan_index_forward] = true self end |
#query ⇒ Object
Set operation to be query instead of scan.
121 122 123 124 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 121 def query @operation = :query self end |
#range(column) ⇒ Object
This method is not implemented. DynamoDB does not provide range.
443 444 445 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 443 def range(column) raise NotImplementedError end |
#run(previous_response = nil) ⇒ Array (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Apply all the options and return a filtered collection.
590 591 592 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 590 def run(previous_response = nil) @dataset.public_send(operation, @options, previous_response) end |
#select(*columns) ⇒ Object
Select only the specified columns.
By default a query selects all the mapped columns.
314 315 316 317 318 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 314 def select(*columns) @options[:select] = "SPECIFIC_ATTRIBUTES" @options[:attributes_to_get] = columns.map(&:to_s) self end |
#serialize_condition(condition, operator: nil, negate: false) ⇒ Hash (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Serialize given condition for DynamoDB API.
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 545 def serialize_condition(condition, operator: nil, negate: false) column, value = condition.keys.first, condition.values.first operator ||= case when value.is_a?(Array) negate ? nil : "IN" when value.is_a?(Range) negate ? nil : "BETWEEN" else negate ? "NE" : "EQ" end # Operator is not supported raise NotImplementedError unless operator values ||= case when value.is_a?(Range) [value.first, value.last] else [value].flatten end serialized = { column.to_s => { comparison_operator: operator, }, } if !["NULL", "NOT_NULL"].include?(operator) serialized[column.to_s][:attribute_value_list] = values.map do |v| @dataset.format_attribute(column, v) end end serialized end |
#sum(column) ⇒ Object
This method is not implemented. DynamoDB does not provide sum.
386 387 388 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 386 def sum(column) raise NotImplementedError end |
#where(condition) ⇒ Object Also known as: eq, in, between
Adds a condition that behaves like SQL ‘WHERE`.
It accepts a ‘Hash` with only one pair. The key must be the name of the column expressed as a `Symbol`. The value is the one used by the internal filtering logic.
154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/lotus/model/adapters/dynamodb/query.rb', line 154 def where(condition) key = key_for_condition(condition) serialized = serialize_condition(condition) if serialized @options[key] ||= {} @options[key].merge!(serialized) end self end |