Skip to content

I am unable to specify a data type for my index, and that compromises the type safety  #456

@FlushBG

Description

@FlushBG

Describe the bug
I am using Orama search in a NestJS project. The use case is as follows:

  • When a module initializes (e.g. UserModule), in the onModuleInit() method a call to the database is made to retrieve all available users.
  • The data is indexed in an Orama index, to be made available for searching later and avoid unnecessary calls to the DB.
  • In case a new user is created or an existing one is updated, respective calls are made to the index to keep the data up to date.

The issue I'm facing is that I can't find a way to specify a type for the objects this index will be storing. Since the schema is only used to specify the searchable fields, I feel there should be a way to tell the index the full data schema that it will be holding. Currently, the search function returns the hits and the documents that were hit, but the return type is Document and it isn't generic. This causes some issues for other services (e.g. UserService), which are required to return an array of users - User[].

The current workaround is to either:

  • cast the document to unknown, and then to the type you need
    const user = document as unknown as User

  • manually map each property you need:

  private toUser(document: Document): User {
    return {
      id: doc['id'] as string,
      name: doc['name'] as string,
      email: doc['email'] as string,
      ...
    };
  }

To Reproduce
Steps to reproduce the behavior:

  1. Create a simple service that holds an Orama index:
@Injectable()
export class UserSearchService {
  private index: Orama;

  constructor(private dbService: DbService) {}

  async initializeIndex(): Promise<void> {
    this.index = await create({
      schema: {
        id: 'string',
        name: 'string',
        email: 'string',
      },
    });

    const users = await this.dbService.findAll<User>();
    await insertMultiple(this.index, users, 500);
  }

  async find(): Promise<User[]> {
    const result = await search(this.index, {...});

    const users = result.hits.map((hit) => hit.document);
    return users;
  }
  1. You will get a type error:
Type 'Document[]' is not assignable to type 'User[]'.
  Type 'Record<string, unknown>' is missing the following properties from type 'User': id, name, email
  1. Casting will also not work properly and will give the following error:
Conversion of type 'Document' to type 'User' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  1. The same errors occur the other way, when you are trying to update the index or insert something in it - for example, your service will receive an User object and you will not be able to insert it because it isn't of type Document.

Expected behavior
For the sake of type safety, I would expect to be able to specify the form of data my index will be holding, and avoid casting and / or mapping. A good approach would be to make all Orama methods generic, or at least the create method - so you can pass the type of your index when making it.

Example given:

const index = await create<User>({ // this will specify the full form of the data
     // and this will specify the searchable fields
      schema: {
        id: 'string',
        name: 'string',
        email: 'string',
        isActive: 'boolean',
        issuer: 'string',
        roles: 'string[]',
      },
    });

// this could either be generic or not, but the type specified at creation would guarantee the type safety of the returned document
const user = await search<User>(index);    

Additional context
The version of Orama I am facing this issue on is 1.1.1

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions