317 lines
8.0 KiB
TypeScript
317 lines
8.0 KiB
TypeScript
// @ts-nocheck
|
|
import { type Knex } from 'knex'
|
|
import _ from 'lodash'
|
|
|
|
import { where } from './knex_helpers.ts'
|
|
|
|
type QueryName =
|
|
| 'create'
|
|
| 'createMany'
|
|
| 'find'
|
|
| 'findOne'
|
|
| 'findById'
|
|
| 'getAll'
|
|
| 'paginate'
|
|
| 'remove'
|
|
| 'removeById'
|
|
| 'replace'
|
|
| 'update'
|
|
|
|
interface Options {
|
|
knex: Knex
|
|
emitter?: ANY
|
|
pick?: QueryName[]
|
|
omit?: QueryName[]
|
|
columns: string[]
|
|
table: string
|
|
selects?: Record<string, ANY>
|
|
}
|
|
|
|
export const count = ({ knex, table, columns }: Pick<Options, 'knex' | 'table' | 'columns'>) =>
|
|
function count(query: Record<string, ANY>, client = knex) {
|
|
let builder = client.table(table)
|
|
|
|
if (!_.isEmpty(query)) {
|
|
builder = where(builder, _.pick(query, columns))
|
|
}
|
|
|
|
return builder.count().then((count) => parseInt(count[0].count, 10))
|
|
}
|
|
|
|
export const create = ({ knex, table, columns, emitter }: Pick<Options, 'knex' | 'table' | 'columns' | 'emitter'>) =>
|
|
function create(json, client = knex) {
|
|
return client
|
|
.table(table)
|
|
.insert(_.pickBy(json, (value, key) => value !== undefined && columns.includes(key)))
|
|
.returning('*')
|
|
.then((result) => {
|
|
if (emitter) {
|
|
emitter.emit('db', { table, action: 'create', result })
|
|
}
|
|
|
|
return result[0]
|
|
})
|
|
}
|
|
|
|
export const createMany = ({
|
|
knex,
|
|
table,
|
|
columns,
|
|
emitter,
|
|
}: Pick<Options, 'knex' | 'table' | 'columns' | 'emitter'>) =>
|
|
function createMany(collection, client = knex) {
|
|
if (!Array.isArray(collection)) {
|
|
collection = [collection]
|
|
}
|
|
|
|
const values = collection.map((item) =>
|
|
_.pickBy(item, (value, key) => value !== undefined && columns.includes(key)),
|
|
)
|
|
|
|
return client
|
|
.table(table)
|
|
.insert(values)
|
|
.returning('*')
|
|
.then((result) => {
|
|
if (emitter) {
|
|
emitter.emit('db', { table, action: 'create', result })
|
|
}
|
|
|
|
return result
|
|
})
|
|
}
|
|
|
|
export const find = ({
|
|
knex,
|
|
table,
|
|
columns,
|
|
allSelects,
|
|
defaults = {},
|
|
}: Pick<Options, 'knex' | 'table' | 'columns'> & { allSelects: string[]; defaults: Record<string, any> }) =>
|
|
function find(json, select, client: Knex) {
|
|
if (!client) {
|
|
// TODO figure out if better, eg instanceof, check is possible
|
|
if (select && select.andWhereNotBetween) {
|
|
client = select
|
|
select = null
|
|
} else {
|
|
client = knex
|
|
}
|
|
}
|
|
|
|
const { offset = defaults.offset, limit = defaults.limit, sort = defaults.sort, ...query } = json
|
|
|
|
let builder = client.table(table).select(select ? _.pick(allSelects, select) : allSelects)
|
|
|
|
if (!_.isEmpty(query)) {
|
|
builder = where(builder, _.pick(query, columns))
|
|
}
|
|
|
|
builder = builder.orderBy(sort || 'id', sort?.startsWith('-') ? 'desc' : 'asc')
|
|
|
|
if (limit) {
|
|
builder = builder.limit(limit)
|
|
}
|
|
|
|
if (offset) {
|
|
builder = builder.offset(offset)
|
|
}
|
|
|
|
return builder
|
|
}
|
|
|
|
export const findById = ({ knex, table, allSelects }: Pick<Options, 'knex' | 'table'> & { allSelects: string[] }) =>
|
|
function findById(id: number | string, select, client: Knex) {
|
|
if (!client) {
|
|
// TODO figure out if better, eg instanceof, check is possible
|
|
if (select && select.andWhereNotBetween) {
|
|
client = select
|
|
select = null
|
|
} else {
|
|
client = knex
|
|
}
|
|
}
|
|
|
|
return client
|
|
.table(table)
|
|
.first(select ? _.pick(allSelects, select) : allSelects)
|
|
.where('id', id)
|
|
}
|
|
|
|
export const findOne = ({
|
|
knex,
|
|
table,
|
|
columns,
|
|
allSelects,
|
|
}: Pick<Options, 'knex' | 'table' | 'columns'> & { allSelects: string[] }) =>
|
|
function findOne(query, select, client: Knex) {
|
|
if (!client) {
|
|
// TODO figure out if better, eg instanceof, check is possible
|
|
if (select && select.andWhereNotBetween) {
|
|
client = select
|
|
select = null
|
|
} else {
|
|
client = knex
|
|
}
|
|
}
|
|
|
|
let builder = client.table(table).first(select ? _.pick(allSelects, select) : allSelects)
|
|
|
|
if (!_.isEmpty(query)) {
|
|
builder = where(builder, _.pick(query, columns))
|
|
}
|
|
|
|
if (query?.sort) {
|
|
builder = builder.orderBy(query.sort)
|
|
}
|
|
|
|
return builder
|
|
}
|
|
|
|
export const getAll = ({ knex, table, allSelects }: Pick<Options, 'knex' | 'table'> & { allSelects: string[] }) =>
|
|
function getAll(select, client: Knex) {
|
|
if (!client) {
|
|
// TODO figure out if better, eg instanceof, check is possible
|
|
if (select && select.andWhereNotBetween) {
|
|
client = select
|
|
select = null
|
|
} else {
|
|
client = knex
|
|
}
|
|
}
|
|
|
|
return client.table(table).select(select ? _.pick(allSelects, select) : allSelects)
|
|
}
|
|
|
|
export const remove = ({ knex, table, columns, emitter }: Pick<Options, 'knex' | 'table' | 'columns' | 'emitter'>) =>
|
|
function remove(query, client = knex) {
|
|
let builder = client.table(table).delete()
|
|
|
|
if (!_.isEmpty(query)) {
|
|
builder = where(builder, _.pick(query, columns))
|
|
}
|
|
|
|
return builder.then((result) => {
|
|
if (emitter) {
|
|
emitter.emit('db', { table, action: 'delete', result })
|
|
}
|
|
|
|
return result
|
|
})
|
|
}
|
|
|
|
export const removeById = ({ knex, table, emitter }: Pick<Options, 'knex' | 'table' | 'emitter'>) =>
|
|
function removeById(id: number | string, client = knex) {
|
|
return client
|
|
.table(table)
|
|
.delete()
|
|
.where('id', id)
|
|
.then((result) => {
|
|
if (emitter) {
|
|
emitter.emit('db', { table, action: 'delete', result })
|
|
}
|
|
|
|
return result
|
|
})
|
|
}
|
|
|
|
// should be used with PUT
|
|
export const replace = ({ knex, table, columns, emitter }: Pick<Options, 'knex' | 'table' | 'columns' | 'emitter'>) =>
|
|
function replace(id: number | string, object, client = knex) {
|
|
object = columns.reduce((result, key) => {
|
|
const value = object[key]
|
|
|
|
result[columns[key]] = value === undefined ? null : value
|
|
|
|
return result
|
|
}, {})
|
|
|
|
return client
|
|
.table(table)
|
|
.update(object)
|
|
.where('id', id)
|
|
.returning('*')
|
|
.then((result) => {
|
|
if (result.length === 0) return null
|
|
|
|
if (emitter) {
|
|
emitter.emit('db', { table, action: 'update', result })
|
|
}
|
|
|
|
return result[0]
|
|
})
|
|
}
|
|
|
|
// should be used with PATCH
|
|
export const update = ({ knex, table, columns, emitter }: Pick<Options, 'knex' | 'table' | 'columns' | 'emitter'>) =>
|
|
function update(id: number | string, object: Record<string, any>, client = knex) {
|
|
object = _.pickBy(object, (value, key) => value !== undefined && columns.includes(key))
|
|
|
|
if (columns.includes('modifiedAt')) {
|
|
object.modifiedAt = knex.fn.now()
|
|
}
|
|
|
|
return client
|
|
.table(table)
|
|
.update(object)
|
|
.where('id', id)
|
|
.returning('*')
|
|
.then((result) => {
|
|
if (result.length === 0) return null
|
|
|
|
if (emitter) {
|
|
emitter.emit('db', { table, action: 'update', result })
|
|
}
|
|
|
|
return result[0]
|
|
})
|
|
}
|
|
|
|
export const updateMany = ({ knex, table, emitter }: Pick<Options, 'knex' | 'table' | 'emitter'>) =>
|
|
function updateMany(query, object, client = knex) {
|
|
const builder = client.table(table).update(typeof object === 'function' ? object(knex) : object)
|
|
|
|
return where(builder, query)
|
|
.returning('*')
|
|
.then((result) => {
|
|
if (result.length === 0) return null
|
|
|
|
if (emitter) {
|
|
emitter.emit('db', { table, action: 'update', result })
|
|
}
|
|
|
|
return result[0]
|
|
})
|
|
}
|
|
|
|
const factories = {
|
|
count,
|
|
create,
|
|
createMany,
|
|
find,
|
|
findOne,
|
|
findById,
|
|
getAll,
|
|
remove,
|
|
removeById,
|
|
replace,
|
|
update,
|
|
updateMany,
|
|
}
|
|
|
|
const queryNames = Object.keys(factories)
|
|
|
|
export default function restQueriesFactory({ knex, emitter, table, columns, selects, omit, pick }: Options) {
|
|
const allSelects = selects ? [...columns, selects] : columns
|
|
|
|
pick = pick || (_.difference(queryNames, omit || []) as QueryName[])
|
|
|
|
return pick.reduce((result, value) => {
|
|
if (factories[value]) {
|
|
result[value] = factories[value]({ columns, selects, allSelects, knex, emitter, table })
|
|
}
|
|
|
|
return result
|
|
}, {}) as Record<QueryName, (...args: any) => Promise<ANY>>
|
|
}
|