init
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import type { ResultSetHeader, RowDataPacket } from "mysql2/promise";
|
||||
import { BILL_BODY_LIMIT } from "./body";
|
||||
import { withTransaction, getPool } from "./db";
|
||||
import { isUuid } from "./ids";
|
||||
|
||||
export class BillStoreError extends Error {
|
||||
readonly status: number;
|
||||
|
||||
constructor(status: number, message: string) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
export async function storePublishedBill(token: string, raw: string): Promise<void> {
|
||||
if (!isUuid(token)) throw new BillStoreError(400, "invalid token");
|
||||
if (Buffer.byteLength(raw, "utf8") > BILL_BODY_LIMIT) throw new BillStoreError(413, "body too large");
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(raw);
|
||||
} catch {
|
||||
throw new BillStoreError(400, "invalid json");
|
||||
}
|
||||
const isSnapshot = parsed !== null && typeof parsed === "object" && !Array.isArray(parsed);
|
||||
await withTransaction(async (conn) => {
|
||||
await conn.query(
|
||||
`INSERT INTO bill_snapshots (token, payload_json, updated_at)
|
||||
VALUES (?, ?, UTC_TIMESTAMP(3))
|
||||
ON DUPLICATE KEY UPDATE payload_json = VALUES(payload_json), updated_at = UTC_TIMESTAMP(3)`,
|
||||
[token, raw],
|
||||
);
|
||||
if (isSnapshot) {
|
||||
await conn.query<ResultSetHeader>(
|
||||
`UPDATE invoices SET snapshot_json = ? WHERE public_token = ? AND deleted_at IS NULL`,
|
||||
[raw, token],
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Invoice snapshot first, then the legacy store. */
|
||||
export async function readBillPayload(token: string): Promise<string | null> {
|
||||
if (!isUuid(token)) return null;
|
||||
const pool = getPool();
|
||||
const [invoices] = await pool.query<RowDataPacket[]>(
|
||||
`SELECT snapshot_json FROM invoices WHERE public_token = ? AND deleted_at IS NULL LIMIT 1`,
|
||||
[token],
|
||||
);
|
||||
const snapshot = invoices[0]?.snapshot_json;
|
||||
if (typeof snapshot === "string" && snapshot.length > 0) return snapshot;
|
||||
const [legacy] = await pool.query<RowDataPacket[]>(
|
||||
`SELECT payload_json FROM bill_snapshots WHERE token = ? LIMIT 1`,
|
||||
[token],
|
||||
);
|
||||
const payload = legacy[0]?.payload_json;
|
||||
if (typeof payload === "string" && payload.length > 0) return payload;
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user