Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { Injectable } from '@nestjs/common'
- import sequelize, {
- FindOptions,
- Transaction,
- TransactionOptions,
- Optional,
- WhereOptions,
- Includeable,
- Op,
- IncludeOptions,
- CreateOptions,
- UpdateOptions,
- DestroyOptions,
- FindAttributeOptions,
- } from 'sequelize'
- import { Repository, Sequelize, Model } from 'sequelize-typescript'
- import { MakeNullishOptional, NullishPropertiesOf } from 'sequelize/lib/utils'
- import { EPGRelationAction } from '~/domain/enums/common.enum'
- export { InjectModel as InjectRepository } from '@nestjs/sequelize'
- export { Repository } from 'sequelize-typescript'
- import { response } from '~/infrastructure/common/helpers/response.helper'
- /**
- * A service for handling Sequelize transactions and common operations.
- */
- @Injectable()
- export class SequelizeService {
- constructor(private sequelize: Sequelize) {}
- /**
- * Executes a database transaction.
- * @param operation The operation to perform within the transaction.
- * @param options Transaction options.
- * @returns The result of the operation, or null if an error occurs.
- */
- async transaction<T = any>(
- operation: (transaction: Transaction) => Promise<T>,
- options?: TransactionOptions,
- ): Promise<T | null> {
- try {
- const transaction = await this.sequelize.transaction({ autocommit: false, ...options })
- try {
- const result: T = await operation(transaction)
- await transaction.commit()
- return result
- } catch (e: any) {
- await transaction.rollback()
- response(e) // Assuming response logs or handles the error
- return null
- }
- } catch (e: any) {
- response(e)
- return null
- }
- }
- /**
- * Finds a record and updates it if found.
- * @param repository The repository to use.
- * @param data The data to update the record with.
- * @param options The find options.
- * @returns The updated record's data values, or null if not found or an error occurs.
- */
- async findOneAndUpdate<T = any>(
- repository: Repository<Model<T, T>>,
- data: Optional<T, NullishPropertiesOf<T>>,
- options: FindOptions<T>,
- ): Promise<T | null> {
- try {
- const repositoryModel: Model<T, T> | null = await repository.findOne(options)
- if (!repositoryModel) return null
- repositoryModel.set(data) // Use set for safer attribute updates
- const updatedModel = await repositoryModel.save(options)
- return updatedModel?.dataValues || null
- } catch (e: any) {
- response(e)
- return null
- }
- }
- }
- /**
- * A fluent query builder for constructing Sequelize queries.
- */
- export class SequelizeQueryBuilder<M extends Model> {
- private model: Repository<M>
- private options: FindOptions<M>
- constructor(model: Repository<M>) {
- this.model = model
- this.options = { where: {}, attributes: { include: [], exclude: [] } }
- }
- /**
- * Specifies columns to include or exclude in the query.
- * @param columns Columns to select.
- */
- select(columns: FindAttributeOptions): this {
- this.options.attributes = columns
- return this
- }
- /**
- * Sets the WHERE condition for the query.
- * @param condition The where condition.
- */
- where(condition: WhereOptions<M>): this {
- this.options.where = condition
- return this
- }
- /**
- * Adds an AND condition to the existing WHERE clause.
- * @param condition The condition to add.
- */
- andWhere(condition: WhereOptions<M>): this {
- if (!this.options.where) {
- this.options.where = {}
- }
- Object.assign(this.options.where, condition)
- return this
- }
- /**
- * Adds an OR condition to the existing WHERE clause.
- * @param condition The condition to add.
- */
- orWhere(condition: WhereOptions<M>): this {
- if (!this.options.where[Op.or]) {
- this.options.where[Op.or] = []
- }
- this.options.where[Op.or].push(condition)
- return this
- }
- /**
- * Adds an OR WHERE IN condition.
- * @param field The field to check.
- * @param values The values to match.
- */
- orWhereIn<T = any>(field: keyof M, values: T[]): this {
- if (!this.options.where[Op.or]) {
- this.options.where[Op.or] = []
- }
- this.options.where[Op.or].push({ [field]: { [Op.in]: values } })
- return this
- }
- /**
- * Adds an AND WHERE IN condition.
- * @param field The field to check.
- * @param values The values to match.
- */
- andWhereIn<T = any>(field: keyof M, values: T[]): this {
- this.options.where[String(field)] = { [Op.in]: values }
- return this
- }
- /**
- * Adds a NOT condition to the WHERE clause.
- * @param condition The condition to negate.
- */
- whereNot(condition: WhereOptions<M>): this {
- this.options.where[Op.not] = condition
- return this
- }
- /**
- * Adds a WHERE NOT IN condition.
- * @param field The field to check.
- * @param values The values to exclude.
- */
- whereNotIn<T = any>(field: keyof M, values: T[]): this {
- this.options.where[String(field)] = { [Op.notIn]: values }
- return this
- }
- /**
- * Adds a WHERE IN condition.
- * @param field The field to check.
- * @param values The values to match.
- */
- whereIn<T = any>(field: keyof M, values: T[]): this {
- this.options.where[String(field)] = { [Op.in]: values }
- return this
- }
- /**
- * Sets the order of the results.
- * @param field The field to order by.
- * @param direction The sort direction (ASC or DESC).
- */
- orderBy(field: keyof M, direction: 'ASC' | 'DESC' = 'ASC'): this {
- this.options.order = [[String(field), direction]]
- return this
- }
- /**
- * Limits the number of results.
- * @param limit The maximum number of records to return.
- */
- limit(limit: number): this {
- this.options.limit = limit
- return this
- }
- /**
- * Sets the offset for pagination.
- * @param offset The number of records to skip.
- */
- offset(offset: number): this {
- this.options.offset = offset
- return this
- }
- /**
- * Includes related models (eager loading).
- * @param include The relations to include.
- */
- include(include: Includeable | Includeable[]): this {
- this.options.include = Array.isArray(include) ? include : [include]
- return this
- }
- /**
- * Configures a join with specified action (INNER, LEFT, RIGHT).
- * @param options The include options for the join.
- * @param action The type of join.
- * @param alias Optional alias for the relation.
- */
- join(options: IncludeOptions | IncludeOptions[], action: EPGRelationAction, alias?: string): this {
- if (Array.isArray(options)) {
- options = options.map((option: IncludeOptions) => {
- if (alias) option.as = alias
- if (action === EPGRelationAction.INNER) option.required = true
- else if (action === EPGRelationAction.LEFT) option.required = false
- else if (action === EPGRelationAction.RIGH) {
- option.required = true
- option.right = true
- }
- return option
- })
- } else {
- if (alias) options.as = alias
- if (action === EPGRelationAction.INNER) options.required = true
- else if (action === EPGRelationAction.LEFT) options.required = false
- else if (action === EPGRelationAction.RIGH) {
- options.required = true
- options.right = true
- }
- }
- this.include(options)
- return this
- }
- /**
- * Inserts a new record.
- * @param values The data to insert.
- * @param options Creation options.
- */
- insert(values: MakeNullishOptional<M>, options?: CreateOptions): Promise<M> {
- return this.model.create(values, options)
- }
- /**
- * Updates records matching the query.
- * @param values The data to update.
- * @param options Update options.
- */
- update(
- values: Partial<M>,
- options?: UpdateOptions & { returning?: boolean | Array<keyof M> },
- ): Promise<[number, M[]]> {
- return this.model.update(values, { ...options, where: this.options.where, returning: options?.returning || true })
- }
- /**
- * Deletes records matching the query.
- * @param options Destroy options.
- */
- delete(options?: DestroyOptions & { returning?: boolean | Array<keyof M> }): Promise<number> {
- return this.model.destroy({ ...options, where: this.options.where })
- }
- /**
- * Adds a LIKE condition.
- * @param field The field to match.
- * @param value The pattern to search for.
- */
- like(field: keyof M, value: string): this {
- this.options.where = sequelize.where(sequelize.literal(`${String(field)}::text`), {
- [Op.iLike]: `%${value}%`,
- })
- return this
- }
- /**
- * Adds an OR LIKE condition.
- * @param field The field to match.
- * @param value The pattern to search for.
- */
- orLike(field: keyof M, value: string): this {
- if (!this.options.where[Op.or]) this.options.where[Op.or] = []
- this.options.where[Op.or].push(
- sequelize.where(sequelize.literal(`${String(field)}::text`), { [Op.iLike]: `%${value}%` }),
- )
- return this
- }
- /**
- * Adds an AND LIKE condition.
- * @param field The field to match.
- * @param value The pattern to search for.
- */
- andLike(field: keyof M, value: string): this {
- if (!this.options.where) this.options.where = {}
- this.options.where = sequelize.where(sequelize.literal(`${String(field)}::text`), {
- [Op.iLike]: `%${value}%`,
- })
- return this
- }
- /**
- * Retrieves one record matching the query.
- */
- getOne(): Promise<M | null> {
- return this.model.findOne({ ...this.options, raw: false })
- }
- /**
- * Retrieves all records matching the query.
- */
- getMany(): Promise<M[]> {
- return this.model.findAll({ ...this.options, raw: false })
- }
- /**
- * Retrieves one raw record matching the query.
- */
- getOneRaw(): Promise<M | null> {
- return this.model.findOne({ ...this.options, raw: true })
- }
- /**
- * Retrieves all raw records matching the query.
- */
- getManyRaw(): Promise<M[]> {
- return this.model.findAll({ ...this.options, raw: true })
- }
- /**
- * Counts the number of records matching the query.
- */
- getCount(): Promise<number> {
- delete this.options.attributes
- return this.model.count(this.options)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement