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