# frozen_string_literal: true
require 'bigdecimal'
require 'date'
module ErpIntegration
module Fulfil
# The `WhereClause` model encapsulates the logic for the filter options for Fulfil.
# It transforms the attributes passed to any of the where lookup methods into
# a format that Fulfil can actually understand.
#
# For more information, see their documentation.
# https://developers.fulfil.io/guides/searching-filtering/#field-filter-expressions
#
# @example
# WhereClause.new({ key: :id, value: 100, comparison_operator: 'ilike' })
# # =>
#
# @example
# $ WhereClause.new({ key: :id, value: 100 })
# # =>
class WhereClause
COMPARISON_OPERATORS = [
'=', '!=', '<', '<=', '>=', '>', 'like', 'ilike', 'in', 'not in'
].freeze
DEFAULT_COMPARISON_OPERATOR = '='
# @param key [String] The name of filtered attribute.
# @param value [String] The value by filtering will be performed.
# @param domain [String] The domain model name to specify filtering attributes location.
# @param comparison_operator [String] The way the key and the value are compared.
def initialize(key:, value:, domain: nil, comparison_operator: DEFAULT_COMPARISON_OPERATOR)
@comparison_operator = verify_comparison_operator(comparison_operator)
@key = key.to_s
@value = to_extended_query_value(value)
@domain = domain
end
# Transforms the `WhereClause` into a filter object for Fulfil.
# @return [Array] The formatted filter for Fulfil.
def to_filter
[@key, @comparison_operator, @value, @domain].compact
end
# The `===` allows comparing different WhereClause objects. Under the hood,
# this is used by `.uniq` to determine whether objects are equal to each other.
#
# Note: `.uniq` also depends on `.hash` on the `WhereClause` instance. See
# the `.hash` method to see how the two objects are compared.
#
# @example
# $ WhereClause.new(id: 100) == WhereClause.new(id: 100)
# # => true
#
# $ WhereClause.new(id: 100) == WhereClause.new(id: 101)
# # => false
#
# $ WhereClause.new(id: 100) == WhereClause.new(name: "PT100")
# # => false
#
# @param other [WhereClause] Another `WhereClause` instance.
# @return [Boolean] Whether or not the `WhereClause`s are equal.
def ==(other)
to_filter == other.to_filter
end
alias eql? ==
# The `.hash` allows comparing two `WhereClause` instances for uniqueness.
# See https://rubyapi.org/2.3/o/object#method-i-hash
# @return [Fixnum] A Fixnum that identifies the `WhereClause`.
def hash
to_filter.hash
end
private
# The {#to_extended_query_value} extends the query value into a rich
# query value to be able to query fields that contain dates, date times,
# or time values.
#
# @param query_value [Any] The input value for the where clause.
# @return [Hash|Any] The formatted input value
def to_extended_query_value(input_value)
case input_value
when DateTime # NOTE: A {DateTime} is also considered a {Date}. Filter first for a {DateTime}.
{ __class__: 'datetime', iso_string: input_value.iso8601 }
when Date
{ __class__: 'date', iso_string: input_value.iso8601 }
when Time
{ __class__: 'time', iso_string: input_value.iso8601 }
else
input_value
end
end
def verify_comparison_operator(comparison_operator)
return comparison_operator if COMPARISON_OPERATORS.include?(comparison_operator)
DEFAULT_COMPARISON_OPERATOR
end
end
end
end