This repository has been archived on 2020-08-13. You can view files and clone it, but cannot push or open issues or pull requests.
requestor/lib/KnexCrudHandler.ts
2020-04-17 11:03:15 +02:00

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);
}
}