382 lines
12 KiB
TypeScript
382 lines
12 KiB
TypeScript
import { DateTime } from "luxon"
|
|
|
|
export default class BaseRepository {
|
|
protected model: any
|
|
protected mainModel: any
|
|
protected isSoftDelete: boolean
|
|
protected RELATIONS: string[]
|
|
protected RELATION_OPTIONS: any
|
|
|
|
constructor(model: any) {
|
|
this.model = model
|
|
this.mainModel = model
|
|
this.isSoftDelete = model.softDelete
|
|
}
|
|
|
|
async getAll(pagination: any, sort: any, whereClauses: any, fields: any, search: any) {
|
|
try {
|
|
this.model = this.mainModel
|
|
this.model = this.model.query()
|
|
this.model = this.parseSelectedFields(this.model, fields)
|
|
this.model = this.parseWhere(this.model, whereClauses)
|
|
this.model = this.parseSearch(this.model, whereClauses, search)
|
|
this.model = this.parseRelation(this.model)
|
|
this.model = this.parseSort(this.model, sort)
|
|
if (pagination.page && pagination.limit) {
|
|
if (this.isSoftDelete) {
|
|
return await this.model.whereNull('deleted_at').paginate(pagination.page, pagination.limit)
|
|
}
|
|
return await this.model.paginate(pagination.page, pagination.limit)
|
|
} else {
|
|
if (this.isSoftDelete) {
|
|
return await this.model.whereNull('deleted_at')
|
|
}
|
|
return await this.model
|
|
}
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async get(data: any = {}) {
|
|
try {
|
|
this.model = this.mainModel
|
|
this.model = this.model.query()
|
|
if (this.isSoftDelete) {
|
|
this.model = this.model.whereNull('deleted_at')
|
|
}
|
|
if (data.sort) {
|
|
this.model = this.parseSort(this.model, data.sort)
|
|
}
|
|
return await this.model
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async store(data: any) {
|
|
try {
|
|
this.model = this.mainModel
|
|
return await this.model.create(data)
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async multiInsert(data: any[]) {
|
|
try {
|
|
this.model = this.mainModel
|
|
return await this.model.createMany(data)
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async show(id: any, fields: any) {
|
|
try {
|
|
this.model = this.mainModel
|
|
this.model = this.model.query().where(this.model.primaryKey, id)
|
|
this.model = this.parseSelectedFields(this.model, fields)
|
|
this.model = this.parseRelation(this.model)
|
|
if (this.isSoftDelete) {
|
|
this.model = this.model.whereNull('deleted_at')
|
|
}
|
|
return await this.model.first()
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async update(id: any, data: any) {
|
|
try {
|
|
this.model = this.mainModel
|
|
if (! await this.model.find(id)) {
|
|
return null
|
|
}
|
|
data.updated_at = DateTime.now()
|
|
if (Object.keys(data).length) {
|
|
await this.model.query().where(this.model.primaryKey, id).update(data)
|
|
}
|
|
return await this.model.find(id)
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async delete(id: any) {
|
|
try {
|
|
this.model = this.mainModel
|
|
const result = await this.model.find(id)
|
|
if (this.isSoftDelete) {
|
|
await this.model.query().where(this.model.primaryKey, id).update({ deleted_at: DateTime.local() })
|
|
} else {
|
|
await this.model.query().where(this.model.primaryKey, id).delete()
|
|
}
|
|
return result
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async deleteAll() {
|
|
try {
|
|
this.model = this.mainModel
|
|
if (this.isSoftDelete) {
|
|
return await this.model.query().whereNull('deleted_at').update({ deleted_at: DateTime.local() })
|
|
} else {
|
|
return await this.model.query().delete()
|
|
}
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async first() {
|
|
try {
|
|
this.model = this.mainModel
|
|
this.model = this.model.query()
|
|
if (this.isSoftDelete) {
|
|
this.model = this.model.whereNull('deleted_at')
|
|
}
|
|
return await this.model.first()
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async find(id: any) {
|
|
try {
|
|
this.model = this.mainModel
|
|
this.model = this.model.query().where(this.model.primaryKey, id)
|
|
if (this.isSoftDelete) {
|
|
this.model = this.model.whereNull('deleted_at')
|
|
}
|
|
return await this.model.first()
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
setRelation(relation: string[]) {
|
|
this.RELATIONS = relation
|
|
}
|
|
|
|
setRelationOptions(relationOptions: any) {
|
|
this.RELATION_OPTIONS = relationOptions
|
|
}
|
|
|
|
parseSelectedFields(model: any, fields: any) {
|
|
if (fields) {
|
|
model = model.select(fields)
|
|
}
|
|
return model
|
|
}
|
|
|
|
parseWhere(model: any, whereClauses: any) {
|
|
if (whereClauses.data) {
|
|
if (whereClauses.operation == 'and') {
|
|
whereClauses.data.forEach((whereClause: any) => {
|
|
if (whereClause.operator == 'between') {
|
|
model = model.whereBetween(whereClause.attribute, whereClause.value)
|
|
} else {
|
|
if (whereClause.value == 'null') {
|
|
model = model.whereNull(whereClause.attribute)
|
|
} else {
|
|
if (whereClause.attribute.includes('.')) {
|
|
const attr = whereClause.attribute.split('.')
|
|
model = model.whereHas(attr[0], (builder: any) => {
|
|
builder.where(attr[1], whereClause.operator, whereClause.value)
|
|
})
|
|
} else {
|
|
model = model.where(whereClause.attribute, whereClause.operator, whereClause.value)
|
|
}
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
whereClauses.data.forEach((whereClause: any, index: number) => {
|
|
if (whereClause.operator == 'between') {
|
|
model = model.whereBetween(whereClause.attribute, whereClause.value)
|
|
} else {
|
|
if (index == 0) {
|
|
if (whereClause.value == 'null') {
|
|
model = model.whereNull(whereClause.attribute)
|
|
} else {
|
|
if (whereClause.attribute.includes('.')) {
|
|
const attr = whereClause.attribute.split('.')
|
|
model = model.whereHas(attr[0], (builder: any) => {
|
|
builder.where(attr[1], whereClause.operator, whereClause.value)
|
|
})
|
|
} else {
|
|
model = model.where(whereClause.attribute, whereClause.operator, whereClause.value)
|
|
}
|
|
}
|
|
} else {
|
|
if (whereClause.value == 'null') {
|
|
model = model.orWhereNull(whereClause.attribute)
|
|
} else {
|
|
if (whereClause.attribute.includes('.')) {
|
|
const attr = whereClause.attribute.split('.')
|
|
model = model.orWhereHas(attr[0], (builder: any) => {
|
|
builder.where(attr[1], whereClause.operator, whereClause.value)
|
|
})
|
|
} else {
|
|
model = model.orWhere(whereClause.attribute, whereClause.operator, whereClause.value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
return model
|
|
}
|
|
|
|
parseRelation(model: any) {
|
|
if (this.RELATIONS) {
|
|
this.RELATIONS.forEach((relation) => {
|
|
if (relation.split('.').length > 1) {
|
|
const firstRelation = relation.substr(0, relation.indexOf('.'))
|
|
model = model.preload(firstRelation, (query) => {
|
|
if (this.RELATION_OPTIONS) {
|
|
let relationOption = this.RELATION_OPTIONS.find((item: any) => { return item.relation == firstRelation })
|
|
this.parseRelationOption(query, relationOption)
|
|
}
|
|
this.parseNestedRelation(query, relation.substr(relation.indexOf('.') + 1), firstRelation)
|
|
})
|
|
} else {
|
|
model = model.preload(relation, (query) => {
|
|
if (this.RELATION_OPTIONS) {
|
|
let relationOption = this.RELATION_OPTIONS.find((item: any) => { return item.relation == relation })
|
|
this.parseRelationOption(query, relationOption)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
return model
|
|
}
|
|
|
|
parseNestedRelation(query: any, relation: string, firstRelation: string) {
|
|
let relations = this.RELATIONS.filter(d => { return typeof d == 'string' })
|
|
relations = relations.filter(d => { return d.includes(firstRelation + '.') })
|
|
if (relations.length > 1) {
|
|
relations.map(data => {
|
|
this.parseNestedRelation(query, data.substr(data.indexOf('.') + 1), relation.substr(0, data.indexOf('.')))
|
|
})
|
|
} else {
|
|
if (relation.indexOf('.') > 0) {
|
|
let subRelation = relation.substr(0, relation.indexOf('.'))
|
|
query.preload(subRelation, (subQuery) => {
|
|
if (this.RELATION_OPTIONS) {
|
|
let relationOption = this.RELATION_OPTIONS.find((item: any) => { return item.relation == subRelation })
|
|
this.parseRelationOption(subQuery, relationOption)
|
|
}
|
|
this.parseNestedRelation(subQuery, relation.substr(relation.indexOf('.') + 1), subRelation)
|
|
})
|
|
} else {
|
|
query.preload(relation, (subQuery) => {
|
|
if (this.RELATION_OPTIONS) {
|
|
let relationOption = this.RELATION_OPTIONS.find((item: any) => { return item.relation == relation })
|
|
this.parseRelationOption(subQuery, relationOption)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
parseRelationOption(query: any, relationOption: any) {
|
|
if (relationOption) {
|
|
if (relationOption.fields) {
|
|
query = query.select(relationOption.fields)
|
|
}
|
|
if (relationOption.sort) {
|
|
query = query.orderBy(relationOption.sort, relationOption.order)
|
|
}
|
|
if (relationOption.filter) {
|
|
query = this.parseWhere(query, relationOption.filter)
|
|
}
|
|
if (relationOption.limit) {
|
|
query = query.limit(relationOption.limit)
|
|
}
|
|
if (relationOption.search) {
|
|
query = this.parseSearch(query, relationOption.filter, relationOption.search)
|
|
}
|
|
}
|
|
return query
|
|
}
|
|
|
|
parseSort(model: any, sort: any[]) {
|
|
if (sort) {
|
|
sort.forEach((sort: any) => {
|
|
model = model.orderBy(sort.attribute, sort.order)
|
|
});
|
|
}
|
|
return model
|
|
}
|
|
|
|
parseSearch(model: any, whereClauses: any, search: any) {
|
|
if (search) {
|
|
const data = search.data
|
|
const attributes = search.attributes
|
|
const operator = search.operator
|
|
if (attributes) {
|
|
model = model.where((query) => {
|
|
if (whereClauses.data.length > 0) {
|
|
attributes.forEach((attribute: string) => {
|
|
if (attribute.includes('.')) {
|
|
const attr = attribute.split('.')
|
|
const field = attr[attr.length - 1]
|
|
const relations = attr.slice(0, attr.length - 1)
|
|
query.whereHas(relations[0], (query: any) => {
|
|
this.parseNestedSearch(query, relations.slice(1), field, data, operator)
|
|
})
|
|
} else {
|
|
query.orWhere(attribute, operator, data)
|
|
}
|
|
});
|
|
} else {
|
|
attributes.forEach((attribute: any, index: number) => {
|
|
if (index == 0) {
|
|
if (attribute.includes('.')) {
|
|
const attr = attribute.split('.')
|
|
const field = attr[attr.length - 1]
|
|
const relations = attr.slice(0, attr.length - 1)
|
|
query.whereHas(relations[0], (query: any) => {
|
|
this.parseNestedSearch(query, relations.slice(1), field, data, operator)
|
|
})
|
|
} else {
|
|
query.where(attribute, operator, data)
|
|
}
|
|
} else {
|
|
if (attribute.includes('.')) {
|
|
const attr = attribute.split('.')
|
|
const field = attr[attr.length - 1]
|
|
const relations = attr.slice(0, attr.length - 1)
|
|
query.orWhereHas(relations[0], (query: any) => {
|
|
this.parseNestedSearch(query, relations.slice(1), field, data, operator)
|
|
})
|
|
} else {
|
|
query.orWhere(attribute, operator, data)
|
|
}
|
|
}
|
|
});
|
|
}
|
|
})
|
|
}
|
|
}
|
|
return model
|
|
}
|
|
|
|
parseNestedSearch(model: any, relations: any, field: any, value: any, operator: any = 'ilike') {
|
|
if (relations.length > 0) {
|
|
model = model.whereHas(relations[0], (query: any) => {
|
|
this.parseNestedSearch(query, relations.slice(1), field, value)
|
|
})
|
|
} else {
|
|
model = model.where(field, operator, value)
|
|
}
|
|
return model
|
|
}
|
|
}
|