Fully functional fulltext search

This commit is contained in:
2023-01-25 14:59:23 +01:00
parent 893013cdae
commit a2c930d457
6 changed files with 172 additions and 81 deletions

View File

@@ -1,18 +1,10 @@
from beanie import PydanticObjectId
from beanie.odm.enums import SortDirection
from beanie.operators import And, Or, RegEx, Eq
from fastapi import APIRouter, HTTPException
from fastapi_paginate import Page, Params, add_pagination
from fastapi_paginate.ext.motor import paginate
from typing import TypeVar, List, Generic, Any, Dict
T = TypeVar('T')
U = TypeVar('U')
V = TypeVar('V')
W = TypeVar('W')
def parse_sort(sort_by):
if not sort_by:
@@ -26,8 +18,29 @@ def parse_sort(sort_by):
return fields
def parse_query(query) -> Dict[Any, Any]:
return {}
def parse_query(query: str, model):
if query is None:
return {}
and_array = []
for criterion in query.split(' AND '):
[column, operator, value] = criterion.split(' ', 2)
column = column.lower()
if column == 'fulltext':
if not model.Settings.fulltext_search:
continue
or_array = []
for field in model.Settings.fulltext_search:
or_array.append(RegEx(field, value, 'i'))
operand = Or(or_array) if len(or_array) > 1 else or_array[0]
elif operator == 'eq':
operand = Eq(column, value)
and_array.append(operand)
return And(and_array) if len(and_array) > 1 else and_array[0]
def get_crud_router(model, model_create, model_read, model_update):
@@ -48,8 +61,7 @@ def get_crud_router(model, model_create, model_read, model_update):
@router.get("/", response_model=Page[model_read], response_description="{} records retrieved".format(model.__name__))
async def read_list(size: int = 50, page: int = 1, sort_by: str = None, query: str = None) -> Page[model_read]:
sort = parse_sort(sort_by)
query = parse_query(query)
# limit=limit, skip=offset,
query = parse_query(query, model_read)
collection = model.get_motor_collection()
items = paginate(collection, query, Params(**{'size': size, 'page': page}), sort=sort)
@@ -89,5 +101,3 @@ def get_crud_router(model, model_create, model_read, model_update):
add_pagination(router)
return router

View File

@@ -15,4 +15,6 @@ async def init_db():
DATABASE_URL, uuidRepresentation="standard"
)
await init_beanie(database=client.db_name, document_models=[User, AccessToken, Entity, Order, Contract, ], )
await init_beanie(database=client.db_name,
document_models=[User, AccessToken, Entity, Order, Contract, ],
allow_index_dropping=True)

View File

@@ -2,8 +2,9 @@ from enum import Enum
from datetime import datetime, date
from typing import List, Literal
from pymongo import TEXT, IndexModel
from pydantic import Field, BaseModel, validator
from beanie import Document, Link
from beanie import Document, Indexed
class EntityType(BaseModel):
@@ -14,13 +15,11 @@ class EntityType(BaseModel):
class Individual(EntityType):
type: Literal['individual'] = 'individual'
firstname: str
middlenames: List[str] = Field(default=[])
lastname: str
surnames: List[str] = Field(default=[])
firstname: Indexed(str, index_type=TEXT)
middlenames: List[Indexed(str)] = Field(default=[])
lastname: Indexed(str)
surnames: List[Indexed(str)] = Field(default=[])
day_of_birth: date
job: str
employer: str
@property
@@ -39,7 +38,7 @@ class Individual(EntityType):
class Employee(EntityType):
role: str
role: Indexed(str)
entity_id: str = Field(foreignKey={
"reference": {
"resource": "entity",
@@ -51,21 +50,21 @@ class Employee(EntityType):
class Corporation(EntityType):
type: Literal['corporation'] = 'corporation'
title: str
activity: str
title: Indexed(str)
activity: Indexed(str)
employees: List[Employee] = Field(default=[])
class Institution(BaseModel):
type: Literal['institution'] = 'institution'
title: str
activity: str
title: Indexed(str)
activity: Indexed(str)
employees: List[Employee] = Field(default=[])
class Entity(Document):
_id: str
address: str
address: Indexed(str, index_type=TEXT)
entity_data: Individual | Corporation | Institution = Field(..., discriminator='type')
label: str = None
@@ -82,3 +81,7 @@ class Entity(Document):
else datetime(year=dt.year, month=dt.month, day=dt.day,
hour=0, minute=0, second=0)
}
fulltext_search = ['label']