import { PostgresJsDatabase } from "drizzle-orm/postgres-js"; import * as driz from "drizzle-orm"; import type { Fact } from "."; import { replicache_clients } from "drizzle/schema"; import type { Attribute, FilterAttributes } from "./attributes"; import { ReadTransaction, WriteTransaction } from "replicache"; import { PgTransaction } from "drizzle-orm/pg-core"; export function FactWithIndexes(f: Fact) { let indexes: { eav: string; vae?: string; } = { eav: `${f.entity}-${f.attribute}-${f.id}`, }; if ( f.data.type === "reference" || f.data.type === "ordered-reference" || f.data.type === "spatial-reference" ) indexes.vae = `${f.data.value}-${f.attribute}`; return { ...f, indexes }; } export async function getClientGroup( db: PgTransaction, clientGroupID: string, ): Promise<{ [clientID: string]: number }> { let data = await db .select() .from(replicache_clients) .where(driz.eq(replicache_clients.client_group, clientGroupID)); if (!data) return {}; return data.reduce( (acc, clientRecord) => { acc[clientRecord.client_id] = clientRecord.last_mutation; return acc; }, {} as { [clientID: string]: number }, ); } export const scanIndex = (tx: ReadTransaction) => ({ async eav(entity: string, attribute: A | "") { return ( ( await tx .scan>({ indexName: "eav", prefix: `${entity}-${attribute}` }) // Hack rn because of the rich bluesky-post type .toArray() ).filter((f) => attribute === "" || f.attribute === attribute) ); }, async vae< A extends keyof FilterAttributes<{ type: "reference" | "ordered-reference" | "spatial-reference"; }>, >(entity: string, attribute: A) { return ( await tx .scan>({ indexName: "vae", prefix: `${entity}-${attribute}` }) .toArray() ).filter((f) => f.attribute === attribute); }, }); export const scanIndexLocal = (initialFacts: Fact[]) => ({ eav(entity: string, attribute: A) { return initialFacts.filter( (f) => f.entity === entity && f.attribute === attribute, ) as SafeArray>; }, }); // Base utility type for making types compatible with ReadonlyJSONObject export type AsReadonlyJSONObject = T & { [key: string]: undefined; }; // Recursive utility type for nested objects export type DeepAsReadonlyJSONValue = T extends object ? T extends Array ? ReadonlyArray> // Handle arrays : AsReadonlyJSONObject<{ [K in keyof T]: DeepAsReadonlyJSONValue; }> : T extends string | number | boolean | null ? T // Primitive types that already match ReadonlyJSONValue : never; // For other types that can't be converted