ankane/searchkick

Unable to index model with composite pk

antarr opened this issue · 1 comments

antarr commented

First
Indexing fails when using composite primary key

Describe the bug
I'm getting this error when the Searchkick::ReindexV2Job job is invoked

Error performing Searchkick::ReindexV2Job (Job ID: 349f96ca-0c71-4255-b7af-afaba72f2438) from Sidekiq(searchkick) in 1.68ms: ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR:  column voter_records.voter_uid,state_abbr does not exist
LINE 1: ...LECT "voter_records".* FROM "voter_records" WHERE "voter_rec...

To reproduce
Use this code to reproduce when possible:

VoterRecord.find_or_initialize_by(voter_uid: voter_id, state_abbr: abbr).tap do |voter_record|
  voter_record.first_name = "John"
  voter_record.last_name = "Doe"
  voter_record.address = "300 Main Street"
  voter_record.status = "Active"
  voter_record.save!
end

app/models/voter_record.rb

# frozen_string_literal: true

# == Schema Information
#
# Table name: voter_records
#
#  [:voter_uid, :state_abbr] :bigint           not null, primary key
#  address                   :citext           indexed
#  age                       :integer
#  claimed                   :boolean          default(FALSE)
#  districts                 :string           default([]), is an Array, indexed
#  dob                       :date
#  email                     :citext           default(""), not null
#  first_name                :string           not null
#  last_name                 :string           not null
#  middle_name               :string           default(""), not null
#  party                     :string
#  phone                     :string
#  raw_data                  :jsonb            not null
#  state_abbr                :string           not null, indexed
#  status                    :string           default("Active"), not null
#  voter_uid                 :string           not null, indexed
#  precinct_id               :bigint           not null, indexed
#

class VoterRecord < VoterDataRecord
  include EstimatedCount

  self.primary_keys = :voter_uid, :state_abbr

  has_one :verification, dependent: :destroy
  has_one :user, through: :verification, disable_joins: true

  belongs_to :precinct, inverse_of: :voter_records
  belongs_to :state, foreign_key: :state_abbr, primary_key: :abbr, inverse_of: :voter_records, class_name: 'LegiscanModel::State'

  delegate :representatives, to: :precinct, prefix: false
  delegate :name, to: :state, prefix: true, allow_nil: true

  scope :claimed, -> { where(claimed: true) }
  scope :unclaimed, -> { where(claimed: false) }

  searchkick callbacks: :async, text_start: [:name_and_address], word_start: [:address, :first_name, :last_name], batch_size: 1000

  def search_data
    {
      address: address,
      state_abbr: state_abbr
    }.merge(name_data)
  end

  def name_data
    {
      first_name: first_name,
      last_name: last_name,
      name_and_address: name_and_address
    }
  end

  def full_name
    "#{first_name} #{last_name}".titlecase
  end

  def display_address
    address.titlecase
  end

  def name_and_address
    "#{full_name} #{display_address}"
  end

  def to_h
    { 'id' => address, 'label' => address, 'value' => address }
  end
end

Additional context
searchkick (5.2.4)

ankane commented

Hi @antarr, thanks for reporting. Searchkick doesn't support composite primary keys, but may add in the future. Added to ideas (#1545).