# 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