0.1.2Updated 7 months ago
import type { PostgresClient } from "@infinity-beyond/infinity.ts";

type CleanupMethod = (rows: any[]) => any[];

export class DataTypeQuery<ArgumentFormat extends any[], MapData extends Record<string, any>, ReturnType = any> {
  readonly query: string
  readonly cleanup?: CleanupMethod;

  constructor(query: string, cleanup?: CleanupMethod) {
    this.query = query;
    this.cleanup = cleanup;
  }

  populate(classInstance: MapData) {
    return new MappedDataTypeQuery<ArgumentFormat, MapData, ReturnType>(this, classInstance);
  }
}

class MappedDataTypeQuery<ArgumentFormat extends any[], MapData extends Record<string, any>, ReturnType = any> {
  parent: DataTypeQuery<ArgumentFormat, MapData>
  mapped_query: string;

  constructor(parent: DataTypeQuery<ArgumentFormat, MapData>, classInstance: MapData) {
    this.parent = parent;

    this.mapped_query = this.parent.query.replace(/\{(\w+)\}/g, (_, name: string) => {
      if(Object.hasOwn(classInstance, name)) return classInstance[name];

      return `{${name}}`;
    })
  }

  private parse(...args: ArgumentFormat): [query: string, args: any[]] {
    return [
      this.mapped_query.replace(/^[\\n\s]+|[\\n\s]+$/g, '').replace(/\s+\\n\s+/g, ' ').replace(/\s{2,}/g, ' '),
      args
    ]
  };

  async execute(client: PostgresClient, ...args: ArgumentFormat) {
    const response = (await client.query<ReturnType>(...this.parse(...args)));

    if(this.parent.cleanup) {
      response.rows = this.parent.cleanup(response.rows);
    }

    return response;
  }
}