Help with types in Repository Pattern

Hello,

I'm trying to set up a crud repository where it can be extended but I'm not sure how to get the typings correct.
Here is what I have and I'm stuck.
The issue that I have is I'm not sure how to actually get the primaryKey in a type safe way.

export interface BaseRepository<T, ID> {
  findAll(): Promise<T[]>;

  findAll(criteria: QueryCriteria): Promise<T[]>;

  findOne(id: ID): Promise<T | null>;

  update(id: ID, data: T): Promise<T>;

  create(data: T): Promise<T>;

  delete(id: ID): Promise<void>;
}


export abstract class CrudRepository<
  M extends MySqlTable,
  ID extends keyof S,
  S extends InferModel<M>,
  I extends InferModel<M, "insert">> implements BaseRepository<S, S[ID]> {


  protected constructor(protected readonly db: DbConnection,
                        protected readonly schema: M,
                        protected readonly primaryKey: ID) {
  }


  async create(data: S): Promise<S> {
    await this.db.insert(this.schema).values([{ ...data }]);

    const result = await this.db.select().from(this.schema).where(eq(this.schema[this.primaryKey], "LAST_INSERT_ID()"));
    return result[0];
  }

  async delete(id: S[ID]): Promise<void> {
    const result = await this.db.delete(this.schema).where(eq(this.schema[this.primaryKey], id));
  }

  async findAll(): Promise<S[]> {
    return this.db.select().from(this.schema);
  }

  findOne(id: S[ID]): Promise<S | null> {
    return this.db.select().from(this.schema).where(eq(this.schema[this.primaryKey], id));
  }

  async update(id: S[ID], data: I): Promise<S | null> {
    const entity = this.findOne(id);
    if (!entity) {
      throw new Error("Entity not found");
    }
    this.db.update(this.schema).set(data).where(eq(this.schema[this.primaryKey], id));
    return this.findOne(id);
  }

}
Was this page helpful?