# frozen_string_literal: true require 'pry' module Some class Messages AND_CONJUCTION = :and OR_CONJUCTION = :or DEFAULT_CONJUCTION = AND_CONJUCTION Token = Struct.new(:conjuction, :field, :value, :messages) do def to_query conjuction_to_use = messages.next_token_id > 1 ? conjuction : '' return "#{conjuction_to_use} (#{value})" if field == :direct "#{conjuction_to_use} (#{field}:#{value})" end end TokenGroup = Struct.new(:conjuction, :tokens, :messages) do def initialize(*) super end def to_query tokens.flat_map(&:to_query).join(' ').to_s end def push_token(field, value) if value.is_a? String tokens.push(Token.new(conjuction, field, value, messages)) elsif value.is_a? Array group = TokenGroup.new(OR_CONJUCTION, [], messages) value.each do |val| group.push_token(field, val) end tokens.push group end end def next_token_id @token_count += 1 end end attr_accessor :query, :current_conjuction, :token_count attr_reader :db def initialize(db:) @db = db @query = [] @current_conjuction = AND_CONJUCTION @token_count = 0 end def or @current_conjuction = OR_CONJUCTION self end def and @current_conjuction = AND_CONJUCTION self end def filter(params) case params when String add_filter_from_string(params) when Hash add_filter_from_hash(params) end self end def each db.search_messages(query_string).each do |msg| yield(Message.new(msg: msg)) end end def add_filter_from_string(string) @query << Token.new(current_conjuction, :direct, string, self) end def add_filter_from_hash(hash) group = TokenGroup.new(current_conjuction, [], self) hash.each do |key, value| group.push_token(key, value) end @query << group end def query_string query.map(&:to_query).join(' ') end def next_token_id @token_count += 1 end end end