@@ -10,16 +10,34 @@ import { Index } from './Index.js';
1010import { IndexedColumn } from './IndexedColumn.js' ;
1111import { TableV2 } from './TableV2.js' ;
1212
13- export interface TableOptions {
13+ interface SharedTableOptions {
14+ localOnly ?: boolean ;
15+ insertOnly ?: boolean ;
16+ viewName ?: string ;
17+ trackPrevious ?: boolean | TrackPreviousOptions ;
18+ trackMetadata ?: boolean ;
19+ ignoreEmptyUpdates ?: boolean ;
20+ }
21+
22+ /** Whether to include previous column values when PowerSync tracks local changes.
23+ *
24+ * Including old values may be helpful for some backend connector implementations, which is
25+ * why it can be enabled on per-table or per-columm basis.
26+ */
27+ export interface TrackPreviousOptions {
28+ /** When defined, a list of column names for which old values should be tracked. */
29+ columns ?: string [ ] ;
30+ /** When enabled, only include values that have actually been changed by an update. */
31+ onlyWhenChanged ?: boolean ;
32+ }
33+
34+ export interface TableOptions extends SharedTableOptions {
1435 /**
1536 * The synced table name, matching sync rules
1637 */
1738 name : string ;
1839 columns : Column [ ] ;
1940 indexes ?: Index [ ] ;
20- localOnly ?: boolean ;
21- insertOnly ?: boolean ;
22- viewName ?: string ;
2341}
2442
2543export type RowType < T extends TableV2 < any > > = {
@@ -30,17 +48,17 @@ export type RowType<T extends TableV2<any>> = {
3048
3149export type IndexShorthand = Record < string , string [ ] > ;
3250
33- export interface TableV2Options {
51+ export interface TableV2Options extends SharedTableOptions {
3452 indexes ?: IndexShorthand ;
35- localOnly ?: boolean ;
36- insertOnly ?: boolean ;
37- viewName ?: string ;
3853}
3954
4055export const DEFAULT_TABLE_OPTIONS = {
4156 indexes : [ ] ,
4257 insertOnly : false ,
43- localOnly : false
58+ localOnly : false ,
59+ trackPrevious : false ,
60+ trackMetadata : false ,
61+ ignoreEmptyUpdates : false
4462} ;
4563
4664export const InvalidSQLCharacters = / [ " ' % , . # \s [ \] ] / ;
@@ -137,17 +155,23 @@ export class Table<Columns extends ColumnsType = ColumnsType> {
137155 }
138156 }
139157
158+ copyWithName ( name : string ) : Table {
159+ return new Table ( {
160+ ...this . options ,
161+ name
162+ } ) ;
163+ }
164+
140165 private isTableV1 ( arg : TableOptions | Columns ) : arg is TableOptions {
141166 return 'columns' in arg && Array . isArray ( arg . columns ) ;
142167 }
143168
144169 private initTableV1 ( options : TableOptions ) {
145170 this . options = {
146171 ...options ,
147- indexes : options . indexes || [ ] ,
148- insertOnly : options . insertOnly ?? DEFAULT_TABLE_OPTIONS . insertOnly ,
149- localOnly : options . localOnly ?? DEFAULT_TABLE_OPTIONS . localOnly
172+ indexes : options . indexes || [ ]
150173 } ;
174+ this . applyDefaultOptions ( ) ;
151175 }
152176
153177 private initTableV2 ( columns : Columns , options ?: TableV2Options ) {
@@ -173,14 +197,26 @@ export class Table<Columns extends ColumnsType = ColumnsType> {
173197 name : '' ,
174198 columns : convertedColumns ,
175199 indexes : convertedIndexes ,
176- insertOnly : options ?. insertOnly ?? DEFAULT_TABLE_OPTIONS . insertOnly ,
177- localOnly : options ?. localOnly ?? DEFAULT_TABLE_OPTIONS . localOnly ,
178- viewName : options ?. viewName
200+ viewName : options ?. viewName ,
201+ insertOnly : options ?. insertOnly ,
202+ localOnly : options ?. localOnly ,
203+ trackPrevious : options ?. trackPrevious ,
204+ trackMetadata : options ?. trackMetadata ,
205+ ignoreEmptyUpdates : options ?. ignoreEmptyUpdates
179206 } ;
207+ this . applyDefaultOptions ( ) ;
180208
181209 this . _mappedColumns = columns ;
182210 }
183211
212+ private applyDefaultOptions ( ) {
213+ this . options . insertOnly ??= DEFAULT_TABLE_OPTIONS . insertOnly ;
214+ this . options . localOnly ??= DEFAULT_TABLE_OPTIONS . localOnly ;
215+ this . options . trackPrevious ??= DEFAULT_TABLE_OPTIONS . trackPrevious ;
216+ this . options . trackMetadata ??= DEFAULT_TABLE_OPTIONS . trackMetadata ;
217+ this . options . ignoreEmptyUpdates ??= DEFAULT_TABLE_OPTIONS . ignoreEmptyUpdates ;
218+ }
219+
184220 get name ( ) {
185221 return this . options . name ;
186222 }
@@ -212,11 +248,23 @@ export class Table<Columns extends ColumnsType = ColumnsType> {
212248 }
213249
214250 get localOnly ( ) {
215- return this . options . localOnly ?? false ;
251+ return this . options . localOnly ! ;
216252 }
217253
218254 get insertOnly ( ) {
219- return this . options . insertOnly ?? false ;
255+ return this . options . insertOnly ! ;
256+ }
257+
258+ get trackPrevious ( ) {
259+ return this . options . trackPrevious ! ;
260+ }
261+
262+ get trackMetadata ( ) {
263+ return this . options . trackMetadata ! ;
264+ }
265+
266+ get ignoreEmptyUpdates ( ) {
267+ return this . options . ignoreEmptyUpdates ! ;
220268 }
221269
222270 get internalName ( ) {
@@ -250,6 +298,13 @@ export class Table<Columns extends ColumnsType = ColumnsType> {
250298 throw new Error ( `Table has too many columns. The maximum number of columns is ${ MAX_AMOUNT_OF_COLUMNS } .` ) ;
251299 }
252300
301+ if ( this . trackMetadata && this . localOnly ) {
302+ throw new Error ( `Can't include metadata for local-only tables.` ) ;
303+ }
304+ if ( this . trackPrevious != false && this . localOnly ) {
305+ throw new Error ( `Can't include old values for local-only tables.` ) ;
306+ }
307+
253308 const columnNames = new Set < string > ( ) ;
254309 columnNames . add ( 'id' ) ;
255310 for ( const column of this . columns ) {
@@ -286,11 +341,17 @@ export class Table<Columns extends ColumnsType = ColumnsType> {
286341 }
287342
288343 toJSON ( ) {
344+ const trackPrevious = this . trackPrevious ;
345+
289346 return {
290347 name : this . name ,
291348 view_name : this . viewName ,
292349 local_only : this . localOnly ,
293350 insert_only : this . insertOnly ,
351+ include_old : trackPrevious && ( ( trackPrevious as any ) . columns ?? true ) ,
352+ include_old_only_when_changed : typeof trackPrevious == 'object' && trackPrevious . onlyWhenChanged == true ,
353+ include_metadata : this . trackMetadata ,
354+ ignore_empty_update : this . ignoreEmptyUpdates ,
294355 columns : this . columns . map ( ( c ) => c . toJSON ( ) ) ,
295356 indexes : this . indexes . map ( ( e ) => e . toJSON ( this ) )
296357 } ;
0 commit comments