0.1.3Updated 6 months ago
import { Paginate, PaginationParams } from "@infinity-beyond/modules/pagination.ts";
import { REST_Wrapper } from "@infinity-beyond/classes/rest_wrapper.ts";
import { HandleBody } from "@infinity-beyond/infinity.ts";

import type { Ledger } from "@infinity-ledger/ledger.ts";
import type { LedgerEntry } from "@infinity-ledger/ledger.types/ledger.entry.ts";

export class LedgerRest<EntityName extends string> extends REST_Wrapper {
  constructor(instance: Ledger<EntityName, any>) {
    super();

    this.post('/', async (req, ctx) => {
      const { body, error_response} = await HandleBody<LedgerEntry>(req, (verify, entry) => {
        verify(!!entry.key).fail('[key] not provided');
        verify(typeof entry.amount == 'number').fail('[amount] must be a number');
        verify(entry.source?.length > 0).fail('[source] must be a string, and have a value');
      });
  
      if(error_response) return error_response;
  
      const response = await instance.ConsumeEntries({
        key: body.key,
        amount: body.amount,
        source: body.source,
        description: body.description,
        reference: body.reference,
        request_id: ctx.state.request.request_id
      });

      return Response.json(response, { status: response.success ? 200 : 400 });
    });

    this.get('/:key', async (req, ctx) => {
      const key = ctx.params.key;

      const { page, page_size } = PaginationParams(req);

      const {
        balance = 0,
        entry_count: total_entries = 0,
        history: entries = [],
      } = await instance.UserData(key, page_size, page) ?? {};

      return Response.json(Paginate(req, entries, total_entries, { balance, total_entries }));
    });

    this.post('/:key', async (req, ctx) => {
      const { body, error_response} = await HandleBody<LedgerEntry>(req, (verify, entry) => {
        verify(typeof entry.amount == 'number').fail('[amount] must be a number');
        verify(entry.source?.length > 0).fail('[source] must be a string, and have a value');
      });
  
      if(error_response) return error_response;
  
      const response = await instance.ConsumeEntries({
        key: ctx.params.key,
        amount: body.amount,
        source: body.source,
        description: body.description,
        reference: body.reference,
        request_id: ctx.state.request.request_id
      });

      return Response.json(response, { status: response.success ? 200 : 400 });
    });

    this.get('/:key/entry/:entry_id', async (_req, ctx) => {
      const key = ctx.params.key;
      const entry_id  = Number(ctx.params.entry_id);
      if(!Number.isSafeInteger(entry_id)) return Response.json({}, { status: 404 });

      const entry_data = await instance.EntryData(entry_id);
      if(!entry_data) return Response.json({}, { status: 404 });

      if(entry_data.entry.key !== key) return Response.json({}, { status: 404 });

      return Response.json(entry_data);
    });
  }
}