Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Medicines: replace in-memory search with pg full text search with GIN index #1439

Closed
wants to merge 10 commits into from
65 changes: 14 additions & 51 deletions care/facility/api/viewsets/prescription.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
from re import IGNORECASE

from django.shortcuts import get_object_or_404
from django_filters import rest_framework as filters
from drf_spectacular.utils import extend_schema
from rest_framework import mixins, status
from rest_framework.decorators import action
from rest_framework.filters import SearchFilter
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ViewSet
from rest_framework.viewsets import GenericViewSet

from care.facility.api.serializers.prescription import (
MedibaseMedicineSerializer,
MedicineAdministrationSerializer,
PrescriptionSerializer,
)
from care.facility.models import (
MedibaseMedicine,
MedicineAdministration,
Prescription,
PrescriptionType,
Expand Down Expand Up @@ -136,52 +137,14 @@ def administer(self, request, *args, **kwargs):
# return Response({"success": True}, status=status.HTTP_200_OK)


class MedibaseViewSet(ViewSet):
class MedicineViewSet(
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
GenericViewSet,
):
serializer_class = MedibaseMedicineSerializer
permission_classes = (IsAuthenticated,)

def serailize_data(self, objects):
result = []
for object in objects:
if type(object) == tuple:
object = object[0]
result.append(
{
"id": object.external_id,
"name": object.name,
"type": object.type,
"generic": object.generic,
"company": object.company,
"contents": object.contents,
"cims_class": object.cims_class,
"atc_classification": object.atc_classification,
}
)
return result

def sort(self, query, results):
exact_matches = []
partial_matches = []

for result in results:
if type(result) == tuple:
result = result[0]
words = result.searchable.lower().split()
if query in words:
exact_matches.append(result)
else:
partial_matches.append(result)

return exact_matches + partial_matches

def list(self, request):
from care.facility.static_data.medibase import MedibaseMedicineTable

queryset = MedibaseMedicineTable

if request.GET.get("query", False):
query = request.GET.get("query").strip().lower()
queryset = queryset.where(
searchable=queryset.re_match(r".*" + query + r".*", IGNORECASE)
)
queryset = self.sort(query, queryset)
return Response(self.serailize_data(queryset[:15]))
queryset = MedibaseMedicine.objects.all()
lookup_field = "external_id"
filter_backends = (SearchFilter,)
search_fields = ("name", "generic", "company", "contents", "cims_class")
22 changes: 22 additions & 0 deletions care/facility/migrations/0371_medibasemedicine_search_idx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 4.2.2 on 2023-07-06 11:18

import django.contrib.postgres.indexes
from django.contrib.postgres.operations import BtreeGinExtension
from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("facility", "0370_merge_20230705_1500"),
]

operations = [
BtreeGinExtension(),
migrations.AddIndex(
model_name="medibasemedicine",
index=django.contrib.postgres.indexes.GinIndex(
fields=["name", "generic", "company", "contents", "cims_class"],
name="search_idx",
),
),
]
9 changes: 9 additions & 0 deletions care/facility/models/prescription.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import enum

from django.contrib.postgres.indexes import GinIndex
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import JSONField
Expand Down Expand Up @@ -66,6 +67,14 @@ class MedibaseMedicine(BaseModel):
def __str__(self):
return " - ".join([self.name, self.generic, self.company])

class Meta:
indexes = [
GinIndex(
fields=["name", "generic", "company", "contents", "cims_class"],
name="search_idx",
)
]


class Prescription(BaseModel):
consultation = models.ForeignKey(
Expand Down
26 changes: 0 additions & 26 deletions care/facility/static_data/medibase.py

This file was deleted.

4 changes: 2 additions & 2 deletions config/api_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
from care.facility.api.viewsets.patient_sample import PatientSampleViewSet
from care.facility.api.viewsets.prescription import (
ConsultationPrescriptionViewSet,
MedibaseViewSet,
MedicineAdministrationViewSet,
MedicineViewSet,
)
from care.facility.api.viewsets.prescription_supplier import (
PrescriptionSupplierConsultationViewSet,
Expand Down Expand Up @@ -200,7 +200,7 @@
consultation_nested_router.register(
r"prescription_administration", MedicineAdministrationViewSet
)
router.register("medibase", MedibaseViewSet, basename="medibase")
router.register("medicine", MedicineViewSet)

# HCX
router.register("hcx/policy", PolicyViewSet)
Expand Down
Loading