# frozen_string_literal: true
require_relative 'query'
require_relative 'where_clause'
require_relative 'or_clause'
module ErpIntegration
module Fulfil
module QueryMethods
attr_accessor :selected_fields, :where_clauses, :or_clauses
# The `QueryMethods#select` works in two unique ways
#
# First, it takes a block to allow it to function like a regular `Enumerable#select`.
#
# @example
# $ ErpIntegration::SalesOrder.select { |sales_order| sales_order.id > 100 }
# # => [, ]
#
# Secondly, it allows us to select specific fields to be returned by Fulfil.
#
# Fulfil only returns an ID by default when one would query their API. However,
# the ID is seldom the only value one will need. The `select` method allows
# selecting multiple fields at once.
#
# @example
# $ ErpIntegration::SalesOrder.select(:id, :name, 'product.name')
# # =>
#
# When one calls the `all` method, it will fetch all the resources from Fulfil
# and it will return all the given fields (if available).
#
# @example
# $ ErpIntegration::SalesOrder.select(:id, :name, 'product.name').all
# # => [, ]
#
# Both a list of Strings, Symbols or a combination of these can be passed
# to the `select` method.
def select(*fields)
if block_given?
raise ArgumentError, "'select' with block doesn't take arguments." if fields.any?
return super()
end
clone.select!(*fields)
end
def select!(*fields)
self.selected_fields = (selected_fields || []).concat(fields)
self
end
# Fulfil has a very powerful query syntax. However, that query syntax is rather
# complicated and it's really specific to Fulfil.
#
# The `where` method introduces a well-known interface (e.g. ActiveRecord::Relation)
# to query resources in Fulfil.
#
# @example
# $ ErpIntegration::SalesOrder.where(id: 100).all
# # => ] />
#
# If one adds the `comparison_operator` key to the arguments, it will use
# that comparison operator to build the query to Fulfil.
#
# All the other `where_` methods use this technique to provide logic for all
# the different comparison operators.
def where(*args)
clone.where!(*args)
end
def where!(args)
comparison_operator = args.delete(:comparison_operator)
args.each_pair do |key, value|
self.where_clauses =
(where_clauses || []) << WhereClause.new(
key: key, value: value, comparison_operator: comparison_operator
)
end
self
end
# The `or` method introduces an interface to query resources in Fulfil
# Is quite similar to the `where` method but with one big difference.
# The `or` method allows us to use the OR operator with several conditions
#
# @example
# $ ErpIntegration::SalesOrder.or(id: 100, carrier: 12).all
# # =>
# ] />
#
# @example
# $ ErpIntegration::SalesOrder.or(id: [100, 200]).all
# # =>
# ] />
#
# Now we are just accepting the last 'or' method so if we have multiple
# we are only accepting the last one.
def or(*args)
clone.or!(*args)
end
def or!(args)
where_clauses = []
args.each_pair do |key, value_or_values|
[*value_or_values].each do |value|
where_clauses << WhereClause.new(
key: key, value: value
)
end
end
self.or_clauses = [
OrClause.new(
where_clauses: where_clauses
)
]
self
end
def where_ilike(args)
where(args.merge(comparison_operator: 'ilike'))
end
def where_in(args)
where(args.merge(comparison_operator: 'in'))
end
def where_less_than(args)
where(args.merge(comparison_operator: '<'))
end
def where_less_or_equal_to(args)
where(args.merge(comparison_operator: '<='))
end
def where_like(args)
where(args.merge(comparison_operator: 'like'))
end
def where_more_than(args)
where(args.merge(comparison_operator: '>'))
end
def where_more_or_equal_to(args)
where(args.merge(comparison_operator: '>='))
end
def where_not(args)
where(args.merge(comparison_operator: '!='))
end
def where_not_in(args)
where(args.merge(comparison_operator: 'not in'))
end
end
end
end