Last active
July 25, 2023 17:30
-
-
Save MurylloEx/63638cf4c386f9d13a471f1794c7dfbb to your computer and use it in GitHub Desktop.
Sample of CRUD Repository and Paging Repository Pattern based on Spring Framework repository abstraction layers (CRUD, PagingAndSorting, Jpa). It was designated to work with Sequelize Typescript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Model } from 'sequelize-typescript'; | |
import { MakeNullishOptional } from 'sequelize/types/utils'; | |
import { DestroyOptions, FindOptions, UpdateOptions } from 'sequelize'; | |
export type RepoPrimaryKey = string | number | bigint; | |
export type RepoDelete<TAttributes extends object> = DestroyOptions<TAttributes>; | |
export type RepoUpdate<TAttributes extends object> = UpdateOptions<TAttributes>; | |
export type RepoFetch<TAttributes extends object> = FindOptions<TAttributes>; | |
export type RepoCreate<TAttributes extends object> = MakeNullishOptional<TAttributes>; | |
export interface ICrudRepository< | |
TModelAttributes extends object, | |
TCreationAttributes extends object, | |
TModel extends Model<TModelAttributes, TCreationAttributes> | |
> { | |
create(value: RepoCreate<TCreationAttributes>): Promise<TModel>; | |
fetchOne(options: RepoFetch<TModelAttributes>): Promise<TModel>; | |
updateOne(options: RepoUpdate<TModelAttributes>, value: TModelAttributes): Promise<TModel>; | |
deleteOne(options: RepoDelete<TModelAttributes>): Promise<TModel>; | |
restoreOne(options: RepoFetch<TModelAttributes>): Promise<TModel>; | |
fetchUnique(identifier: RepoPrimaryKey, options?: RepoFetch<TModelAttributes>): Promise<TModel>; | |
updateUnique(identifier: RepoPrimaryKey, value: TModelAttributes): Promise<TModel>; | |
deleteUnique(identifier: RepoPrimaryKey): Promise<TModel>; | |
restoreUnique(identifier: RepoPrimaryKey): Promise<TModel>; | |
fetch(options: RepoFetch<TModelAttributes>): Promise<TModel[]>; | |
update(options: RepoUpdate<TModelAttributes>, value: TModelAttributes): Promise<TModel[]>; | |
delete(options: RepoDelete<TModelAttributes>): Promise<TModel[]>; | |
restore(options: RepoFetch<TModelAttributes>): Promise<TModel[]>; | |
count(options: RepoFetch<TModelAttributes>): Promise<number>; | |
exists(options: RepoFetch<TModelAttributes>): Promise<boolean>; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Model } from 'sequelize-typescript'; | |
import { ModelStatic } from 'sequelize'; | |
import { | |
RepoUpdate, | |
RepoCreate, | |
RepoDelete, | |
RepoFetch, | |
RepoPrimaryKey, | |
ICrudRepository, | |
} from './crud-repository.interface'; | |
export abstract class CrudRepository< | |
TModelAttributes extends object, | |
TCreationAttributes extends object, | |
TModel extends Model<TModelAttributes, TCreationAttributes> | |
> implements ICrudRepository<TModelAttributes, TCreationAttributes, TModel> { | |
constructor(protected readonly model: ModelStatic<TModel>) {} | |
async create(value: RepoCreate<TCreationAttributes>): Promise<TModel> { | |
return await this.model.create(value); | |
} | |
async fetch(options: RepoFetch<TModelAttributes>): Promise<TModel[]> { | |
return await this.model.findAll(options); | |
} | |
async fetchOne(options: RepoFetch<TModelAttributes>): Promise<TModel> { | |
const entity = await this.model.findOne(options); | |
if (!entity) | |
throw new Error('The specified record was not found in the database.'); | |
return entity; | |
} | |
async fetchUnique(identifier: RepoPrimaryKey, options?: RepoFetch<TModelAttributes>): Promise<TModel> { | |
const entity = await this.model.findByPk(identifier, options); | |
if (!entity) | |
throw new Error('The specified record was not found in the database.'); | |
return entity; | |
} | |
async update(options: RepoUpdate<TModelAttributes>, value: TModelAttributes): Promise<TModel[]> { | |
await this.model.update(value, options); | |
return await this.fetch(options); | |
} | |
async updateUnique(identifier: RepoPrimaryKey, value: TModelAttributes): Promise<TModel> { | |
const entity = await this.fetchUnique(identifier); | |
return await entity.update(value); | |
} | |
async updateOne(options: RepoUpdate<TModelAttributes>, value: TModelAttributes): Promise<TModel> { | |
const entity = await this.fetchOne(options); | |
return await entity.update(value); | |
} | |
async delete(options: RepoDelete<TModelAttributes>): Promise<TModel[]> { | |
const entities = await this.fetch(options); | |
await Promise.all(entities.map(entity => entity.destroy())); | |
return entities; | |
} | |
async deleteUnique(identifier: RepoPrimaryKey): Promise<TModel> { | |
const entity = await this.fetchUnique(identifier); | |
await entity.destroy(); | |
return entity; | |
} | |
async deleteOne(options: RepoDelete<TModelAttributes>): Promise<TModel> { | |
const entity = await this.fetchOne(options); | |
await entity.destroy(); | |
return entity; | |
} | |
async restore(options: RepoFetch<TModelAttributes>): Promise<TModel[]> { | |
const entities = await this.fetch(options); | |
await Promise.all(entities.map(entity => entity.restore(options))); | |
return entities; | |
} | |
async restoreUnique(identifier: RepoPrimaryKey): Promise<TModel> { | |
const entity = await this.fetchUnique(identifier, { paranoid: false }); | |
await entity.restore(); | |
return entity; | |
} | |
async restoreOne(options: RepoFetch<TModelAttributes>): Promise<TModel> { | |
const entity = await this.fetchOne({ ...options, paranoid: false }); | |
await entity.restore(); | |
return entity; | |
} | |
async count(options: RepoFetch<TModelAttributes>): Promise<number> { | |
return await this.model.count(options); | |
} | |
async exists(options: RepoFetch<TModelAttributes>): Promise<boolean> { | |
return (await this.count(options)) > 0; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Model } from 'sequelize-typescript'; | |
import { ICrudRepository, RepoFetch } from './crud-repository.interface'; | |
export interface IPagingRepository< | |
TModelAttributes extends object, | |
TCreationAttributes extends object, | |
TModel extends Model<TModelAttributes, TCreationAttributes> | |
> extends ICrudRepository<TModelAttributes, TCreationAttributes, TModel> { | |
fetchByPage(page: number, pageSize: number): Promise<TModel[]>; | |
fetchByOffset(offset: number, count: number): Promise<TModel[]>; | |
fetchPaginated(page: number, pageSize: number, options: RepoFetch<TModelAttributes>): Promise<TModel[]>; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ModelStatic } from 'sequelize'; | |
import { Model } from 'sequelize-typescript'; | |
import { CrudRepository } from './crud.repository'; | |
import { IPagingRepository, RepoFetch } from './paging-repository.interface'; | |
export abstract class PagingRepository< | |
TModelAttributes extends object, | |
TCreationAttributes extends object, | |
TModel extends Model<TModelAttributes, TCreationAttributes> | |
> extends CrudRepository<TModelAttributes, TCreationAttributes, TModel> | |
implements IPagingRepository<TModelAttributes, TCreationAttributes, TModel> { | |
constructor(protected readonly model: ModelStatic<TModel>) { | |
super(model); | |
} | |
async fetchByOffset(offset: number, count: number): Promise<TModel[]> { | |
return await super.fetch({ | |
offset, | |
limit: count, | |
}); | |
} | |
async fetchByPage(page: number, pageSize: number): Promise<TModel[]> { | |
return await super.fetch({ | |
offset: page * pageSize, | |
limit: pageSize, | |
}); | |
} | |
async fetchPaginated(page: number, pageSize: number, options: RepoFetch<TModelAttributes>): Promise<TModel[]> { | |
return await super.fetch({ | |
...options, | |
offset: page * pageSize, | |
limit: pageSize, | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment