feat: Search improvements

This commit is contained in:
Tejaswini Chile 2022-12-05 21:38:12 +05:30
parent 34f7405689
commit 23cd34cbd6
10 changed files with 112 additions and 8 deletions

View file

@ -104,11 +104,8 @@ class ConversationFinder
end end
def filter_by_query def filter_by_query
allowed_message_types = [Message.message_types[:incoming], Message.message_types[:outgoing]] conversation_ids = PgSearch.multisearch("#{params[:q]}%").where(account_id: current_account).pluck(:conversation_id)
@conversations = conversations.joins(:messages).where('messages.content ILIKE :search', search: "%#{params[:q]}%") @conversations = Conversation.where(id: conversation_ids).includes(:messages)
.where(messages: { message_type: allowed_message_types }).includes(:messages)
.where('messages.content ILIKE :search', search: "%#{params[:q]}%")
.where(messages: { message_type: allowed_message_types })
end end
def filter_by_status def filter_by_status

View file

@ -0,0 +1,38 @@
module MultiSearchableHelpers
extend ActiveSupport::Concern
included do
PgSearch.multisearch_options = {
using: {
tsearch: {
prefix: true,
any_word: true,
normalization: 3
}
}
}
def self.rebuild_pg_search_documents
return unless name == 'Contact'
connection.execute <<~SQL.squish
INSERT INTO pg_search_documents (searchable_type, searchable_id, content, account_id, conversation_id, created_at, updated_at)
SELECT 'Contact' AS searchable_type,
contacts.id AS searchable_id,
CONCAT_WS(' ', contacts.email, contacts.name, contacts.phone_number, contacts.id, contacts.account_id) AS content,
contacts.account_id::int AS account_id,
conversations.id AS conversation_id,
now() AS created_at,
now() AS updated_at
FROM contacts
INNER JOIN conversations
ON conversations.contact_id = contacts.id
SQL
end
def update_contact_search_document
PgSearch::Document.create({ searchable_type: 'Contact', searchable_id: contact_id, conversation_id: id, account_id: account_id,
content: "#{contact.email} #{contact.name} #{contact.phone_number} #{contact.id}" })
end
end
end

View file

@ -26,6 +26,13 @@ class Contact < ApplicationRecord
include Avatarable include Avatarable
include AvailabilityStatusable include AvailabilityStatusable
include Labelable include Labelable
include PgSearch::Model
include MultiSearchableHelpers
# multisearchable(
# against: [:email, :name, :phone_number, :id],
# additional_attributes: -> (contact) { { conversation_id: nil, account_id: contact.account_id } }
# )
validates :account_id, presence: true validates :account_id, presence: true
validates :email, allow_blank: true, uniqueness: { scope: [:account_id], case_sensitive: false }, validates :email, allow_blank: true, uniqueness: { scope: [:account_id], case_sensitive: false },

View file

@ -48,7 +48,13 @@ class Conversation < ApplicationRecord
include ActivityMessageHandler include ActivityMessageHandler
include UrlHelper include UrlHelper
include SortHandler include SortHandler
include PgSearch::Model
include MultiSearchableHelpers
multisearchable(
against: [:display_id],
additional_attributes: ->(conversation) { { conversation_id: conversation.id, account_id: conversation.account_id } }
)
validates :account_id, presence: true validates :account_id, presence: true
validates :inbox_id, presence: true validates :inbox_id, presence: true
before_validation :validate_additional_attributes before_validation :validate_additional_attributes
@ -93,6 +99,7 @@ class Conversation < ApplicationRecord
after_update_commit :execute_after_update_commit_callbacks after_update_commit :execute_after_update_commit_callbacks
after_create_commit :notify_conversation_creation after_create_commit :notify_conversation_creation
after_create :update_contact_search_document
after_commit :set_display_id, unless: :display_id? after_commit :set_display_id, unless: :display_id?
delegate :auto_resolve_duration, to: :account delegate :auto_resolve_duration, to: :account

View file

@ -33,6 +33,14 @@
class Message < ApplicationRecord class Message < ApplicationRecord
include MessageFilterHelpers include MessageFilterHelpers
NUMBER_OF_PERMITTED_ATTACHMENTS = 15 NUMBER_OF_PERMITTED_ATTACHMENTS = 15
include PgSearch::Model
include MultiSearchableHelpers
multisearchable(
against: [:content],
if: :allowed_message_types?,
additional_attributes: ->(message) { { conversation_id: message.conversation_id, account_id: message.account_id } }
)
before_validation :ensure_content_type before_validation :ensure_content_type
@ -274,4 +282,8 @@ class Message < ApplicationRecord
conversation.update_columns(last_activity_at: created_at) conversation.update_columns(last_activity_at: created_at)
# rubocop:enable Rails/SkipsModelValidations # rubocop:enable Rails/SkipsModelValidations
end end
def allowed_message_types?
incoming? || outgoing?
end
end end

View file

@ -13,8 +13,10 @@
# display_name :string # display_name :string
# email :string # email :string
# encrypted_password :string default(""), not null # encrypted_password :string default(""), not null
# failed_attempts :integer
# last_sign_in_at :datetime # last_sign_in_at :datetime
# last_sign_in_ip :string # last_sign_in_ip :string
# locked_at :datetime
# message_signature :text # message_signature :text
# name :string not null # name :string not null
# provider :string default("email"), not null # provider :string default("email"), not null
@ -28,6 +30,7 @@
# ui_settings :jsonb # ui_settings :jsonb
# uid :string default(""), not null # uid :string default(""), not null
# unconfirmed_email :string # unconfirmed_email :string
# unlock_token :string
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# #

View file

@ -13,8 +13,10 @@
# display_name :string # display_name :string
# email :string # email :string
# encrypted_password :string default(""), not null # encrypted_password :string default(""), not null
# failed_attempts :integer
# last_sign_in_at :datetime # last_sign_in_at :datetime
# last_sign_in_ip :string # last_sign_in_ip :string
# locked_at :datetime
# message_signature :text # message_signature :text
# name :string not null # name :string not null
# provider :string default("email"), not null # provider :string default("email"), not null
@ -28,6 +30,7 @@
# ui_settings :jsonb # ui_settings :jsonb
# uid :string default(""), not null # uid :string default(""), not null
# unconfirmed_email :string # unconfirmed_email :string
# unlock_token :string
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# #

View file

@ -10,7 +10,7 @@ json.inbox do
json.channel_type conversation.inbox.channel_type json.channel_type conversation.inbox.channel_type
end end
json.messages do json.messages do
json.array! conversation.messages do |message| json.array! conversation.messages.last(1) do |message|
json.content message.content json.content message.content
json.id message.id json.id message.id
json.sender_name message.sender.name if message.sender json.sender_name message.sender.name if message.sender

View file

@ -0,0 +1,21 @@
class CreatePgSearchDocuments < ActiveRecord::Migration[6.1]
def up
say_with_time('Creating table for pg_search multisearch') do
create_table :pg_search_documents do |t|
t.text :content
t.bigint 'conversation_id'
t.bigint 'account_id'
t.belongs_to :searchable, polymorphic: true, index: true
t.timestamps null: false
end
add_index :pg_search_documents, :account_id
add_index :pg_search_documents, :conversation_id
end
end
def down
say_with_time('Dropping table for pg_search multisearch') do
drop_table :pg_search_documents
end
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2022_12_19_162759) do ActiveRecord::Schema.define(version: 2022_12_05_081737) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements" enable_extension "pg_stat_statements"
@ -399,7 +399,7 @@ ActiveRecord::Schema.define(version: 2022_12_19_162759) do
t.datetime "agent_last_seen_at" t.datetime "agent_last_seen_at"
t.jsonb "additional_attributes", default: {} t.jsonb "additional_attributes", default: {}
t.bigint "contact_inbox_id" t.bigint "contact_inbox_id"
t.uuid "uuid", default: -> { "gen_random_uuid()" }, null: false t.uuid "uuid", default: -> { "public.gen_random_uuid()" }, null: false
t.string "identifier" t.string "identifier"
t.datetime "last_activity_at", default: -> { "CURRENT_TIMESTAMP" }, null: false t.datetime "last_activity_at", default: -> { "CURRENT_TIMESTAMP" }, null: false
t.bigint "team_id" t.bigint "team_id"
@ -674,6 +674,19 @@ ActiveRecord::Schema.define(version: 2022_12_19_162759) do
t.index ["user_id"], name: "index_notifications_on_user_id" t.index ["user_id"], name: "index_notifications_on_user_id"
end end
create_table "pg_search_documents", force: :cascade do |t|
t.text "content"
t.bigint "conversation_id"
t.bigint "account_id"
t.string "searchable_type"
t.bigint "searchable_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["account_id"], name: "index_pg_search_documents_on_account_id"
t.index ["conversation_id"], name: "index_pg_search_documents_on_conversation_id"
t.index ["searchable_type", "searchable_id"], name: "index_pg_search_documents_on_searchable"
end
create_table "platform_app_permissibles", force: :cascade do |t| create_table "platform_app_permissibles", force: :cascade do |t|
t.bigint "platform_app_id", null: false t.bigint "platform_app_id", null: false
t.string "permissible_type", null: false t.string "permissible_type", null: false
@ -836,6 +849,9 @@ ActiveRecord::Schema.define(version: 2022_12_19_162759) do
t.jsonb "custom_attributes", default: {} t.jsonb "custom_attributes", default: {}
t.string "type" t.string "type"
t.text "message_signature" t.text "message_signature"
t.datetime "locked_at"
t.integer "failed_attempts"
t.string "unlock_token"
t.index ["email"], name: "index_users_on_email" t.index ["email"], name: "index_users_on_email"
t.index ["pubsub_token"], name: "index_users_on_pubsub_token", unique: true t.index ["pubsub_token"], name: "index_users_on_pubsub_token", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true