11import { LockContext } from 'src/db/DBAdapter.js' ;
22
3+ /**
4+ * SQLite operations to track changes for with {@link TriggerManager}
5+ */
36export enum DiffTriggerOperation {
47 INSERT = 'INSERT' ,
58 UPDATE = 'UPDATE' ,
69 DELETE = 'DELETE'
710}
811
12+ /**
13+ * Diffs created by {@link TriggerManager#createDiffTrigger} are stored in a temporary table.
14+ * This is the base record structure for all diff records.
15+ */
916export interface BaseTriggerDiffRecord {
1017 id : string ;
1118 operation : DiffTriggerOperation ;
@@ -16,31 +23,55 @@ export interface BaseTriggerDiffRecord {
1623 timestamp : string ;
1724}
1825
26+ /**
27+ * Represents a diff record for a SQLite UPDATE operation.
28+ * This record contains the new value and optionally the previous value.
29+ * Values are stored as JSON strings.
30+ */
1931export interface TriggerDiffUpdateRecord extends BaseTriggerDiffRecord {
2032 operation : DiffTriggerOperation . UPDATE ;
2133 value : string ;
2234 previous_value ?: string ;
2335}
2436
37+ /**
38+ * Represents a diff record for a SQLite INSERT operation.
39+ * This record contains the new value represented as a JSON string.
40+ */
2541export interface TriggerDiffInsertRecord extends BaseTriggerDiffRecord {
2642 operation : DiffTriggerOperation . INSERT ;
2743 value : string ;
2844}
2945
46+ /**
47+ * Represents a diff record for a SQLite DELETE operation.
48+ * This record contains the new value represented as a JSON string.
49+ */
3050export interface TriggerDiffDeleteRecord extends BaseTriggerDiffRecord {
3151 operation : DiffTriggerOperation . DELETE ;
3252}
3353
54+ /**
55+ * Diffs created by {@link TriggerManager#createDiffTrigger} are stored in a temporary table.
56+ * This is the record structure for all diff records.
57+ */
3458export type TriggerDiffRecord = TriggerDiffUpdateRecord | TriggerDiffInsertRecord | TriggerDiffDeleteRecord ;
3559
60+ /**
61+ * Hooks used in the creation of a table diff trigger.
62+ */
3663export interface TriggerCreationHooks {
3764 /**
38- * Executed inside the write lock before the trigger is created.
65+ * Executed inside a write lock before the trigger is created.
3966 */
4067 beforeCreate ?: ( context : LockContext ) => Promise < void > ;
4168}
4269
43- export interface CreateDiffTriggerOptions {
70+ /**
71+ * Common interface for options used in creating a diff trigger.
72+ */
73+
74+ interface BaseCreateDiffTriggerOptions {
4475 /**
4576 * Source table/view to trigger and track changes from.
4677 * This should be present in the PowerSync database's schema.
@@ -52,27 +83,26 @@ export interface CreateDiffTriggerOptions {
5283 */
5384 operations : DiffTriggerOperation [ ] ;
5485
55- /**
56- * Destination table to track changes to.
57- * This table is created internally.
58- */
59- destination : string ;
60-
6186 /**
6287 * Columns to track and report changes for.
6388 * Defaults to all columns in the source table.
89+ * Use an empty array to track only the ID and operation.
6490 */
6591 columns ?: string [ ] ;
6692
6793 /**
68- * Optional condition to filter when the trigger should fire.
94+ * Optional condition to filter when the triggers should fire.
6995 * This is useful for only triggering on specific conditions.
7096 * For example, you can use it to only trigger on certain values in the NEW row.
7197 * Note that for PowerSync the data is stored in a JSON column named `data`.
7298 * @example
73- * [`NEW.data.status = 'active' AND length(NEW.data.name) > 3`]
99+ * {
100+ * 'INSERT': `json_extract(NEW.data, '$.list_id') = 'abcd'`
101+ * 'UPDATE': `NEW.id = 'abcd' AND json_extract(NEW.data, '$.status') = 'active'`
102+ * 'DELETE': `json_extract(OLD.data, '$.list_id') = 'abcd'`
103+ * }
74104 */
75- when ?: string ;
105+ when ?: Partial < Record < DiffTriggerOperation , string > > ;
76106
77107 /**
78108 * Optional context to create the triggers in.
@@ -81,54 +111,97 @@ export interface CreateDiffTriggerOptions {
81111 hooks ?: TriggerCreationHooks ;
82112}
83113
114+ /**
115+ * Options for {@link TriggerManager#createDiffTrigger}.
116+ */
117+ export interface CreateDiffTriggerOptions extends BaseCreateDiffTriggerOptions {
118+ /**
119+ * Destination table to track changes to.
120+ * This table is created internally.
121+ */
122+ destination : string ;
123+ }
124+
84125export type TriggerRemoveCallback = ( ) => Promise < void > ;
85126
86- export interface TriggerDiffHandlerContext {
127+ /**
128+ * Context for the onChange handler provided to {@link TriggerManager#trackTableDiff}.
129+ */
130+ export interface TriggerDiffHandlerContext extends LockContext {
131+ /**
132+ * The name of the temporary destination table created by the trigger.
133+ */
134+ destination_table : string ;
135+
87136 /**
88137 * Allows querying the database with access to the table containing diff records.
89- * The diff table is accessible via the `diff ` accessor.
138+ * The diff table is accessible via the `DIFF ` accessor.
90139 *
91140 * The `DIFF` table is of the form described in {@link TriggerManager#createDiffTrigger}
141+ * ```sql
142+ * CREATE TEMP DIFF (
143+ * id TEXT,
144+ * operation TEXT,
145+ * timestamp TEXT
146+ * value TEXT,
147+ * previous_value TEXT
148+ * );
149+ * ```
92150 *
93151 * @example
94152 * ```sql
95153 * SELECT
96154 * todos.*
97155 * FROM
98156 * DIFF
99- * JOIN todos ON DIFF.id = todos.id
157+ * JOIN todos ON DIFF.id = todos.id
158+ * WHERE json_extract(DIFF.value, '$.status') = 'active'
100159 * ```
101160 */
102- getAll : < T = any > ( query : string , params ?: any [ ] ) => Promise < T [ ] > ;
103- }
161+ withDiff : < T = any > ( query : string , params ?: any [ ] ) => Promise < T [ ] > ;
104162
105- export interface TrackDiffOptions {
106- /**
107- * A source SQLite table/view to track changes for.
108- * This should be present in the PowerSync database's schema.
109- */
110- source : string ;
111- /**
112- * SQLite Trigger WHEN condition to filter when the trigger should fire.
113- */
114- filter ?: string ;
115163 /**
116- * Table columns to track changes for.
117- */
118- columns ?: string [ ] ;
119- /**
120- * SQLite operations to track changes for.
164+ * Allows querying the database with access to the table containing diff records.
165+ * The diff table is accessible via the `DIFF` accessor.
166+ *
167+ * This is similar to {@link withDiff} but extracts the columns from the JSON value.
168+ * The `DIFF` table exposes the tracked table columns directly as columns. The diff meta data is available as _columns.
169+ *
170+ * ```sql
171+ * CREATE TEMP TABLE DIFF (
172+ * id TEXT,
173+ * replicated_column_1 COLUMN_TYPE,
174+ * replicated_column_2 COLUMN_TYPE,
175+ * __operation TEXT,
176+ * __timestamp TEXT,
177+ * __previous_value TEXT
178+ * );
179+ * ```
180+ *
181+ * @example
182+ * ```sql
183+ * SELECT
184+ * todos.*
185+ * FROM
186+ * DIFF
187+ * JOIN todos ON DIFF.id = todos.id
188+ * --- The todo column names are extracted from json and are available as DIFF.name
189+ * WHERE DIFF.name = 'example'
190+ * ```
121191 */
122- operations : DiffTriggerOperation [ ] ;
192+ withExtractedDiff : < T = any > ( query : string , params ?: any [ ] ) => Promise < T [ ] > ;
193+ }
194+
195+ /**
196+ * Options for tracking changes to a table with {@link TriggerManager#trackTableDiff}.
197+ */
198+ export interface TrackDiffOptions extends BaseCreateDiffTriggerOptions {
123199 /**
124200 * Handler for processing diff operations.
125201 * Automatically invoked once diff items are present.
202+ * Diff items are automatically cleared after the handler is invoked.
126203 */
127204 onChange : ( context : TriggerDiffHandlerContext ) => Promise < void > ;
128- /**
129- * Hooks into the trigger creation process.
130- */
131- hooks ?: TriggerCreationHooks ;
132205}
133206
134207export interface TriggerManager {
0 commit comments