feat: things are happening...

This commit is contained in:
Daniel Ledda
2022-07-10 23:07:51 +02:00
parent ba68f953f0
commit fb9f78caf7
22 changed files with 448 additions and 207 deletions

View File

@@ -1,42 +1,73 @@
import { Client } from "postgres";
import config from "./config.ts";
import {Maybe} from "./Maybe.ts";
import {JSONObject} from "./JSON.ts";
import { JSONObject } from "./JSON.ts";
import { Result, StoccaTreError } from "./Result.ts";
type Interpolable = number | string | bigint | null | boolean;
type UnionToIntersection<Union> =
(Union extends any ? (x: Union) => any : never) extends (x: infer Intersection) => any
? Intersection
: never;
type SQLWithArg<Arg> = Arg extends string ? `${string}$${Arg}${string}` : never;
type SQLWithArgs<Args extends Record<string, Interpolable>> = UnionToIntersection<SQLWithArg<keyof Args>>;
type ArgNamesInSQL<SQL extends string> =
SQL extends `${string}$${infer Arg1} ${infer SQLAfterArg1}`
? Arg1 extends `${infer Arg1NoTrailing}${";" | "," | "'" | "\"" | "(" | ")"}`
? Arg1NoTrailing | ArgNamesInSQL<SQLAfterArg1>
: Arg1 | ArgNamesInSQL<SQLAfterArg1>
: SQL extends `${string}$${infer ArgN}`
? ArgN extends `${infer ArgNNoTrailing}${";" | "," | "'" | "\"" | "(" | ")"}`
? ArgNNoTrailing
: ArgN
: never;
type ParametrisedSQL = `${string}$${string}`;
type IsPlainSQL<T> = T extends ParametrisedSQL ? never : T;
type ArgsForSQL<SQL extends string> = SQL extends ParametrisedSQL
? Record<ArgNamesInSQL<SQL>, Interpolable>
: JSONObject | undefined;
// Helper for casting queries
export type Q<T extends JSONObject> = Result<T[]>;
export type WithoutId<T> = Omit<T, "id">;
export interface StoccaTreDbConn {
query<T extends JSONObject | JSONObject[]>(query: string): Promise<Maybe<T>>,
query<Q extends string>(query: Q, ...args: Q extends IsPlainSQL<Q> ? [(JSONObject | undefined)?] : [ArgsForSQL<Q>]): Promise<Result<JSONObject[]>>;
}
export default function createNewDbConnection(): StoccaTreDbConn {
const postgresClient = new Client({
hostname: config.hostname,
password: config.password,
user: config.username,
database: "stocca_tre",
port: config.port,
});
await postgresClient.connect();
return {
async queryMany<T extends JSONObject[]>(query: string): Promise<Maybe<{ rows: T, count: number }>> {
try {
const result = await postgresClient.queryArray<T>(query);
return {
just: {
rows: result.rows,
count: result.rowCount ?? NaN,
},
};
} catch (e: unknown) {
}
},
queryOne<T extends JSONObject>(query: string): Promise<Maybe<T>> {
try {
const result = await postgresClient.queryObject<T>(query);
return { just: result };
}
export default async function createNewDbConnection(): Promise<Result<StoccaTreDbConn>> {
let postgresClient: Client;
try {
postgresClient = new Client({
user: config.dbUsername,
database: "stocca_tre",
hostname: config.hostname,
port: config.dbPort,
password: config.dbPassword,
tls: {
enabled: false,
},
});
await postgresClient.connect();
} catch (e: unknown) {
const error = e as { message?: string };
if (error.message) {
return [new StoccaTreError(error.message).qualified("Error connecting to database: ")];
}
return [new StoccaTreError("Error connecting to database.")];
}
return [,
{
async query<Q extends string>(query: Q, ...args: Q extends IsPlainSQL<Q> ? [(JSONObject | undefined)?] : [ArgsForSQL<Q>]): Promise<Result<JSONObject[]>> {
try {
const result = <{rows: JSONObject[]}> await postgresClient.queryObject(query, args[0]);
return [, result.rows];
} catch (e: unknown) {
const error = e as { message?: string };
return [new StoccaTreError(error.message ?? "Internal database error.")];
}
},
},
];
}