2021-06-14 20:07:13 +02:00
|
|
|
const { DataSourceOperation, SortDirection } = require("../../constants")
|
2021-06-03 17:31:24 +02:00
|
|
|
|
|
|
|
const BASE_LIMIT = 5000
|
|
|
|
|
|
|
|
function addFilters(query, filters) {
|
|
|
|
function iterate(structure, fn) {
|
|
|
|
for (let [key, value] of Object.entries(structure)) {
|
|
|
|
fn(key, value)
|
|
|
|
}
|
|
|
|
}
|
2021-06-04 16:16:15 +02:00
|
|
|
if (!filters) {
|
|
|
|
return query
|
|
|
|
}
|
2021-06-15 14:50:41 +02:00
|
|
|
// if all or specified in filters, then everything is an or
|
|
|
|
const allOr = !!filters.allOr
|
2021-06-03 17:31:24 +02:00
|
|
|
if (filters.string) {
|
|
|
|
iterate(filters.string, (key, value) => {
|
2021-06-15 14:03:55 +02:00
|
|
|
const fnc = allOr ? "orWhere" : "where"
|
|
|
|
query = query[fnc](key, "like", `${value}%`)
|
2021-06-03 17:31:24 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
if (filters.range) {
|
|
|
|
iterate(filters.range, (key, value) => {
|
|
|
|
if (!value.high || !value.low) {
|
|
|
|
return
|
|
|
|
}
|
2021-06-15 14:03:55 +02:00
|
|
|
const fnc = allOr ? "orWhereBetween" : "whereBetween"
|
|
|
|
query = query[fnc](key, [value.low, value.high])
|
2021-06-03 17:31:24 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
if (filters.equal) {
|
|
|
|
iterate(filters.equal, (key, value) => {
|
2021-06-15 14:03:55 +02:00
|
|
|
const fnc = allOr ? "orWhere" : "where"
|
|
|
|
query = query[fnc]({ [key]: value })
|
2021-06-03 17:31:24 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
if (filters.notEqual) {
|
|
|
|
iterate(filters.notEqual, (key, value) => {
|
2021-06-15 14:03:55 +02:00
|
|
|
const fnc = allOr ? "orWhereNot" : "whereNot"
|
|
|
|
query = query[fnc]({ [key]: value })
|
2021-06-03 17:31:24 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
if (filters.empty) {
|
|
|
|
iterate(filters.empty, key => {
|
2021-06-15 14:03:55 +02:00
|
|
|
const fnc = allOr ? "orWhereNull" : "whereNull"
|
|
|
|
query = query[fnc](key)
|
2021-06-03 17:31:24 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
if (filters.notEmpty) {
|
|
|
|
iterate(filters.notEmpty, key => {
|
2021-06-15 14:03:55 +02:00
|
|
|
const fnc = allOr ? "orWhereNotNull" : "whereNotNull"
|
|
|
|
query = query[fnc](key)
|
2021-06-03 17:31:24 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return query
|
|
|
|
}
|
|
|
|
|
2021-06-14 20:07:13 +02:00
|
|
|
function buildRelationships() {}
|
2021-06-11 19:56:30 +02:00
|
|
|
|
2021-06-03 17:31:24 +02:00
|
|
|
function buildCreate(knex, json) {
|
|
|
|
const { endpoint, body } = json
|
|
|
|
let query = knex(endpoint.entityId)
|
2021-06-03 18:45:19 +02:00
|
|
|
return query.insert(body)
|
2021-06-03 17:31:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function buildRead(knex, json, limit) {
|
|
|
|
const { endpoint, resource, filters, sort, paginate } = json
|
|
|
|
let query = knex(endpoint.entityId)
|
|
|
|
// handle select
|
|
|
|
if (resource.fields && resource.fields.length > 0) {
|
|
|
|
query = query.select(resource.fields)
|
|
|
|
} else {
|
|
|
|
query = query.select("*")
|
|
|
|
}
|
|
|
|
// handle where
|
|
|
|
query = addFilters(query, filters)
|
|
|
|
// handle sorting
|
|
|
|
if (sort) {
|
|
|
|
for (let [key, value] of Object.entries(sort)) {
|
|
|
|
const direction = value === SortDirection.ASCENDING ? "asc" : "desc"
|
|
|
|
query = query.orderBy(key, direction)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// handle pagination
|
2021-06-04 16:16:15 +02:00
|
|
|
if (paginate && paginate.page && paginate.limit) {
|
2021-06-03 17:31:24 +02:00
|
|
|
const page = paginate.page <= 1 ? 0 : paginate.page - 1
|
|
|
|
const offset = page * paginate.limit
|
|
|
|
query = query.offset(offset).limit(paginate.limit)
|
2021-06-04 16:16:15 +02:00
|
|
|
} else if (paginate && paginate.limit) {
|
2021-06-03 17:31:24 +02:00
|
|
|
query = query.limit(paginate.limit)
|
|
|
|
} else {
|
|
|
|
query.limit(limit)
|
|
|
|
}
|
2021-06-03 18:45:19 +02:00
|
|
|
return query
|
2021-06-03 17:31:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function buildUpdate(knex, json) {
|
|
|
|
const { endpoint, body, filters } = json
|
|
|
|
let query = knex(endpoint.entityId)
|
|
|
|
query = addFilters(query, filters)
|
2021-06-03 18:45:19 +02:00
|
|
|
return query.update(body)
|
2021-06-03 17:31:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function buildDelete(knex, json) {
|
|
|
|
const { endpoint, filters } = json
|
|
|
|
let query = knex(endpoint.entityId)
|
|
|
|
query = addFilters(query, filters)
|
2021-06-03 18:45:19 +02:00
|
|
|
return query.delete()
|
2021-06-03 17:31:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
class SqlQueryBuilder {
|
|
|
|
// pass through client to get flavour of SQL
|
|
|
|
constructor(client, limit = BASE_LIMIT) {
|
|
|
|
this._client = client
|
|
|
|
this._limit = limit
|
|
|
|
}
|
|
|
|
|
2021-06-03 19:48:04 +02:00
|
|
|
_operation(json) {
|
|
|
|
if (!json || !json.endpoint) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
return json.endpoint.operation
|
|
|
|
}
|
|
|
|
|
2021-06-03 18:45:19 +02:00
|
|
|
_query(json) {
|
2021-06-03 17:31:24 +02:00
|
|
|
const knex = require("knex")({ client: this._client })
|
2021-06-03 18:45:19 +02:00
|
|
|
let query
|
2021-06-03 19:48:04 +02:00
|
|
|
switch (this._operation(json)) {
|
2021-06-04 15:53:49 +02:00
|
|
|
case DataSourceOperation.CREATE:
|
2021-06-03 18:45:19 +02:00
|
|
|
query = buildCreate(knex, json)
|
|
|
|
break
|
2021-06-04 15:53:49 +02:00
|
|
|
case DataSourceOperation.READ:
|
2021-06-03 18:45:19 +02:00
|
|
|
query = buildRead(knex, json, this._limit)
|
|
|
|
break
|
2021-06-04 15:53:49 +02:00
|
|
|
case DataSourceOperation.UPDATE:
|
2021-06-03 18:45:19 +02:00
|
|
|
query = buildUpdate(knex, json)
|
|
|
|
break
|
2021-06-04 15:53:49 +02:00
|
|
|
case DataSourceOperation.DELETE:
|
2021-06-03 18:45:19 +02:00
|
|
|
query = buildDelete(knex, json)
|
|
|
|
break
|
2021-06-03 17:31:24 +02:00
|
|
|
default:
|
2021-06-04 15:53:49 +02:00
|
|
|
throw `Operation type is not supported by SQL query builder`
|
2021-06-03 17:31:24 +02:00
|
|
|
}
|
2021-06-03 18:45:19 +02:00
|
|
|
return query.toSQL().toNative()
|
2021-06-03 17:31:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = SqlQueryBuilder
|