require 'sequel' require_relative './models/post' require_relative './models/thread' RESULTS_PER_PAGE = 50 def search(params) query = params[:q].strip offset = (params[:page] - 1) * RESULTS_PER_PAGE username = params[:username].strip from_date = params[:from_date].strip to_date = params[:to_date].strip sort = params[:sort].strip exact_match = params[:exact_match].strip == "yes" errors = Array.new if from_date.empty? from_date = nil else if from_date.match(/\d{4}-\d{2}-\d{2}/) from_date = Date.parse(params[:from_date]) rescue errors << 'Invalid From Date' else errors << 'From Date must be in the format YYYY-MM-DD' end end if to_date.empty? to_date = nil else if to_date.match(/\d{4}-\d{2}-\d{2}/) to_date = Date.parse(params[:to_date]).next rescue errors << 'Invalid To Date' else errors << 'To Date must be in the format YYYY-MM-DD' end end if errors.empty? && !to_date.nil? && !from_date.nil? && to_date < from_date errors << 'To Date must be after From Date' end return {results: Array.new, errors: errors} unless errors.empty? results = case params[:type] when 'threads' search_threads(query, username, from_date, to_date, sort, offset, exact_match) when 'posts' search_posts(query, username, from_date, to_date, offset, exact_match) else Array.new end {results: results, errors: errors} end def search_threads(q, username, from_date, to_date, sort, offset, exact_match) sort = Sequel.desc(sort == 'post' ? :last_post_created_at : :created_at) query = VLV::Thread .select(Sequel.lit('threads.*, count(*) OVER() AS full_count')) .where(Sequel.lit("(LOWER(threads.creator) = LOWER(?) OR ? = '')", username, username)) .where(Sequel.lit("created_at >= ? OR ? IS NULL", from_date, from_date)) .where(Sequel.lit("created_at >= ? OR ? IS NULL", to_date, to_date)) .order(sort) .limit(RESULTS_PER_PAGE) .offset(Sequel.lit('?', offset)) if exact_match query.where(Sequel.ilike(:title, "%#{q}%")) else query.full_text_search(:title, Sequel.lit("websearch_to_tsquery(?)", q), tsquery: true, language: 'english') end end def search_posts(q, username, from_date, to_date, offset, exact_match) query = VLV::Post .select(Sequel.lit('posts.*, threads.title as thread_title, threads.remote_id as remote_thread_id, count(*) OVER() AS full_count')) .join(Sequel.lit('threads on posts.thread_id = threads.id')) .where(Sequel.lit("(LOWER(posts.creator) = LOWER(?) OR (? = ''))", username, username)) .where(Sequel.lit("posts.created_at >= ? OR ? IS NULL", from_date, from_date)) .where(Sequel.lit("posts.created_at >= ? OR ? IS NULL", to_date, to_date)) .limit(RESULTS_PER_PAGE) .offset(Sequel.lit('?', offset)) .order(Sequel.desc(Sequel.lit('posts.created_at'))) if exact_match query.where(Sequel.ilike(:body, "%#{q}%")) else query.full_text_search(:tsv, Sequel.lit("websearch_to_tsquery(?)", q), { tsquery: true, tsvector: true, language: 'english' }) end end