@@ -14,8 +14,11 @@ export enum DiffTriggerOperation {
1414 * @experimental
1515 * Diffs created by {@link TriggerManager#createDiffTrigger} are stored in a temporary table.
1616 * This is the base record structure for all diff records.
17+ *
18+ * @template TOperationId - The type for `operation_id`. Defaults to `number` as returned by default SQLite database queries.
19+ * Use `string` for full 64-bit precision when using `{ castOperationIdAsText: true }` option.
1720 */
18- export interface BaseTriggerDiffRecord {
21+ export interface BaseTriggerDiffRecord < TOperationId extends string | number = number > {
1922 /**
2023 * The modified row's `id` column value.
2124 */
@@ -24,6 +27,13 @@ export interface BaseTriggerDiffRecord {
2427 * The operation performed which created this record.
2528 */
2629 operation : DiffTriggerOperation ;
30+ /**
31+ * Auto-incrementing primary key for the operation.
32+ * Defaults to number as returned by database queries (wa-sqlite returns lower 32 bits).
33+ * Can be string for full 64-bit precision when using `{ castOperationIdAsText: true }` option.
34+ */
35+ operation_id : TOperationId ;
36+
2737 /**
2838 * Time the change operation was recorded.
2939 * This is in ISO 8601 format, e.g. `2023-10-01T12:00:00.000Z`.
@@ -37,7 +47,8 @@ export interface BaseTriggerDiffRecord {
3747 * This record contains the new value and optionally the previous value.
3848 * Values are stored as JSON strings.
3949 */
40- export interface TriggerDiffUpdateRecord extends BaseTriggerDiffRecord {
50+ export interface TriggerDiffUpdateRecord < TOperationId extends string | number = number >
51+ extends BaseTriggerDiffRecord < TOperationId > {
4152 operation : DiffTriggerOperation . UPDATE ;
4253 /**
4354 * The updated state of the row in JSON string format.
@@ -54,7 +65,8 @@ export interface TriggerDiffUpdateRecord extends BaseTriggerDiffRecord {
5465 * Represents a diff record for a SQLite INSERT operation.
5566 * This record contains the new value represented as a JSON string.
5667 */
57- export interface TriggerDiffInsertRecord extends BaseTriggerDiffRecord {
68+ export interface TriggerDiffInsertRecord < TOperationId extends string | number = number >
69+ extends BaseTriggerDiffRecord < TOperationId > {
5870 operation : DiffTriggerOperation . INSERT ;
5971 /**
6072 * The value of the row, at the time of INSERT, in JSON string format.
@@ -67,7 +79,8 @@ export interface TriggerDiffInsertRecord extends BaseTriggerDiffRecord {
6779 * Represents a diff record for a SQLite DELETE operation.
6880 * This record contains the new value represented as a JSON string.
6981 */
70- export interface TriggerDiffDeleteRecord extends BaseTriggerDiffRecord {
82+ export interface TriggerDiffDeleteRecord < TOperationId extends string | number = number >
83+ extends BaseTriggerDiffRecord < TOperationId > {
7184 operation : DiffTriggerOperation . DELETE ;
7285 /**
7386 * The value of the row, before the DELETE operation, in JSON string format.
@@ -82,27 +95,53 @@ export interface TriggerDiffDeleteRecord extends BaseTriggerDiffRecord {
8295 *
8396 * Querying the DIFF table directly with {@link TriggerDiffHandlerContext#withDiff} will return records
8497 * with the structure of this type.
98+ *
99+ * @template TOperationId - The type for `operation_id`. Defaults to `number` as returned by database queries.
100+ * Use `string` for full 64-bit precision when using `{ castOperationIdAsText: true }` option.
101+ *
85102 * @example
86103 * ```typescript
104+ * // Default: operation_id is number
87105 * const diffs = await context.withDiff<TriggerDiffRecord>('SELECT * FROM DIFF');
88- * diff.forEach(diff => console.log(diff.operation, diff.timestamp, JSON.parse(diff.value)))
106+ *
107+ * // With string operation_id for full precision
108+ * const diffsWithString = await context.withDiff<TriggerDiffRecord<string>>(
109+ * 'SELECT * FROM DIFF',
110+ * undefined,
111+ * { castOperationIdAsText: true }
112+ * );
89113 * ```
90114 */
91- export type TriggerDiffRecord = TriggerDiffUpdateRecord | TriggerDiffInsertRecord | TriggerDiffDeleteRecord ;
115+ export type TriggerDiffRecord < TOperationId extends string | number = number > =
116+ | TriggerDiffUpdateRecord < TOperationId >
117+ | TriggerDiffInsertRecord < TOperationId >
118+ | TriggerDiffDeleteRecord < TOperationId > ;
92119
93120/**
94121 * @experimental
95122 * Querying the DIFF table directly with {@link TriggerDiffHandlerContext#withExtractedDiff} will return records
96123 * with the tracked columns extracted from the JSON value.
97124 * This type represents the structure of such records.
125+ *
126+ * @template T - The type for the extracted columns from the tracked JSON value.
127+ * @template TOperationId - The type for `operation_id`. Defaults to `number` as returned by database queries.
128+ * Use `string` for full 64-bit precision when using `{ castOperationIdAsText: true }` option.
129+ *
98130 * @example
99131 * ```typescript
132+ * // Default: operation_id is number
100133 * const diffs = await context.withExtractedDiff<ExtractedTriggerDiffRecord<{id: string, name: string}>>('SELECT * FROM DIFF');
101- * diff.forEach(diff => console.log(diff.__operation, diff.__timestamp, diff.columnName))
134+ *
135+ * // With string operation_id for full precision
136+ * const diffsWithString = await context.withExtractedDiff<ExtractedTriggerDiffRecord<{id: string, name: string}, string>>(
137+ * 'SELECT * FROM DIFF',
138+ * undefined,
139+ * { castOperationIdAsText: true }
140+ * );
102141 * ```
103142 */
104- export type ExtractedTriggerDiffRecord < T > = T & {
105- [ K in keyof Omit < BaseTriggerDiffRecord , 'id' > as `__${string & K } `] : TriggerDiffRecord [ K ] ;
143+ export type ExtractedTriggerDiffRecord < T , TOperationId extends string | number = number > = T & {
144+ [ K in keyof Omit < BaseTriggerDiffRecord < TOperationId > , 'id' > as `__${string & K } `] : TriggerDiffRecord < TOperationId > [ K ] ;
106145} & {
107146 __previous_value ?: string ;
108147} ;
@@ -183,6 +222,21 @@ export interface CreateDiffTriggerOptions extends BaseCreateDiffTriggerOptions {
183222 */
184223export type TriggerRemoveCallback = ( ) => Promise < void > ;
185224
225+ /**
226+ * @experimental
227+ * Options for {@link TriggerDiffHandlerContext#withDiff}.
228+ */
229+ export interface WithDiffOptions {
230+ /**
231+ * If true, casts `operation_id` as TEXT in the internal CTE to preserve full 64-bit precision.
232+ * Use this when you need to ensure `operation_id` is treated as a string to avoid precision loss
233+ * for values exceeding JavaScript's Number.MAX_SAFE_INTEGER.
234+ *
235+ * When enabled, use {@link TriggerDiffRecord}<string> to type the result correctly.
236+ */
237+ castOperationIdAsText ?: boolean ;
238+ }
239+
186240/**
187241 * @experimental
188242 * Context for the `onChange` handler provided to {@link TriggerManager#trackTableDiff}.
@@ -200,9 +254,10 @@ export interface TriggerDiffHandlerContext extends LockContext {
200254 * The `DIFF` table is of the form described in {@link TriggerManager#createDiffTrigger}
201255 * ```sql
202256 * CREATE TEMP DIFF (
257+ * operation_id INTEGER PRIMARY KEY AUTOINCREMENT,
203258 * id TEXT,
204259 * operation TEXT,
205- * timestamp TEXT
260+ * timestamp TEXT,
206261 * value TEXT,
207262 * previous_value TEXT
208263 * );
@@ -222,8 +277,19 @@ export interface TriggerDiffHandlerContext extends LockContext {
222277 * JOIN todos ON DIFF.id = todos.id
223278 * WHERE json_extract(DIFF.value, '$.status') = 'active'
224279 * ```
280+ *
281+ * @example
282+ * ```typescript
283+ * // With operation_id cast as TEXT for full precision
284+ * const diffs = await context.withDiff<TriggerDiffRecord<string>>(
285+ * 'SELECT * FROM DIFF',
286+ * undefined,
287+ * { castOperationIdAsText: true }
288+ * );
289+ * // diffs[0].operation_id is now typed as string
290+ * ```
225291 */
226- withDiff : < T = any > ( query : string , params ?: ReadonlyArray < Readonly < any > > ) => Promise < T [ ] > ;
292+ withDiff : < T = any > ( query : string , params ?: ReadonlyArray < Readonly < any > > , options ?: WithDiffOptions ) => Promise < T [ ] > ;
227293
228294 /**
229295 * Allows querying the database with access to the table containing diff records.
@@ -292,9 +358,10 @@ export interface TriggerManager {
292358 *
293359 * ```sql
294360 * CREATE TEMP TABLE ${destination} (
361+ * operation_id INTEGER PRIMARY KEY AUTOINCREMENT,
295362 * id TEXT,
296363 * operation TEXT,
297- * timestamp TEXT
364+ * timestamp TEXT,
298365 * value TEXT,
299366 * previous_value TEXT
300367 * );
0 commit comments