160 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { Request, Response, Router } from 'express';
 | 
						|
import { http } from '@scode/consts';
 | 
						|
import { ControlModel, DatabaseModel } from '@scode/modelling';
 | 
						|
import { CrudHandler } from './CrudHandler';
 | 
						|
import { HttpHandler } from './HttpHandler';
 | 
						|
import { DatabaseCrudOptionsReader } from './DatabaseCrudOptionsReader';
 | 
						|
 | 
						|
export class DatabaseCrudHandler extends HttpHandler implements CrudHandler {
 | 
						|
  protected cm: new () => ControlModel;
 | 
						|
  protected dm: new () => DatabaseModel;
 | 
						|
  protected options: DatabaseCrudOptionsReader;
 | 
						|
 | 
						|
  public constructor<T extends ControlModel, U extends DatabaseModel> (
 | 
						|
    table: string,
 | 
						|
    cm: new () => ControlModel,
 | 
						|
    dm: new () => DatabaseModel
 | 
						|
  ) {
 | 
						|
    super ();
 | 
						|
    this.cm = cm;
 | 
						|
    this.dm = dm;
 | 
						|
    this.options = new DatabaseCrudOptionsReader (options);
 | 
						|
  }
 | 
						|
 | 
						|
  protected validate_body (
 | 
						|
    req: Request,
 | 
						|
    res: Response
 | 
						|
  ): Promise<Record<string, unknown>> | Record<string, unknown> {
 | 
						|
    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;
 | 
						|
  }
 | 
						|
 | 
						|
  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 cm = new this.cm;
 | 
						|
    cm.object = body_data;
 | 
						|
    cm.update ();
 | 
						|
 | 
						|
    const dm = new this.dm;
 | 
						|
    for (const key of Object.keys (body_data))
 | 
						|
      dm.set (key, cm.get (key));
 | 
						|
    await dm.write ();
 | 
						|
 | 
						|
    res.status (http.status_created)
 | 
						|
      .end (dm.id);
 | 
						|
  }
 | 
						|
 | 
						|
  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 dm = new this.dm (req.headers.id);
 | 
						|
    const found = await dm.read ();
 | 
						|
 | 
						|
    const cm = new this.cm (dm.object);
 | 
						|
    cm.update ();
 | 
						|
 | 
						|
    res.status (found ? http.status_ok : http.status_not_found)
 | 
						|
      .json (cm.object);
 | 
						|
  }
 | 
						|
 | 
						|
  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;
 | 
						|
 | 
						|
    if (typeof req.headers.id === 'undefined') {
 | 
						|
      res.status (http.status_bad_request)
 | 
						|
        .end ('id undefined');
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    const dm = new this.dm (req.headers.id);
 | 
						|
    const found = await dm.read ();
 | 
						|
    if (!found) {
 | 
						|
      res.status (http.status_not_found)
 | 
						|
        .end ();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    const cm = new this.cm (dm.object);
 | 
						|
    cm.update ();
 | 
						|
 | 
						|
    for (const key of Object.keys (body_data))
 | 
						|
      cm.set (key, body_data[key]);
 | 
						|
    cm.update ();
 | 
						|
 | 
						|
    dm.object = cm.object;
 | 
						|
    const written = await dm.write ();
 | 
						|
 | 
						|
    res.status (written ? http.status_ok : http.status_internal_server_error)
 | 
						|
      .end ();
 | 
						|
  }
 | 
						|
 | 
						|
  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;
 | 
						|
    }
 | 
						|
 | 
						|
    const dm = new this.dm (req.headers.id);
 | 
						|
    const found = await dm.read ();
 | 
						|
    if (!found) {
 | 
						|
      res.status (http.status_not_found)
 | 
						|
        .end ();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    const deleted = await dm.delete ();
 | 
						|
 | 
						|
    res.status (deleted ? http.status_ok : http.status_internal_server_error)
 | 
						|
      .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);
 | 
						|
  }
 | 
						|
}
 |