Add API gateway for prints

This commit is contained in:
dirtydishes 2025-12-27 19:28:30 -05:00
parent 6a1f457028
commit ba84554b0b
4 changed files with 346 additions and 9 deletions

View file

@ -1,4 +1,5 @@
import { createClient, type ClickHouseClient } from "@clickhouse/client";
import { EquityPrintSchema, OptionPrintSchema } from "@islandflow/types";
import type { EquityPrint, OptionPrint } from "@islandflow/types";
import {
normalizeOptionPrint,
@ -66,3 +67,104 @@ export const insertEquityPrint = async (
format: "JSONEachRow"
});
};
const clampLimit = (limit: number): number => {
if (!Number.isFinite(limit)) {
return 100;
}
return Math.max(1, Math.min(1000, Math.floor(limit)));
};
const coerceNumber = (value: unknown): unknown => {
if (typeof value === "string") {
const parsed = Number(value);
if (Number.isFinite(parsed)) {
return parsed;
}
}
return value;
};
const normalizeNumericFields = (
row: Record<string, unknown>,
fields: string[]
): Record<string, unknown> => {
const record: Record<string, unknown> = { ...row };
for (const field of fields) {
if (field in record) {
record[field] = coerceNumber(record[field]);
}
}
return record;
};
export const fetchRecentOptionPrints = async (
client: ClickHouseClient,
limit: number
): Promise<OptionPrint[]> => {
const safeLimit = clampLimit(limit);
const result = await client.query({
query: `SELECT * FROM ${OPTION_PRINTS_TABLE} ORDER BY ts DESC, seq DESC LIMIT ${safeLimit}`,
format: "JSONEachRow"
});
const rows = await result.json<unknown[]>();
const normalized = rows.map((row) => {
if (row && typeof row === "object") {
return normalizeNumericFields(row as Record<string, unknown>, [
"source_ts",
"ingest_ts",
"seq",
"ts",
"price",
"size"
]);
}
return row;
});
return OptionPrintSchema.array().parse(normalized);
};
export const fetchRecentEquityPrints = async (
client: ClickHouseClient,
limit: number
): Promise<EquityPrint[]> => {
const safeLimit = clampLimit(limit);
const result = await client.query({
query: `SELECT * FROM ${EQUITY_PRINTS_TABLE} ORDER BY ts DESC, seq DESC LIMIT ${safeLimit}`,
format: "JSONEachRow"
});
const rows = await result.json<unknown[]>();
const normalized = rows.map((row) => {
if (row && typeof row === "object") {
const record = normalizeNumericFields(row as Record<string, unknown>, [
"source_ts",
"ingest_ts",
"seq",
"ts",
"price",
"size"
]);
if ("offExchangeFlag" in record) {
return {
...record,
offExchangeFlag: Boolean(record.offExchangeFlag)
};
}
return record;
}
return row;
});
return EquityPrintSchema.array().parse(normalized);
};