import { ChangesetExecutor } from './ChangesetExecutor.js'; import { Context, Changeset, IModel, Transaction, OptimisticPromise, } from '@aphro/context-runtime-ts'; import tracer from './trace.js'; type ExtractValue[]> = { [K in keyof T]: T[K] extends Changeset ? V : never; }; export function commit, D extends {}>( ctx: Context, changesets: Changeset, ): OptimisticPromise; export function commit>>( ctx: Context, ...changesets: T ): OptimisticPromise<[...ExtractValue]>; export function commit>>( ctx: Context, changesets: T, ): OptimisticPromise<[...ExtractValue]>; export function commit[]>( ctx: Context, ...changesets: T ): OptimisticPromise<[...ExtractValue]> { return tracer.startActiveSpan('commit', () => { // Handle overloads. let singular = false; if (Array.isArray(changesets[0])) { // The user called commit like: commit(ctx, [cs1, ...]); changesets = changesets[0] as any; } else if (changesets.length === 1) { // The user called commit like: commit(ctx, cs1); singular = true; } // else -- the user called commit like: commit(ctx, cs1, cs2, ...); const transaction = new ChangesetExecutor(ctx, changesets).execute(); const optimistic = changesets.map(cs => transaction.nodes.get(cs.id)); let result: any; if (singular) { result = optimistic[0]; } else { result = optimistic; } const ret = new OptimisticPromise((resolve, reject) => { transaction.persistHandle.then( () => // explain why we can use `optimistic` results here resolve(result), reject, ); }); ret.__setOptimisticResult(result); return ret as any; }); } // TODO: we need to re-enable optimistic updates + delayed persists. // and test the interaction of this with live queries. // Give the user more control of how commits are handled. // One reason is to delay actual persisting of data for highly-interactive applications. // The user can provide their own `persistor` impl which collects updates and persists after some delay. // Or maybe it throws all persists out except the last one and runs that via debounce. type CommitOptions = { ctx: Context; persistor?: (ctx: Context, tx: Omit) => Promise<[void, void]>; }; // export function commitExt, D>( // opts: CommitOptions, // changesets: Changeset, // ): [Promise, M]; // export function commitExt>>( // opts: CommitOptions, // changesets: T, // ): [Promise, ...ExtractValue]; // export function commitExt>>( // opts: CommitOptions, // ...changesets: T // ): [Promise, ...ExtractValue]; // export function commitExt[]>( // opts: CommitOptions, // ...changesets: T // ): [Promise, ...ExtractValue] { // throw new Error(); // }