76 lines
1.6 KiB
Ruby
76 lines
1.6 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
module AceOfBase
|
||
|
# A query builder for querying our data.
|
||
|
class Query
|
||
|
INVALID_FIELD_MESSAGE = 'Field %s is not a valid field name'
|
||
|
|
||
|
def initialize(storage)
|
||
|
@fields = []
|
||
|
@order_bys = []
|
||
|
@filters = []
|
||
|
@storage = storage
|
||
|
end
|
||
|
|
||
|
def select(*fields)
|
||
|
ensure_valid_fields!(fields)
|
||
|
@fields = fields
|
||
|
|
||
|
self
|
||
|
end
|
||
|
|
||
|
def order_by(*fields)
|
||
|
ensure_valid_fields!(fields)
|
||
|
@order_bys = fields
|
||
|
self
|
||
|
end
|
||
|
|
||
|
def filter(field, value)
|
||
|
ensure_valid_fields!([field])
|
||
|
@filters << [field, value]
|
||
|
self
|
||
|
end
|
||
|
|
||
|
def execute
|
||
|
@storage
|
||
|
.select(&method(:select_with_filters))
|
||
|
.sort(&method(:sort_with_order_bys))
|
||
|
.map(&method(:take_fields))
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
attr_reader :fields, :order_bys, :filters, :storage
|
||
|
|
||
|
def ensure_valid_fields!(fields)
|
||
|
fields.each do |field|
|
||
|
raise ArgumentError, format(INVALID_FIELD_MESSAGE, field) \
|
||
|
unless Record::ATTRIBUTES.include?(field.to_sym)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def take_fields(record)
|
||
|
selected_fields.map { |field| record.public_send(field) }
|
||
|
end
|
||
|
|
||
|
def sort_with_order_bys(lhs, rhs)
|
||
|
@order_bys
|
||
|
.lazy
|
||
|
.map { |attr| lhs.public_send(attr) <=> rhs.public_send(attr) }
|
||
|
.find(-> { 0 }, &:nonzero?)
|
||
|
end
|
||
|
|
||
|
def select_with_filters(record)
|
||
|
@filters.all? do |(key, value)|
|
||
|
record.public_send(key) == value
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def selected_fields
|
||
|
return Record::ATTRIBUTES if fields.empty?
|
||
|
|
||
|
fields
|
||
|
end
|
||
|
end
|
||
|
end
|