107 lines
3.1 KiB
Ruby
107 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
#
|
|
# Copyright (C) 2019 - present Instructure, Inc.
|
|
#
|
|
# This file is part of Canvas.
|
|
#
|
|
# Canvas is free software: you can redistribute it and/or modify it under
|
|
# the terms of the GNU Affero General Public License as published by the Free
|
|
# Software Foundation, version 3 of the License.
|
|
#
|
|
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License along
|
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
##
|
|
# = Paginated Dynamo Queries
|
|
#
|
|
# Returning an instance of +DynamoQuery+ in a GraphQL resolver allows
|
|
# pagination to work for dynamo queries.
|
|
#
|
|
# NOTE: The current "Connection" implementation is awful. There is no way to
|
|
# disable the backwards pagination arguments (last/before). There is some
|
|
# ongoing work on Connections
|
|
# (https://github.com/rmosolgo/graphql-ruby/issues/1359).
|
|
#
|
|
# Since Dynamo only supports paging in one direction, we shouldn't include
|
|
# "after"/"last" arguments on these connections, but avoiding that in the
|
|
# current codebase is difficult. Passing "after"/"last" will essentially be a
|
|
# no-op on dynamo connections.
|
|
class DynamoQuery
|
|
attr_reader :partition_key, :sort_key
|
|
|
|
def initialize(db,
|
|
table,
|
|
partition_key:,
|
|
key_condition_expression:,
|
|
expression_attribute_values:,
|
|
value:,
|
|
sort_key:,
|
|
scan_index_forward: true)
|
|
@db = db
|
|
@table = table
|
|
@partition_key = partition_key
|
|
@partition_value = value
|
|
@sort_key = sort_key
|
|
@scan_index_forward = scan_index_forward
|
|
@key_condition_expression = +"#{partition_key} = :id"
|
|
@key_condition_expression << " AND #{key_condition_expression}" if key_condition_expression
|
|
@expression_attribute_values = expression_attribute_values.merge(":id" => value)
|
|
end
|
|
|
|
def limit(limit)
|
|
@limit = limit
|
|
self
|
|
end
|
|
|
|
def after(sort_cursor)
|
|
@exclusive_start_key = if sort_cursor
|
|
{
|
|
@partition_key => @partition_value,
|
|
@sort_key => sort_cursor,
|
|
}
|
|
else
|
|
nil
|
|
end
|
|
self
|
|
end
|
|
|
|
def each(&)
|
|
query.items.each(&)
|
|
end
|
|
|
|
def map
|
|
res = []
|
|
each { |item| res << yield(item) }
|
|
res
|
|
end
|
|
|
|
def first
|
|
query.items.first
|
|
end
|
|
|
|
def last
|
|
query.items.last
|
|
end
|
|
|
|
def query
|
|
return @query if defined? @query
|
|
|
|
params = {
|
|
table_name: @table,
|
|
key_condition_expression: @key_condition_expression,
|
|
expression_attribute_values: @expression_attribute_values,
|
|
scan_index_forward: @scan_index_forward,
|
|
}
|
|
params[:limit] = @limit if @limit
|
|
params[:exclusive_start_key] = @exclusive_start_key if @exclusive_start_key
|
|
@query = @db.query(params)
|
|
end
|
|
end
|