You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

search.rb 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. require 'sequel'
  2. require_relative './models/post'
  3. require_relative './models/thread'
  4. RESULTS_PER_PAGE = 50
  5. def search(params)
  6. query = params[:q].strip
  7. offset = (params[:page] - 1) * RESULTS_PER_PAGE
  8. username = params[:username].strip
  9. from_date = params[:from_date].strip
  10. to_date = params[:to_date].strip
  11. sort = (params[:sort] || "").strip
  12. exact_match = params[:exact_match].strip == "yes"
  13. errors = Array.new
  14. if from_date.empty?
  15. from_date = nil
  16. else
  17. if from_date.match(/\d{4}-\d{2}-\d{2}/)
  18. from_date = Date.parse(params[:from_date]) rescue errors << 'Invalid From Date'
  19. else
  20. errors << 'From Date must be in the format YYYY-MM-DD'
  21. end
  22. end
  23. if to_date.empty?
  24. to_date = nil
  25. else
  26. if to_date.match(/\d{4}-\d{2}-\d{2}/)
  27. to_date = Date.parse(params[:to_date]).next rescue errors << 'Invalid To Date'
  28. else
  29. errors << 'To Date must be in the format YYYY-MM-DD'
  30. end
  31. end
  32. if errors.empty? && !to_date.nil? && !from_date.nil? && to_date < from_date
  33. errors << 'To Date must be after From Date'
  34. end
  35. return {results: Array.new, errors: errors} unless errors.empty?
  36. results = case params[:type]
  37. when 'threads'
  38. search_threads(query, username, from_date, to_date, sort, offset, exact_match)
  39. when 'posts'
  40. search_posts(query, username, from_date, to_date, offset, exact_match)
  41. else
  42. Array.new
  43. end
  44. {results: results, errors: errors}
  45. end
  46. def search_threads(q, username, from_date, to_date, sort, offset, exact_match)
  47. sort = Sequel.desc(sort == 'post' ? :last_post_created_at : :created_at)
  48. query = VLV::Thread
  49. .select(Sequel.lit('threads.*'))
  50. .where(Sequel.lit("(LOWER(threads.creator) = LOWER(?) OR ? = '')", username, username))
  51. .where(Sequel.lit("created_at >= ? OR ? IS NULL", from_date, from_date))
  52. .where(Sequel.lit("created_at >= ? OR ? IS NULL", to_date, to_date))
  53. .order(sort)
  54. .limit(RESULTS_PER_PAGE)
  55. .offset(Sequel.lit('?', offset))
  56. count_query = VLV::Thread
  57. .select(Sequel.lit('count(*) as full_count'))
  58. .where(Sequel.lit("(LOWER(threads.creator) = LOWER(?) OR ? = '')", username, username))
  59. .where(Sequel.lit("created_at >= ? OR ? IS NULL", from_date, from_date))
  60. .where(Sequel.lit("created_at >= ? OR ? IS NULL", to_date, to_date))
  61. if exact_match
  62. filter = Sequel.ilike(:title, "%#{q}%")
  63. result = query.where(filter)
  64. full_count = count_query.where(filter).first.values[:full_count]
  65. [full_count, result]
  66. else
  67. result = query.full_text_search(:title, Sequel.lit("websearch_to_tsquery(?)", q), tsquery: true, language: 'english')
  68. full_count = count_query.full_text_search(
  69. :title, Sequel.lit("websearch_to_tsquery(?)", q), tsquery: true, language: 'english'
  70. ).first.values[:full_count]
  71. [full_count, result]
  72. end
  73. end
  74. def search_posts(q, username, from_date, to_date, offset, exact_match)
  75. query = VLV::Post
  76. .select(Sequel.lit('posts.*, threads.title as thread_title, threads.remote_id as remote_thread_id'))
  77. .join(Sequel.lit('threads on posts.thread_id = threads.id'))
  78. .where(Sequel.lit("(LOWER(posts.creator) = LOWER(?) OR (? = ''))", username, username))
  79. .where(Sequel.lit("posts.created_at >= ? OR ? IS NULL", from_date, from_date))
  80. .where(Sequel.lit("posts.created_at >= ? OR ? IS NULL", to_date, to_date))
  81. .limit(RESULTS_PER_PAGE)
  82. .offset(Sequel.lit('?', offset))
  83. .order(Sequel.desc(Sequel.lit('posts.created_at')))
  84. count_query = VLV::Post
  85. .select(Sequel.lit('count(*) as full_count'))
  86. .join(Sequel.lit('threads on posts.thread_id = threads.id'))
  87. .where(Sequel.lit("(LOWER(posts.creator) = LOWER(?) OR (? = ''))", username, username))
  88. .where(Sequel.lit("posts.created_at >= ? OR ? IS NULL", from_date, from_date))
  89. .where(Sequel.lit("posts.created_at >= ? OR ? IS NULL", to_date, to_date))
  90. if exact_match
  91. result = query.where(Sequel.ilike(:body, "%#{q}%"))
  92. full_count = count_query.where(Sequel.ilike(:body, "%#{q}%")).first.values[:full_count]
  93. [full_count, result]
  94. else
  95. result = query.full_text_search(:tsv, Sequel.lit("websearch_to_tsquery(?)", q), {
  96. tsquery: true,
  97. tsvector: true,
  98. language: 'english'
  99. })
  100. full_count = count_query.full_text_search(:tsv, Sequel.lit("websearch_to_tsquery(?)", q), {
  101. tsquery: true,
  102. tsvector: true,
  103. language: 'english'
  104. }).first.values[:full_count]
  105. [full_count, result]
  106. end
  107. end