Add fuzzy name search (pg_trgm) and living-person protection
Fuzzy search: pg_trgm extension + trigram GIN indexes on name parts and a GET /trees/{id}/persons?q= search ranked by trigram similarity (finds Mueller for 'muller'), privacy-filtered. Living-person protection: the privacy engine now derives possibly-living status (explicit flag, else no death fact + birth within ~100y or unknown) and returns 'redacted' for non-members of public/unlisted trees; the service minimises those records ('Living person', no vitals). Members are unaffected. 31 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>
This commit is contained in:
@@ -7,7 +7,7 @@ aliases) so name changes over time are first-class.
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import Boolean, ForeignKey, Integer, String, Text, text
|
||||
from sqlalchemy import Boolean, ForeignKey, Index, Integer, String, Text, text
|
||||
from sqlalchemy import Enum as SAEnum
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
@@ -33,6 +33,22 @@ class Person(Base, UUIDPrimaryKey, TenantScoped, Timestamps, SoftDelete):
|
||||
|
||||
class Name(Base, UUIDPrimaryKey, TenantScoped, Timestamps, SoftDelete):
|
||||
__tablename__ = "names"
|
||||
# Trigram indexes for fuzzy name search (Mueller/Müller/Muller). Requires the
|
||||
# pg_trgm extension (enabled in the accompanying migration).
|
||||
__table_args__ = (
|
||||
Index(
|
||||
"ix_names_given_trgm",
|
||||
"given",
|
||||
postgresql_using="gin",
|
||||
postgresql_ops={"given": "gin_trgm_ops"},
|
||||
),
|
||||
Index(
|
||||
"ix_names_surname_trgm",
|
||||
"surname",
|
||||
postgresql_using="gin",
|
||||
postgresql_ops={"surname": "gin_trgm_ops"},
|
||||
),
|
||||
)
|
||||
|
||||
person_id: Mapped[uuid.UUID] = mapped_column(
|
||||
ForeignKey("persons.id", ondelete="CASCADE"), index=True
|
||||
|
||||
Reference in New Issue
Block a user