Skip to content

Database repository ​

The DatabaseRepository is a class that receives a kyseley database and expose common database operations for a specific table. It is designed to be extended and customized for different tables and use cases.

Simple usage ​

The simple way to use the DatabaseRepository is to create an instance of it by passing the database and the name of the table you want to access. For example, if you have an orders table in your database, you can create a repository for it like this:

ts
import { DatabaseRepository, database } from '@sidekick-coder/zenith-kit/server';

interface Order {
    id: number;
    user_id: number;
    total: number;
}

const orderRepository = new DatabaseRepository<Order, number>(database, 'orders', 'id');

const orders = await orderRepository.findMany();

You will have the basic CRUD operations available on the orderRepository instance, such as findMany, findOne, create, update, and delete. but without any filters or custom logic.

Custom repository ​

To have custom filters you can extend the class and modify the query method, this method is used internally by the other methods to build the query

ts
import { DatabaseRepository, database } from '@sidekick-coder/zenith-kit/server';

interface Order {
    id: number;
    user_id: number;
    total: number;
}

interface OrderFilters {
    userId?: number;
    minTotal?: number;
    maxTotal?: number;
}

class OrderRepository extends DatabaseRepository<Order, number, OrderFilters> {
    constructor() {
        super(database, 'orders', 'id');
    }

    async query(filters: OrderFilters) {
        let qb = super.query();

        if (filters.userId) {
            qb = query.where('user_id', filters.userId);
        }

        if (filters.minTotal) {
            qb = query.where('total', '>=', filters.minTotal);
        }

        if (filters.maxTotal) {
            qb = query.where('total', '<=', filters.maxTotal);
        }

        return await query.select();
    }
}

This enable to to use the methods with the custom filters you defined in the OrderFilters interface, for example:

ts
await orderRepository.findMany({ userId: 1, minTotal: 100 });

await orderRepository.findOne({ minTotal: 100 });

await orderRepository.deleteMany({ maxTotal: 50 });

query ​

Builds the base query used by all read operations.

ts
query(options?: { qb?: any } & TOptions)

Returns a Kysely query builder instance.

ts
public query(options?: TOptions) {
    let qb = super.query(options)

    if (options?.active !== undefined) {
        qb = qb.where('active', '=', options.active)
    }

    return qb
}

count ​

Returns the total number of matching records.

ts
count(options?: TOptions): Promise<number>
ts
const total = await repository.count()

findMany ​

Returns multiple records.

ts
findMany(options?: FindManyOptions & TOptions): Promise<TEntity[]>

Supported options:

ts
{
    limit?: number
    offset?: number
    orderBy?: string | string[]
    orderDirection?: 'asc' | 'desc' | ('asc' | 'desc')[]
}
ts
const users = await repository.findMany({
    limit: 10,
    offset: 0,
    orderBy: 'name',
    orderDirection: 'asc'
})

findOne ​

Returns the first matching record.

ts
findOne(options?: TOptions): Promise<TEntity | null>
ts
const user = await repository.findOne()

findById ​

Finds a record by primary key.

ts
findById(
    id: TPrimaryKey,
    options?: TOptions
): Promise<TEntity | null>
ts
const user = await repository.findById(1)

findByIdOrFail ​

Finds a record by primary key.

Throws BaseException(404) if not found.

ts
findByIdOrFail(
    id: TPrimaryKey,
    options?: TOptions
): Promise<TEntity>
ts
const user = await repository.findByIdOrFail(1)

paginate ​

Returns paginated results.

ts
paginate(
    options?: PaginateOptions & TOptions
): Promise<Pagination<TEntity>>

Supported options:

ts
{
    page?: number
    limit?: number
    orderBy?: string | string[]
    orderDirection?: 'asc' | 'desc' | ('asc' | 'desc')[]
}
ts
const result = await repository.paginate({
    page: 1,
    limit: 20
})

Response:

ts
{
    items: TEntity[],
    page: number,
    per_page: number,
    total: number,
    total_pages: number
}

create ​

Creates a new record.

Automatically sets created_at when autoCreatedAt is enabled.

ts
create(data: Partial<TEntity>): Promise<TEntity>

Hook flow:

text
beforeCreate -> insert -> afterCreate
ts
const user = await repository.create({
    name: 'John'
})

createMany ​

Creates multiple records.

Automatically sets created_at when autoCreatedAt is enabled.

ts
createMany(
    data: Partial<TEntity>[]
): Promise<TEntity[]>

Hook flow:

text
beforeCreateMany -> insert -> afterCreateMany
ts
await repository.createMany([
    { name: 'John' },
    { name: 'Jane' }
])

updateById ​

Updates a record by primary key.

Automatically sets updated_at when autoUpdatedAt is enabled.

Throws BaseException(404) if the record does not exist.

ts
updateById(
    id: TPrimaryKey,
    data: Partial<TEntity>
): Promise<void>

Hook flow:

text
beforeUpdate -> update -> afterUpdate
ts
await repository.updateById(1, {
    name: 'Updated Name'
})

deleteById ​

Deletes a record by primary key.

Throws BaseException(404) if the record does not exist.

ts
deleteById(id: TPrimaryKey): Promise<void>

Hook flow:

text
beforeDelete -> delete -> afterDelete
ts
await repository.deleteById(1)

deleteMany ​

Deletes multiple records using filters defined in query().

ts
deleteMany(
    options?: DeleteManyOptions & TOptions
): Promise<void>

Supported options:

ts
{
    limit?: number
}

Hook flow:

text
beforeDeleteMany -> delete -> afterDeleteMany
ts
await repository.deleteMany({
    limit: 100
})

beforeCreate ​

Executed before creating a record.

ts
protected beforeCreate(
    data: Partial<TEntity>
): Promise<Partial<TEntity>>

afterCreate ​

Executed after creating a record.

ts
protected afterCreate(
    data: TEntity
): Promise<void>

beforeCreateMany ​

Executed before creating multiple records.

ts
protected beforeCreateMany(
    data: Partial<TEntity>[]
): Promise<Partial<TEntity>[]>

afterCreateMany ​

Executed after creating multiple records.

ts
protected afterCreateMany(
    data: TEntity[]
): Promise<TEntity[]>

beforeUpdate ​

Executed before updating a record.

ts
protected beforeUpdate(
    data: Partial<TEntity>,
    id: TPrimaryKey
): Promise<Partial<TEntity>>

afterUpdate ​

Executed after updating a record.

ts
protected afterUpdate(
    data: TEntity
): Promise<TEntity>

beforeDelete ​

Executed before deleting a record.

ts
protected beforeDelete(
    id: TPrimaryKey
): Promise<void>

afterDelete ​

Executed after deleting a record.

ts
protected afterDelete(
    id: TPrimaryKey
): Promise<void>

beforeDeleteMany ​

Executed before deleting multiple records.

ts
protected beforeDeleteMany(
    options?: DeleteManyOptions & TOptions
)

afterDeleteMany ​

Executed after deleting multiple records.

ts
protected afterDeleteMany(
    options?: DeleteManyOptions & TOptions
): Promise<void> | void