Skip to content

Commit

Permalink
Add CustomCollection.reconcile
Browse files Browse the repository at this point in the history
  • Loading branch information
finestructure committed Oct 9, 2024
1 parent 37e3902 commit d7b0496
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 0 deletions.
31 changes: 31 additions & 0 deletions Sources/App/Models/CustomCollection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,34 @@ final class CustomCollection: @unchecked Sendable, Model, Content {
}

}


extension CustomCollection {
func reconcile(on database: Database, packageURLs: [URL]) async throws {
let incoming: [Package.Id: Package] = .init(
packages: try await Package.query(on: database)
.filter(by: packageURLs)
.all()
)
try await $packages.load(on: database)
let existing: [Package.Id: Package] = .init(packages: packages)
let newIDs = Set(incoming.keys).subtracting(Set(existing.keys))
try await $packages.attach(incoming[newIDs], on: database)
let removedIDs = Set(existing.keys).subtracting(Set(incoming.keys))
try await $packages.detach(existing[removedIDs], on: database)
}
}


private extension [Package.Id: Package] {
init(packages: [Package]) {
self.init(
packages.compactMap({ pkg in pkg.id.map({ ($0, pkg) }) }),
uniquingKeysWith: { (first, second) in first }
)
}

subscript(ids: some Collection<Package.Id>) -> [Package] {
Array(ids.compactMap { self[$0] })
}
}
55 changes: 55 additions & 0 deletions Tests/AppTests/CustomCollectionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,59 @@ class CustomCollectionTests: AppTestCase {
}
}

func test_CustomCollection_reconcile() async throws {
// Test reconciliation of a custom collection against a list of package URLs
let collection = CustomCollection(id: .id0, name: "List", url: "https://github.com/foo/bar/list.json")
try await collection.save(on: app.db)
try await Package(id: .id1, url: URL("https://a")).save(on: app.db)
try await Package(id: .id2, url: URL("https://b")).save(on: app.db)

do { // Initial set of URLs
// MUT
try await collection.reconcile(on: app.db, packageURLs: [URL("https://a")])

do { // validate
let count = try await CustomCollectionPackage.query(on: app.db).count()
XCTAssertEqual(count, 1)
let collection = try await CustomCollection.find(.id0, on: app.db).unwrap()
try await collection.$packages.load(on: app.db)
XCTAssertEqual(collection.packages.map(\.url), ["https://a"])
}
}

do { // Add more URLs
// MUT
try await collection.reconcile(on: app.db, packageURLs: [
URL("https://a"),
URL("https://b")
])

do { // validate
let count = try await CustomCollectionPackage.query(on: app.db).count()
XCTAssertEqual(count, 2)
let collection = try await CustomCollection.find(.id0, on: app.db).unwrap()
try await collection.$packages.load(on: app.db)
XCTAssertEqual(collection.packages.map(\.url).sorted(), [
"https://a",
"https://b"
])
}
}

do { // Remove URLs
// MUT
try await collection.reconcile(on: app.db, packageURLs: [
URL("https://b")
])

do { // validate
let count = try await CustomCollectionPackage.query(on: app.db).count()
XCTAssertEqual(count, 1)
let collection = try await CustomCollection.find(.id0, on: app.db).unwrap()
try await collection.$packages.load(on: app.db)
XCTAssertEqual(collection.packages.map(\.url), ["https://b"])
}
}
}

}

0 comments on commit d7b0496

Please sign in to comment.