Skip to content

Commit 05f755f

Browse files
Added identifier as a requirement for decoders
1 parent f54712c commit 05f755f

File tree

2 files changed

+70
-43
lines changed

2 files changed

+70
-43
lines changed

Sources/CodableDatastore/Datastore/Datastore.swift

Lines changed: 69 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public actor Datastore<
1919
let key: DatastoreKey
2020
let version: Version
2121
let encoder: (_ instance: CodedType) async throws -> Data
22-
let decoders: [Version: (_ data: Data) async throws -> CodedType]
22+
let decoders: [Version: (_ data: Data) async throws -> (id: IdentifierType, instance: CodedType)]
2323
let directIndexes: [IndexPath<CodedType, _AnyIndexed>]
2424
let computedIndexes: [IndexPath<CodedType, _AnyIndexed>]
2525

@@ -41,7 +41,7 @@ public actor Datastore<
4141
codedType: CodedType.Type = CodedType.self,
4242
identifierType: IdentifierType.Type,
4343
encoder: @escaping (_ instance: CodedType) async throws -> Data,
44-
decoders: [Version: (_ data: Data) async throws -> CodedType],
44+
decoders: [Version: (_ data: Data) async throws -> (id: IdentifierType, instance: CodedType)],
4545
directIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
4646
computedIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
4747
configuration: Configuration = .init()
@@ -53,6 +53,11 @@ public actor Datastore<
5353
self.decoders = decoders
5454
self.directIndexes = directIndexes
5555
self.computedIndexes = computedIndexes
56+
57+
for decoderVersion in Version.allCases {
58+
guard decoders[decoderVersion] == nil else { continue }
59+
assertionFailure("Decoders missing case for \(decoderVersion). Please make sure you have a decoder configured for this version or you may encounter errors at runtime.")
60+
}
5661
}
5762

5863
public init(
@@ -61,7 +66,7 @@ public actor Datastore<
6166
version: Version,
6267
codedType: CodedType.Type = CodedType.self,
6368
identifierType: IdentifierType.Type,
64-
decoders: [Version: (_ data: Data) async throws -> CodedType],
69+
decoders: [Version: (_ data: Data) async throws -> (id: IdentifierType, instance: CodedType)],
6570
directIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
6671
computedIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
6772
configuration: Configuration = .init()
@@ -95,7 +100,7 @@ extension Datastore {
95100
return descriptor
96101
}
97102

98-
func decoder(for version: Version) throws -> (_ data: Data) async throws -> CodedType {
103+
func decoder(for version: Version) throws -> (_ data: Data) async throws -> (id: IdentifierType, instance: CodedType) {
99104
guard let decoder = decoders[version] else {
100105
throw DatastoreError.missingDecoder(version: String(describing: version))
101106
}
@@ -272,7 +277,7 @@ extension Datastore {
272277

273278
let entryVersion = try Version(persistedEntry.versionData)
274279
let decoder = try await self.decoder(for: entryVersion)
275-
let instance = try await decoder(persistedEntry.instanceData)
280+
let instance = try await decoder(persistedEntry.instanceData).instance
276281

277282
return instance
278283
} catch DatastoreInterfaceError.instanceNotFound {
@@ -297,7 +302,7 @@ extension Datastore {
297302
try await transaction.primaryIndexScan(range: range.applying(order), datastoreKey: self.key) { versionData, instanceData in
298303
let entryVersion = try Version(versionData)
299304
let decoder = try await self.decoder(for: entryVersion)
300-
let instance = try await decoder(instanceData)
305+
let instance = try await decoder(instanceData).instance
301306

302307
try await provider.yield(instance)
303308
}
@@ -342,7 +347,7 @@ extension Datastore {
342347
) { versionData, instanceData in
343348
let entryVersion = try Version(versionData)
344349
let decoder = try await self.decoder(for: entryVersion)
345-
let instance = try await decoder(instanceData)
350+
let instance = try await decoder(instanceData).instance
346351

347352
try await provider.yield(instance)
348353
}
@@ -356,7 +361,7 @@ extension Datastore {
356361

357362
let entryVersion = try Version(persistedEntry.versionData)
358363
let decoder = try await self.decoder(for: entryVersion)
359-
let instance = try await decoder(persistedEntry.instanceData)
364+
let instance = try await decoder(persistedEntry.instanceData).instance
360365

361366
try await provider.yield(instance)
362367
}
@@ -416,7 +421,7 @@ extension Datastore {
416421
try? await event.mapEntries { entry in
417422
let version = try Version(entry.versionData)
418423
let decoder = try await self.decoder(for: version)
419-
let instance = try await decoder(entry.instanceData)
424+
let instance = try await decoder(entry.instanceData).instance
420425
return instance
421426
}
422427
}
@@ -453,7 +458,7 @@ extension Datastore where AccessMode == ReadWrite {
453458

454459
let existingVersion = try Version(existingEntry.versionData)
455460
let decoder = try await self.decoder(for: existingVersion)
456-
let existingInstance = try await decoder(existingEntry.instanceData)
461+
let existingInstance = try await decoder(existingEntry.instanceData).instance
457462

458463
return (
459464
cursor: existingEntry.cursor,
@@ -664,7 +669,7 @@ extension Datastore where AccessMode == ReadWrite {
664669
@discardableResult
665670
public func delete(_ idenfifier: IdentifierType) async throws -> CodedType {
666671
try await warmupIfNeeded()
667-
672+
668673
return try await persistence._withTransaction(
669674
actionName: "Delete Entry",
670675
options: [.idempotent]
@@ -678,7 +683,7 @@ extension Datastore where AccessMode == ReadWrite {
678683
/// Load the instance completely so we can delete the entry within the direct and secondary indexes too.
679684
let existingVersion = try Version(existingEntry.versionData)
680685
let decoder = try await self.decoder(for: existingVersion)
681-
let existingInstance = try await decoder(existingEntry.instanceData)
686+
let existingInstance = try await decoder(existingEntry.instanceData).instance
682687

683688
try await transaction.emit(
684689
event: .deleted(
@@ -805,7 +810,7 @@ extension Datastore where AccessMode == ReadWrite {
805810
identifierType: IdentifierType.Type,
806811
encoder: JSONEncoder = JSONEncoder(),
807812
decoder: JSONDecoder = JSONDecoder(),
808-
migrations: [Version: (_ data: Data, _ decoder: JSONDecoder) async throws -> CodedType],
813+
migrations: [Version: (_ data: Data, _ decoder: JSONDecoder) async throws -> (id: IdentifierType, instance: CodedType)],
809814
directIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
810815
computedIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
811816
configuration: Configuration = .init()
@@ -817,11 +822,9 @@ extension Datastore where AccessMode == ReadWrite {
817822
codedType: codedType,
818823
identifierType: identifierType,
819824
encoder: { try encoder.encode($0) },
820-
decoders: migrations.mapValues({ migration in
821-
return { data in
822-
return try await migration(data, decoder)
823-
}
824-
}),
825+
decoders: migrations.mapValues { migration in
826+
{ data in try await migration(data, decoder) }
827+
},
825828
directIndexes: directIndexes,
826829
computedIndexes: computedIndexes,
827830
configuration: configuration
@@ -835,7 +838,7 @@ extension Datastore where AccessMode == ReadWrite {
835838
codedType: CodedType.Type = CodedType.self,
836839
identifierType: IdentifierType.Type,
837840
outputFormat: PropertyListSerialization.PropertyListFormat = .binary,
838-
migrations: [Version: (_ data: Data, _ decoder: PropertyListDecoder) async throws -> CodedType],
841+
migrations: [Version: (_ data: Data, _ decoder: PropertyListDecoder) async throws -> (id: IdentifierType, instance: CodedType)],
839842
directIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
840843
computedIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
841844
configuration: Configuration = .init()
@@ -852,11 +855,9 @@ extension Datastore where AccessMode == ReadWrite {
852855
codedType: codedType,
853856
identifierType: identifierType,
854857
encoder: { try encoder.encode($0) },
855-
decoders: migrations.mapValues({ migration in
856-
return { data in
857-
return try await migration(data, decoder)
858-
}
859-
}),
858+
decoders: migrations.mapValues { migration in
859+
{ data in try await migration(data, decoder) }
860+
},
860861
directIndexes: directIndexes,
861862
computedIndexes: computedIndexes,
862863
configuration: configuration
@@ -872,7 +873,7 @@ extension Datastore where AccessMode == ReadOnly {
872873
codedType: CodedType.Type = CodedType.self,
873874
identifierType: IdentifierType.Type,
874875
decoder: JSONDecoder = JSONDecoder(),
875-
migrations: [Version: (_ data: Data, _ decoder: JSONDecoder) async throws -> CodedType],
876+
migrations: [Version: (_ data: Data, _ decoder: JSONDecoder) async throws -> (id: IdentifierType, instance: CodedType)],
876877
directIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
877878
computedIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
878879
configuration: Configuration = .init()
@@ -883,11 +884,9 @@ extension Datastore where AccessMode == ReadOnly {
883884
version: version,
884885
codedType: codedType,
885886
identifierType: identifierType,
886-
decoders: migrations.mapValues({ migration in
887-
return { data in
888-
return try await migration(data, decoder)
889-
}
890-
}),
887+
decoders: migrations.mapValues { migration in
888+
{ data in try await migration(data, decoder) }
889+
},
891890
directIndexes: directIndexes,
892891
computedIndexes: computedIndexes,
893892
configuration: configuration
@@ -900,7 +899,7 @@ extension Datastore where AccessMode == ReadOnly {
900899
version: Version,
901900
codedType: CodedType.Type = CodedType.self,
902901
identifierType: IdentifierType.Type,
903-
migrations: [Version: (_ data: Data, _ decoder: PropertyListDecoder) async throws -> CodedType],
902+
migrations: [Version: (_ data: Data, _ decoder: PropertyListDecoder) async throws -> (id: IdentifierType, instance: CodedType)],
904903
directIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
905904
computedIndexes: [IndexPath<CodedType, _AnyIndexed>] = [],
906905
configuration: Configuration = .init()
@@ -913,11 +912,9 @@ extension Datastore where AccessMode == ReadOnly {
913912
version: version,
914913
codedType: codedType,
915914
identifierType: identifierType,
916-
decoders: migrations.mapValues({ migration in
917-
return { data in
918-
return try await migration(data, decoder)
919-
}
920-
}),
915+
decoders: migrations.mapValues { migration in
916+
{ data in try await migration(data, decoder) }
917+
},
921918
directIndexes: directIndexes,
922919
computedIndexes: computedIndexes,
923920
configuration: configuration
@@ -946,7 +943,12 @@ extension Datastore where CodedType: Identifiable, IdentifierType == CodedType.I
946943
codedType: codedType,
947944
identifierType: codedType.ID.self,
948945
encoder: encoder,
949-
decoders: decoders,
946+
decoders: decoders.mapValues { decoder in
947+
{ data in
948+
let instance = try await decoder(data)
949+
return (id: instance.id, instance: instance)
950+
}
951+
},
950952
directIndexes: directIndexes,
951953
computedIndexes: computedIndexes,
952954
configuration: configuration
@@ -973,7 +975,12 @@ extension Datastore where CodedType: Identifiable, IdentifierType == CodedType.I
973975
identifierType: codedType.ID.self,
974976
encoder: encoder,
975977
decoder: decoder,
976-
migrations: migrations,
978+
migrations: migrations.mapValues { migration in
979+
{ data, decoder in
980+
let instance = try await migration(data, decoder)
981+
return (id: instance.id, instance: instance)
982+
}
983+
},
977984
directIndexes: directIndexes,
978985
computedIndexes: computedIndexes,
979986
configuration: configuration
@@ -998,7 +1005,12 @@ extension Datastore where CodedType: Identifiable, IdentifierType == CodedType.I
9981005
codedType: codedType,
9991006
identifierType: codedType.ID.self,
10001007
outputFormat: outputFormat,
1001-
migrations: migrations,
1008+
migrations: migrations.mapValues { migration in
1009+
{ data, decoder in
1010+
let instance = try await migration(data, decoder)
1011+
return (id: instance.id, instance: instance)
1012+
}
1013+
},
10021014
directIndexes: directIndexes,
10031015
computedIndexes: computedIndexes,
10041016
configuration: configuration
@@ -1023,7 +1035,12 @@ extension Datastore where CodedType: Identifiable, IdentifierType == CodedType.I
10231035
version: version,
10241036
codedType: codedType,
10251037
identifierType: codedType.ID.self,
1026-
decoders: decoders,
1038+
decoders: decoders.mapValues { decoder in
1039+
{ data in
1040+
let instance = try await decoder(data)
1041+
return (id: instance.id, instance: instance)
1042+
}
1043+
},
10271044
directIndexes: directIndexes,
10281045
computedIndexes: computedIndexes,
10291046
configuration: configuration
@@ -1048,7 +1065,12 @@ extension Datastore where CodedType: Identifiable, IdentifierType == CodedType.I
10481065
codedType: codedType,
10491066
identifierType: codedType.ID.self,
10501067
decoder: decoder,
1051-
migrations: migrations,
1068+
migrations: migrations.mapValues { migration in
1069+
{ data, decoder in
1070+
let instance = try await migration(data, decoder)
1071+
return (id: instance.id, instance: instance)
1072+
}
1073+
},
10521074
directIndexes: directIndexes,
10531075
computedIndexes: computedIndexes,
10541076
configuration: configuration
@@ -1071,7 +1093,12 @@ extension Datastore where CodedType: Identifiable, IdentifierType == CodedType.I
10711093
version: version,
10721094
codedType: codedType,
10731095
identifierType: codedType.ID.self,
1074-
migrations: migrations,
1096+
migrations: migrations.mapValues { migration in
1097+
{ data, decoder in
1098+
let instance = try await migration(data, decoder)
1099+
return (id: instance.id, instance: instance)
1100+
}
1101+
},
10751102
directIndexes: directIndexes,
10761103
computedIndexes: computedIndexes,
10771104
configuration: configuration

Tests/CodableDatastoreTests/DiskTransactionTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ final class DiskTransactionTests: XCTestCase {
3535
version: Version.zero,
3636
codedType: TestStruct.self,
3737
identifierType: UUID.self,
38-
decoders: [.zero: { _ in TestStruct() }],
38+
decoders: [.zero: { _ in (id: UUID(), instance: TestStruct()) }],
3939
directIndexes: [],
4040
computedIndexes: [],
4141
configuration: .init()

0 commit comments

Comments
 (0)