@@ -26,6 +26,46 @@ public protocol TableProtocol {
2626 ///
2727 var viewNameOverride : String ? { get }
2828 var viewName : String { get }
29+
30+ /// Whether to add a hidden `_metadata` column that will ne abled for updates to
31+ /// attach custom information about writes.
32+ ///
33+ /// When the `_metadata` column is written to for inserts or updates, its value will not be
34+ /// part of ``CrudEntry/opData``. Instead, it is reported as ``CrudEntry/metadata``,
35+ /// allowing ``PowerSyncBackendConnector``s to handle these updates specially.
36+ var trackMetadata : Bool { get }
37+
38+ /// When set to a non-`nil` value, track old values of columns for ``CrudEntry/previousValues``.
39+ ///
40+ /// See ``TrackPreviousValuesOptions`` for details
41+ var trackPreviousValues : TrackPreviousValuesOptions ? { get }
42+
43+ /// Whether an `UPDATE` statement that doesn't change any values should be ignored entirely when
44+ /// creating CRUD entries.
45+ ///
46+ /// This is disabled by default, meaning that an `UPDATE` on a row that doesn't change values would
47+ /// create a ``CrudEntry`` with an empty ``CrudEntry/opData`` and ``UpdateType/patch``.
48+ var ignoreEmptyUpdates : Bool { get }
49+ }
50+
51+ /// Options to include old values in ``CrudEntry/previousValues`` for update statements.
52+ ///
53+ /// These options are enabled by passing them to a non-local ``Table`` constructor.
54+ public struct TrackPreviousValuesOptions {
55+ /// A filter of column names for which updates should be tracked.
56+ ///
57+ /// When set to a non-`nil` value, columns not included in this list will not appear in
58+ /// ``CrudEntry/previousValues``. By default, all columns are included.
59+ public let columnFilter : [ String ] ? ;
60+
61+ /// Whether to only include old values when they were changed by an update, instead of always including
62+ /// all old values.
63+ public let onlyWhenChanged : Bool ;
64+
65+ public init ( columnFilter: [ String ] ? = nil , onlyWhenChanged: Bool = false ) {
66+ self . columnFilter = columnFilter
67+ self . onlyWhenChanged = onlyWhenChanged
68+ }
2969}
3070
3171private let MAX_AMOUNT_OF_COLUMNS = 63
@@ -40,6 +80,9 @@ public struct Table: TableProtocol {
4080 public let localOnly : Bool
4181 public let insertOnly : Bool
4282 public let viewNameOverride : String ?
83+ public let trackMetadata : Bool
84+ public let trackPreviousValues : TrackPreviousValuesOptions ?
85+ public let ignoreEmptyUpdates : Bool
4386
4487 public var viewName : String {
4588 viewNameOverride ?? name
@@ -60,14 +103,20 @@ public struct Table: TableProtocol {
60103 indexes: [ Index ] = [ ] ,
61104 localOnly: Bool = false ,
62105 insertOnly: Bool = false ,
63- viewNameOverride: String ? = nil
106+ viewNameOverride: String ? = nil ,
107+ trackMetadata: Bool = false ,
108+ trackPreviousValues: TrackPreviousValuesOptions ? = nil ,
109+ ignoreEmptyUpdates: Bool = false
64110 ) {
65111 self . name = name
66112 self . columns = columns
67113 self . indexes = indexes
68114 self . localOnly = localOnly
69115 self . insertOnly = insertOnly
70116 self . viewNameOverride = viewNameOverride
117+ self . trackMetadata = trackMetadata
118+ self . trackPreviousValues = trackPreviousValues
119+ self . ignoreEmptyUpdates = ignoreEmptyUpdates
71120 }
72121
73122 private func hasInvalidSqliteCharacters( _ string: String ) -> Bool {
@@ -82,11 +131,20 @@ public struct Table: TableProtocol {
82131 if columns. count > MAX_AMOUNT_OF_COLUMNS {
83132 throw TableError . tooManyColumns ( tableName: name, count: columns. count)
84133 }
85-
134+
86135 if let viewNameOverride = viewNameOverride,
87136 hasInvalidSqliteCharacters ( viewNameOverride) {
88137 throw TableError . invalidViewName ( viewName: viewNameOverride)
89138 }
139+
140+ if localOnly {
141+ if trackPreviousValues != nil {
142+ throw TableError . trackPreviousForLocalTable ( tableName: name)
143+ }
144+ if trackMetadata {
145+ throw TableError . metadataForLocalTable ( tableName: name)
146+ }
147+ }
90148
91149 var columnNames = Set < String > ( [ " id " ] )
92150
@@ -156,4 +214,8 @@ public enum TableError: Error {
156214 case duplicateIndex( tableName: String , indexName: String )
157215 case invalidIndexName( tableName: String , indexName: String )
158216 case columnNotFound( tableName: String , columnName: String , indexName: String )
217+ /// Local-only tables can't enable ``Table/trackMetadata`` because no updates are tracked for those tables at all.
218+ case metadataForLocalTable( tableName: String )
219+ /// Local-only tables can't enable ``Table/trackPreviousValues`` because no updates are tracked for those tables at all.
220+ case trackPreviousForLocalTable( tableName: String )
159221}
0 commit comments