171 lines
4.3 KiB
TypeScript
171 lines
4.3 KiB
TypeScript
import { Request, Response, Router } from 'express';
|
|
import { http } from '@scode/consts';
|
|
import { KnexCrudOptions } from './KnexCrudOptions';
|
|
import { CrudHandler } from './CrudHandler';
|
|
import { Knex } from './KnexInterface';
|
|
import { HttpHandler } from './HttpHandler';
|
|
|
|
export class KnexCrudHandler extends HttpHandler implements CrudHandler {
|
|
protected table: string;
|
|
protected columns: Array<string>;
|
|
protected options: KnexCrudOptions;
|
|
protected knex: Knex;
|
|
|
|
public constructor (
|
|
table: string,
|
|
columns: Array<string>,
|
|
options: KnexCrudOptions = {}
|
|
) {
|
|
super ();
|
|
this.table = table;
|
|
this.columns = columns;
|
|
this.options = options;
|
|
if (this.columns.filter ((val) => val.toLowerCase () === 'id').length > 0) {
|
|
throw new Error (
|
|
'the column id cannot be made available to modification'
|
|
);
|
|
}
|
|
}
|
|
|
|
protected validate_body (
|
|
req: Request,
|
|
res: Response
|
|
): Promise<object> | object {
|
|
if (typeof req.body === 'undefined') {
|
|
res.status (http.status_bad_request);
|
|
res.end ('body was undefined');
|
|
return null;
|
|
}
|
|
try {
|
|
return JSON.parse (req.body);
|
|
}
|
|
catch (e) {
|
|
res.status (http.status_bad_request);
|
|
res.end ('invalid json input');
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected ensure_data (
|
|
data: object,
|
|
res: Response,
|
|
fail_on_undef = true
|
|
): Promise<object>|object {
|
|
const obj = {};
|
|
const keys = Object.keys (data);
|
|
for (const col of this.columns) {
|
|
if (!keys.includes (col) && fail_on_undef) {
|
|
res.status (http.status_bad_request)
|
|
.end (`missing field: ${col}`);
|
|
return null;
|
|
}
|
|
obj[col] = data[col];
|
|
}
|
|
for (const col of this.options.optional_columns)
|
|
obj[col] = data[col];
|
|
|
|
return obj;
|
|
}
|
|
|
|
public async create (req: Request, res: Response): Promise<void> {
|
|
if (!await this.options.create_authorization (req, res))
|
|
return;
|
|
|
|
const body_data = await this.validate_body (req, res);
|
|
if (body_data === null)
|
|
return;
|
|
|
|
const db_data = await this.ensure_data (body_data, res);
|
|
if (db_data === null)
|
|
return;
|
|
|
|
const inserted = await this.knex (this.table)
|
|
.returning ('id')
|
|
.insert (db_data);
|
|
|
|
res.status (http.status_created)
|
|
.end (inserted[0]);
|
|
}
|
|
|
|
public async read (req: Request, res: Response): Promise<void> {
|
|
if (!await this.options.read_authorization (req, res))
|
|
return;
|
|
|
|
if (typeof req.headers.id === 'undefined') {
|
|
res.status (http.status_bad_request)
|
|
.end ('id undefined');
|
|
return;
|
|
}
|
|
|
|
const json = await this.knex (this.table)
|
|
.select ([
|
|
'id',
|
|
...this.columns
|
|
])
|
|
.where ({ id: req.headers.id });
|
|
|
|
res.status (json.length > 0 ? http.status_ok : http.status_not_found)
|
|
.json (json[0]);
|
|
}
|
|
|
|
public async update (req: Request, res: Response): Promise<void> {
|
|
if (!await this.options.update_authorization (req, res))
|
|
return;
|
|
|
|
const body_data = await this.validate_body (req, res);
|
|
if (body_data === null)
|
|
return;
|
|
|
|
const db_data = await this.ensure_data (body_data, res, false);
|
|
if (db_data === null)
|
|
return;
|
|
|
|
if (typeof req.headers.id === 'undefined') {
|
|
res.status (http.status_bad_request)
|
|
.end ('id undefined');
|
|
return;
|
|
}
|
|
|
|
await this.knex (this.table)
|
|
.where ({ id: req.headers.id })
|
|
.update (db_data);
|
|
|
|
res.status (http.status_ok)
|
|
.end (inserted[0]);
|
|
}
|
|
|
|
public async delete (req: Request, res: Response): Promise<void> {
|
|
if (!await this.options.delete_authorization (req, res))
|
|
return;
|
|
|
|
if (typeof req.headers.id === 'undefined') {
|
|
res.status (http.status_bad_request)
|
|
.end ('id undefined');
|
|
return;
|
|
}
|
|
|
|
await this.knex (this.table)
|
|
.where ({ id: req.headers.id })
|
|
.delete ();
|
|
|
|
res.status (http.status_ok)
|
|
.end ();
|
|
}
|
|
|
|
protected async create_or_update (
|
|
req: Request,
|
|
res: Response
|
|
): Promise<void> {
|
|
if (typeof req.headers.id === 'undefined')
|
|
await this.create (req, res);
|
|
else
|
|
await this.update (req, res);
|
|
}
|
|
|
|
public register_handlers (router: Router): void {
|
|
router.post ('/', this.create_or_update);
|
|
router.get ('/', this.read);
|
|
router.delete ('/', this.delete);
|
|
}
|
|
}
|