Skip to content

Commit a880448

Browse files
Revert citext column type for patient names
- Revert collumn type change in commit 192fcc1 - The citext collation does not work with the trigram (pg_tgrm) index - Instead of using ILIKE for case insensitive comparison use equality with lower() - This should hopefully keep the memory benefits of the citext type for this query
1 parent 0db62bb commit a880448

6 files changed

Lines changed: 107 additions & 18 deletions

File tree

app/lib/patient_matcher.rb

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,36 @@ def self.from_relation(
1717
return [patient]
1818
end
1919

20-
scope = relation.where(given_name:, family_name:, date_of_birth:)
20+
scope =
21+
relation.where(
22+
"lower(given_name) = lower(?) AND lower(family_name) = lower(?)",
23+
given_name,
24+
family_name
25+
).where(date_of_birth:)
2126

2227
if address_postcode.present?
2328
scope =
2429
if include_3_out_of_4_matches
2530
scope
26-
.or(relation.where(given_name:, family_name:, address_postcode:))
27-
.or(relation.where(given_name:, date_of_birth:, address_postcode:))
28-
.or(relation.where(family_name:, date_of_birth:, address_postcode:))
31+
.or(
32+
relation.where(
33+
"lower(given_name) = lower(?) AND lower(family_name) = lower(?)",
34+
given_name,
35+
family_name
36+
).where(address_postcode:)
37+
)
38+
.or(
39+
relation.where("lower(given_name) = lower(?)", given_name).where(
40+
date_of_birth:,
41+
address_postcode:
42+
)
43+
)
44+
.or(
45+
relation.where(
46+
"lower(family_name) = lower(?)",
47+
family_name
48+
).where(date_of_birth:, address_postcode:)
49+
)
2950
else
3051
scope.where(address_postcode:)
3152
end

app/models/patient.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
# ethnic_background :integer
1717
# ethnic_background_other :string
1818
# ethnic_group :integer
19-
# family_name :citext not null
19+
# family_name :string not null
2020
# gender_code :integer default("not_known"), not null
21-
# given_name :citext not null
21+
# given_name :string not null
2222
# home_educated :boolean
2323
# invalidated_at :datetime
2424
# local_authority_mhclg_code :string
@@ -227,22 +227,22 @@ class Patient < ApplicationRecord
227227
)
228228
end
229229

230-
like_scope =
230+
ilike_scope =
231231
terms.reduce(self) do |scope, term|
232232
if term.length < 3
233233
scope.and where(
234-
"family_name LIKE :term || '%' OR given_name LIKE :term || '%'",
234+
"family_name ILIKE :term || '%' OR given_name ILIKE :term || '%'",
235235
term:
236236
)
237237
else
238238
scope.and where(
239-
"family_name LIKE '%' || :term || '%' OR given_name LIKE '%' || :term || '%'",
239+
"family_name ILIKE '%' || :term || '%' OR given_name ILIKE '%' || :term || '%'",
240240
term:
241241
)
242242
end
243243
end
244244

245-
similarity_scope.or(like_scope).order(
245+
similarity_scope.or(ilike_scope).order(
246246
Arel.sql(
247247
"(STRICT_WORD_SIMILARITY(given_name, :query) + STRICT_WORD_SIMILARITY(family_name, :query)) DESC",
248248
query:
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# frozen_string_literal: true
2+
3+
class ChangePatientNamesBackToText < ActiveRecord::Migration[8.1]
4+
disable_ddl_transaction!
5+
6+
def change
7+
# Drop indexes on given_name/family_name concurrently first so the
8+
# ALTER COLUMN TYPE doesn't hold an ACCESS EXCLUSIVE lock while
9+
# rebuilding them.
10+
11+
remove_index :patients,
12+
column: %i[family_name given_name],
13+
name: "index_patients_on_names_family_first",
14+
algorithm: :concurrently
15+
remove_index :patients,
16+
column: %i[given_name family_name],
17+
name: "index_patients_on_names_given_first",
18+
algorithm: :concurrently
19+
remove_index :patients,
20+
column: :family_name,
21+
name: "index_patients_on_family_name_trigram",
22+
algorithm: :concurrently,
23+
opclass: :gin_trgm_ops,
24+
using: :gin
25+
remove_index :patients,
26+
column: :given_name,
27+
name: "index_patients_on_given_name_trigram",
28+
algorithm: :concurrently,
29+
opclass: :gin_trgm_ops,
30+
using: :gin
31+
32+
reversible do |dir|
33+
dir.up do
34+
change_table :patients, bulk: true do |t|
35+
t.change :given_name, :string, null: false
36+
t.change :family_name, :string, null: false
37+
end
38+
end
39+
dir.down do
40+
change_table :patients, bulk: true do |t|
41+
t.change :given_name, :citext, null: false
42+
t.change :family_name, :citext, null: false
43+
end
44+
end
45+
end
46+
47+
add_index :patients,
48+
%i[family_name given_name],
49+
name: "index_patients_on_names_family_first",
50+
algorithm: :concurrently
51+
add_index :patients,
52+
%i[given_name family_name],
53+
name: "index_patients_on_names_given_first",
54+
algorithm: :concurrently
55+
add_index :patients,
56+
:family_name,
57+
name: "index_patients_on_family_name_trigram",
58+
opclass: :gin_trgm_ops,
59+
using: :gin,
60+
algorithm: :concurrently
61+
add_index :patients,
62+
:given_name,
63+
name: "index_patients_on_given_name_trigram",
64+
opclass: :gin_trgm_ops,
65+
using: :gin,
66+
algorithm: :concurrently
67+
disable_extension "citext"
68+
end
69+
end

db/schema.rb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[8.1].define(version: 2026_03_10_195113) do
13+
ActiveRecord::Schema[8.1].define(version: 2026_03_16_165220) do
1414
# These are extensions that must be enabled in order to support this database
15-
enable_extension "citext"
1615
enable_extension "pg_catalog.plpgsql"
1716
enable_extension "pg_trgm"
1817

@@ -742,9 +741,9 @@
742741
t.integer "ethnic_background"
743742
t.string "ethnic_background_other"
744743
t.integer "ethnic_group"
745-
t.citext "family_name", null: false
744+
t.string "family_name", null: false
746745
t.integer "gender_code", default: 0, null: false
747-
t.citext "given_name", null: false
746+
t.string "given_name", null: false
748747
t.bigint "gp_practice_id"
749748
t.boolean "home_educated"
750749
t.datetime "invalidated_at"

spec/factories/patients.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
# ethnic_background :integer
1717
# ethnic_background_other :string
1818
# ethnic_group :integer
19-
# family_name :citext not null
19+
# family_name :string not null
2020
# gender_code :integer default("not_known"), not null
21-
# given_name :citext not null
21+
# given_name :string not null
2222
# home_educated :boolean
2323
# invalidated_at :datetime
2424
# local_authority_mhclg_code :string

spec/models/patient_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
# ethnic_background :integer
1717
# ethnic_background_other :string
1818
# ethnic_group :integer
19-
# family_name :citext not null
19+
# family_name :string not null
2020
# gender_code :integer default("not_known"), not null
21-
# given_name :citext not null
21+
# given_name :string not null
2222
# home_educated :boolean
2323
# invalidated_at :datetime
2424
# local_authority_mhclg_code :string

0 commit comments

Comments
 (0)