|
11 | 11 | /// See <doc:CloudKit#Accessing-CloudKit-metadata> for more info. |
12 | 12 | @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) |
13 | 13 | @Table("sqlitedata_icloud_metadata") |
14 | | - public struct SyncMetadata: Hashable, Sendable { |
| 14 | + public struct SyncMetadata: Hashable, Identifiable, Sendable { |
| 15 | + /// A selection of columns representing a synchronized record's unique identifier and type. |
| 16 | + @Selection |
| 17 | + public struct ID: Hashable, Sendable { |
| 18 | + /// The unique identifier of the record synchronized. |
| 19 | + public var recordPrimaryKey: String |
| 20 | + |
| 21 | + /// The type of the record synchronized, _i.e._ its table name. |
| 22 | + public var recordType: String |
| 23 | + } |
| 24 | + |
| 25 | + /// The unique identifier and type of the record synchronized. |
| 26 | + public let id: ID |
| 27 | + |
15 | 28 | /// The unique identifier of the record synchronized. |
16 | | - public var recordPrimaryKey: String |
| 29 | + public var recordPrimaryKey: String { id.recordPrimaryKey } |
17 | 30 |
|
18 | 31 | /// The type of the record synchronized, _i.e._ its table name. |
19 | | - public var recordType: String |
| 32 | + public var recordType: String { id.recordType } |
20 | 33 |
|
21 | 34 | /// The record zone name. |
22 | 35 | public var zoneName: String |
|
35 | 48 | @Column(generated: .virtual) |
36 | 49 | public let recordName: String |
37 | 50 |
|
| 51 | + /// A selection of columns representing a synchronized parent record's unique identifier and |
| 52 | + /// type. |
| 53 | + @Selection |
| 54 | + public struct ParentID: Hashable, Sendable { |
| 55 | + /// The unique identifier of the parent record synchronized. |
| 56 | + public var parentRecordPrimaryKey: String |
| 57 | + |
| 58 | + /// The type of the parent record synchronized, _i.e._ its table name. |
| 59 | + public var parentRecordType: String |
| 60 | + } |
| 61 | + |
| 62 | + /// The identifier and type of this record's parent, if any. |
| 63 | + public var parentRecordID: ParentID? |
| 64 | + |
38 | 65 | /// The unique identifier of this record's parent, if any. |
39 | | - public var parentRecordPrimaryKey: String? |
| 66 | + public var parentRecordPrimaryKey: String? { parentRecordID?.parentRecordPrimaryKey } |
40 | 67 |
|
41 | 68 | /// The type of this record's parent, _i.e._ its table name, if any. |
42 | | - public var parentRecordType: String? |
| 69 | + public var parentRecordType: String? { parentRecordID?.parentRecordType } |
43 | 70 |
|
44 | 71 | /// The name of this record's parent, if any. |
45 | 72 | /// |
|
85 | 112 | public var userModificationTime: Int64 |
86 | 113 | } |
87 | 114 |
|
| 115 | + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) |
| 116 | + extension SyncMetadata.TableColumns { |
| 117 | + public var recordPrimaryKey: TableColumn<SyncMetadata, String> { |
| 118 | + id.recordPrimaryKey |
| 119 | + } |
| 120 | + |
| 121 | + public var recordType: TableColumn<SyncMetadata, String> { |
| 122 | + id.recordType |
| 123 | + } |
| 124 | + |
| 125 | + public var parentRecordPrimaryKey: TableColumn<SyncMetadata, String?> { |
| 126 | + parentRecordID.parentRecordPrimaryKey |
| 127 | + } |
| 128 | + |
| 129 | + public var parentRecordType: TableColumn<SyncMetadata, String?> { |
| 130 | + parentRecordID.parentRecordType |
| 131 | + } |
| 132 | + } |
| 133 | + |
88 | 134 | @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) |
89 | 135 | extension SyncMetadata { |
90 | 136 | package init( |
|
99 | 145 | share: CKShare? = nil, |
100 | 146 | userModificationTime: Int64 |
101 | 147 | ) { |
102 | | - self.recordPrimaryKey = recordPrimaryKey |
103 | | - self.recordType = recordType |
| 148 | + self.id = ID(recordPrimaryKey: recordPrimaryKey, recordType: recordType) |
104 | 149 | self.recordName = "\(recordPrimaryKey):\(recordType)" |
105 | 150 | self.zoneName = zoneName |
106 | 151 | self.ownerName = ownerName |
107 | | - self.parentRecordPrimaryKey = parentRecordPrimaryKey |
108 | | - self.parentRecordType = parentRecordType |
109 | 152 | if let parentRecordPrimaryKey, let parentRecordType { |
| 153 | + self.parentRecordID = ParentID( |
| 154 | + parentRecordPrimaryKey: parentRecordPrimaryKey, |
| 155 | + parentRecordType: parentRecordType |
| 156 | + ) |
110 | 157 | self.parentRecordName = "\(parentRecordPrimaryKey):\(parentRecordType)" |
111 | 158 | } else { |
| 159 | + self.parentRecordID = nil |
112 | 160 | self.parentRecordName = nil |
113 | 161 | } |
114 | 162 | self.lastKnownServerRecord = lastKnownServerRecord |
|
139 | 187 | } |
140 | 188 |
|
141 | 189 | @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) |
142 | | - extension PrimaryKeyedTable where PrimaryKey: IdentifierStringConvertible { |
| 190 | + extension PrimaryKeyedTable where PrimaryKey.QueryOutput: IdentifierStringConvertible { |
143 | 191 | /// A query for finding the metadata associated with a record. |
144 | 192 | /// |
145 | 193 | /// - Parameter primaryKey: The primary key of the record whose metadata to look up. |
| 194 | + @available(*, deprecated, message: "Use 'SyncMetadata.find(record.syncMetadataID)', instead") |
146 | 195 | public static func metadata(for primaryKey: PrimaryKey.QueryOutput) -> Where<SyncMetadata> { |
147 | 196 | SyncMetadata.where { |
148 | 197 | #sql( |
|
153 | 202 | ) |
154 | 203 | } |
155 | 204 | } |
156 | | - } |
157 | 205 |
|
158 | | - @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) |
159 | | - extension PrimaryKeyedTable where PrimaryKey.QueryOutput: IdentifierStringConvertible { |
160 | | - /// Constructs a ``SyncMetadata/RecordName-swift.struct`` for a primary keyed table give an ID. |
161 | | - /// |
162 | | - /// - Parameter id: The ID of the record. |
| 206 | + /// An identifier representing any associated synchronization metadata. |
| 207 | + public var syncMetadataID: SyncMetadata.ID { |
| 208 | + SyncMetadata.ID( |
| 209 | + recordPrimaryKey: primaryKey.rawIdentifier, |
| 210 | + recordType: Self.tableName |
| 211 | + ) |
| 212 | + } |
| 213 | + |
163 | 214 | package static func recordName(for id: PrimaryKey.QueryOutput) -> String { |
164 | 215 | "\(id.rawIdentifier):\(tableName)" |
165 | 216 | } |
|
179 | 230 | /// RemindersList |
180 | 231 | /// .leftJoin(SyncMetadata.all) { $0.hasMetadata.in($1) } |
181 | 232 | /// ``` |
| 233 | + @available( |
| 234 | + *, |
| 235 | + deprecated, |
| 236 | + message: """ |
| 237 | + Join the 'SyncMetadata' table using 'SyncMetadata.id' and 'Table.syncMetadataID', instead. |
| 238 | + """ |
| 239 | + ) |
182 | 240 | public func hasMetadata(in metadata: SyncMetadata.TableColumns) -> some QueryExpression<Bool> { |
183 | 241 | metadata.recordType.eq(QueryValue.tableName) |
184 | 242 | && #sql("\(primaryKey)").eq(metadata.recordPrimaryKey) |
185 | 243 | } |
| 244 | + |
| 245 | + /// An identifier representing any associated synchronization metadata. |
| 246 | + /// |
| 247 | + /// This helper can be useful when joining your tables to the ``SyncMetadata`` table: |
| 248 | + /// |
| 249 | + /// ```swift |
| 250 | + /// RemindersList |
| 251 | + /// .leftJoin(SyncMetadata.all) { $0.syncMetadataID.eq($1.id) } |
| 252 | + /// ``` |
| 253 | + public var syncMetadataID: some QueryExpression<SyncMetadata.ID> { |
| 254 | + #sql("\(primaryKey), \(bind: QueryValue.tableName)") |
| 255 | + } |
186 | 256 | } |
187 | 257 |
|
188 | 258 | @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) |
|
0 commit comments