@@ -7,15 +7,57 @@ public class TableOptions(
77 Dictionary < string , List < string > > ? indexes = null ,
88 bool ? localOnly = null ,
99 bool ? insertOnly = null ,
10- string ? viewName = null )
10+ string ? viewName = null ,
11+ bool ? trackMetadata = null ,
12+ TrackPreviousOptions ? trackPreviousOptions = null ,
13+ bool ? ignoreEmptyUpdates = null
14+ )
1115{
1216 public Dictionary < string , List < string > > Indexes { get ; set ; } = indexes ?? [ ] ;
1317
14- public bool LocalOnly { get ; set ; } = localOnly ?? false ;
18+ public bool LocalOnly { get ; } = localOnly ?? false ;
1519
16- public bool InsertOnly { get ; set ; } = insertOnly ?? false ;
20+ public bool InsertOnly { get ; } = insertOnly ?? false ;
1721
18- public string ? ViewName { get ; set ; } = viewName ;
22+ public string ? ViewName { get ; } = viewName ;
23+
24+ /// <summary>
25+ /// Whether to add a hidden `_metadata` column that will be enabled for updates to attach custom
26+ /// information about writes that will be reported through [CrudEntry.metadata].
27+ /// </summary>
28+ public bool TrackMetadata { get ; } = trackMetadata ?? false ;
29+
30+ /// <summary>
31+ /// When set to a non-null value, track old values of columns
32+ /// </summary>
33+ public TrackPreviousOptions ? TrackPreviousOptions { get ; } = trackPreviousOptions ?? null ;
34+
35+ /// <summary>
36+ /// Whether an `UPDATE` statement that doesn't change any values should be ignored when creating
37+ /// CRUD entries.
38+ /// </summary>
39+ public bool IgnoreEmptyUpdates { get ; } = ignoreEmptyUpdates ?? false ;
40+ }
41+
42+ /// <summary>
43+ /// Whether to include previous column values when PowerSync tracks local changes.
44+ /// Including old values may be helpful for some backend connector implementations,
45+ /// which is why it can be enabled on a per-table or per-column basis.
46+ /// </summary>
47+ public class TrackPreviousOptions
48+ {
49+ /// <summary>
50+ /// When defined, a list of column names for which old values should be tracked.
51+ /// </summary>
52+ [ JsonProperty ( "columns" ) ]
53+ public List < string > ? Columns { get ; set ; }
54+
55+ /// <summary>
56+ /// Whether to only include old values when they were changed by an update, instead of always
57+ /// including all old values,
58+ /// </summary>
59+ [ JsonProperty ( "onlyWhenChanged" ) ]
60+ public bool ? OnlyWhenChanged { get ; set ; }
1961}
2062
2163public class Table
@@ -35,16 +77,21 @@ public Table(Dictionary<string, ColumnType> columns, TableOptions? options = nul
3577 {
3678 ConvertedColumns = [ .. columns . Select ( kv => new Column ( new ColumnOptions ( kv . Key , kv . Value ) ) ) ] ;
3779
38- ConvertedIndexes = [ .. ( Options ? . Indexes ?? [ ] )
80+ ConvertedIndexes =
81+ [
82+ .. ( Options ? . Indexes ?? [ ] )
3983 . Select ( kv =>
4084 new Index ( new IndexOptions (
4185 kv . Key ,
42- [ .. kv . Value . Select ( name =>
43- new IndexedColumn ( new IndexColumnOptions (
44- name . Replace ( "-" , "" ) , ! name . StartsWith ( "-" ) ) )
45- ) ]
86+ [
87+ .. kv . Value . Select ( name =>
88+ new IndexedColumn ( new IndexColumnOptions (
89+ name . Replace ( "-" , "" ) , ! name . StartsWith ( "-" ) ) )
90+ )
91+ ]
4692 ) )
47- ) ] ;
93+ )
94+ ] ;
4895
4996 Options = options ?? new TableOptions ( ) ;
5097
@@ -61,7 +108,18 @@ public void Validate()
61108
62109 if ( Columns . Count > Column . MAX_AMOUNT_OF_COLUMNS )
63110 {
64- throw new Exception ( $ "Table has too many columns. The maximum number of columns is { Column . MAX_AMOUNT_OF_COLUMNS } .") ;
111+ throw new Exception (
112+ $ "Table has too many columns. The maximum number of columns is { Column . MAX_AMOUNT_OF_COLUMNS } .") ;
113+ }
114+
115+ if ( Options . TrackMetadata && Options . LocalOnly )
116+ {
117+ throw new Exception ( "Can't include metadata for local-only tables." ) ;
118+ }
119+
120+ if ( Options . TrackPreviousOptions != null && Options . LocalOnly )
121+ {
122+ throw new Exception ( "Can't include old values for local-only tables." ) ;
65123 }
66124
67125 var columnNames = new HashSet < string > { "id" } ;
@@ -103,15 +161,27 @@ public void Validate()
103161
104162 public string ToJSON ( string Name = "" )
105163 {
164+ var trackPrevious = Options . TrackPreviousOptions ;
165+
106166 var jsonObject = new
107167 {
108168 view_name = Options . ViewName ?? Name ,
109169 local_only = Options . LocalOnly ,
110170 insert_only = Options . InsertOnly ,
111171 columns = ConvertedColumns . Select ( c => JsonConvert . DeserializeObject < object > ( c . ToJSON ( ) ) ) . ToList ( ) ,
112- indexes = ConvertedIndexes . Select ( e => JsonConvert . DeserializeObject < object > ( e . ToJSON ( this ) ) ) . ToList ( )
172+ indexes = ConvertedIndexes . Select ( e => JsonConvert . DeserializeObject < object > ( e . ToJSON ( this ) ) ) . ToList ( ) ,
173+
174+ include_metadata = Options . TrackMetadata ,
175+ ignore_empty_update = Options . IgnoreEmptyUpdates ,
176+ include_old = ( object ) ( trackPrevious switch
177+ {
178+ null => false ,
179+ { Columns : null } => true ,
180+ { Columns : var cols } => cols
181+ } ) ,
182+ include_old_only_when_changed = trackPrevious ? . OnlyWhenChanged ?? false
113183 } ;
114184
115185 return JsonConvert . SerializeObject ( jsonObject ) ;
116186 }
117- }
187+ }
0 commit comments