Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions Sources/SharingGRDBCore/FetchKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -310,11 +310,7 @@ public struct FetchKey<Value: Sendable>: SharedReaderKey {
continuation.resumeReturningInitialValue()
return
}
guard !isTesting else {
continuation.resume(with: Result { try database.read(request.fetch) })
return
}
let scheduler: any ValueObservationScheduler = scheduler ?? .async(onQueue: .main)
let scheduler: any ValueObservationScheduler = scheduler ?? ImmediateScheduler()
database.asyncRead { dbResult in
let result = dbResult.flatMap { db in
Result {
Expand Down Expand Up @@ -345,7 +341,7 @@ public struct FetchKey<Value: Sendable>: SharedReaderKey {
let observation = ValueObservation.tracking { db in
Result { try request.fetch(db) }
}
let scheduler: any ValueObservationScheduler = scheduler ?? .async(onQueue: .main)
let scheduler: any ValueObservationScheduler = scheduler ?? ImmediateScheduler()
#if canImport(Combine)
let dropFirst =
switch context {
Expand Down Expand Up @@ -434,3 +430,10 @@ private struct FetchOneRequest<Value: DatabaseValueConvertible>: FetchKeyRequest
public struct NotFound: Error {
public init() {}
}

private struct ImmediateScheduler: ValueObservationScheduler, Hashable {
func immediateInitialValue() -> Bool { true }
func schedule(_ action: @escaping @Sendable () -> Void) {
action()
}
}
76 changes: 76 additions & 0 deletions Tests/SharingGRDBTests/FetchAllTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import Dependencies
import DependenciesTestSupport
import Foundation
import SharingGRDB
import Testing

@Suite(.dependency(\.defaultDatabase, try .database()))
struct FetchAllTests {
@Dependency(\.defaultDatabase) var database

@MainActor
@Test func concurrency() async throws {
let count = 1_000
try await database.write { db in
try Record.delete().execute(db)
}

@FetchAll var records: [Record]

await withThrowingTaskGroup { group in
for index in 1...count {
group.addTask {
try await database.write { db in
try Record.insert(Record(id: index)).execute(db)
}
}
}
}

try await $records.load()
#expect(records == (1...count).map { Record(id: $0) })

await withThrowingTaskGroup { group in
for index in 1...(count/2) {
group.addTask {
try await database.write { db in
try Record.find(index * 2).delete().execute(db)
}
}
}
}

try await $records.load()
#expect(records == (0...(count/2-1)).map { Record(id: $0 * 2 + 1) })
}
}

@Table
private struct Record: Equatable {
let id: Int
@Column(as: Date.UnixTimeRepresentation.self)
var date = Date(timeIntervalSince1970: 42)
@Column(as: Date?.UnixTimeRepresentation.self)
var optionalDate: Date?
}
extension DatabaseWriter where Self == DatabaseQueue {
fileprivate static func database() throws -> DatabaseQueue {
let database = try DatabaseQueue()
try database.write { db in
try #sql(
"""
CREATE TABLE "records" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT
, "date" INTEGER NOT NULL DEFAULT 42
, "optionalDate" INTEGER
)
"""
)
.execute(db)
for _ in 1...3 {
_ = try Record.insert(Record.Draft()).execute(db)
}
}
return database
}
}
5 changes: 0 additions & 5 deletions Tests/SharingGRDBTests/FetchTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,26 @@ import Testing
struct FetchTests {
@Test func bareFetchAll() async throws {
@FetchAll var records: [Record]
try await Task.sleep(nanoseconds: 100_000_000)
#expect(records == [Record(id: 1), Record(id: 2), Record(id: 3)])
}

@Test func fetchAllWithQuery() async throws {
@FetchAll(Record.where { $0.id > 1 }) var records: [Record]
try await Task.sleep(nanoseconds: 100_000_000)
#expect(records == [Record(id: 2), Record(id: 3)])
}

@Test func fetchOneCountWithQuery() async throws {
@FetchOne(Record.where { $0.id > 1 }.count()) var recordsCount = 0
try await Task.sleep(nanoseconds: 100_000_000)
#expect(recordsCount == 2)
}

@Test func bareFetchOneOptional() async throws {
@FetchOne var record: Record?
try await Task.sleep(nanoseconds: 100_000_000)
#expect(record != nil)
}

@Test func fetchOneOptionalWithQuery() async throws {
@FetchOne(#sql("SELECT * FROM records LIMIT 1")) var record: Record?
try await Task.sleep(nanoseconds: 100_000_000)
#expect(record != nil)
}
}
Expand Down
12 changes: 6 additions & 6 deletions Tests/SharingGRDBTests/IntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ struct IntegrationTests {
_ = try SyncUp.insert(SyncUp.Draft(isActive: true, title: "Engineering"))
.execute(db)
}
try await Task.sleep(nanoseconds: 100_000_000)
try await $syncUps.load()
#expect(syncUps == [SyncUp(id: 1, isActive: true, title: "Engineering")])
try await database.write { db in
_ = try SyncUp.upsert(SyncUp.Draft(id: 1, isActive: false, title: "Engineering"))
.execute(db)
}
try await Task.sleep(nanoseconds: 100_000_000)
try await $syncUps.load()
#expect(syncUps == [])
try await database.write { db in
_ = try SyncUp.upsert(SyncUp.Draft(id: 1, isActive: true, title: "Engineering"))
.execute(db)
}
try await Task.sleep(nanoseconds: 100_000_000)
try await $syncUps.load()
#expect(syncUps == [SyncUp(id: 1, isActive: true, title: "Engineering")])
}

Expand All @@ -43,19 +43,19 @@ struct IntegrationTests {
_ = try SyncUp.insert(SyncUp.Draft(isActive: true, title: "Engineering"))
.execute(db)
}
try await Task.sleep(nanoseconds: 100_000_000)
try await $syncUps.load()
#expect(syncUps == [SyncUp(id: 1, isActive: true, title: "Engineering")])
try await database.write { db in
_ = try SyncUp.upsert(SyncUp.Draft(id: 1, isActive: false, title: "Engineering"))
.execute(db)
}
try await Task.sleep(nanoseconds: 100_000_000)
try await $syncUps.load()
#expect(syncUps == [])
try await database.write { db in
_ = try SyncUp.upsert(SyncUp.Draft(id: 1, isActive: true, title: "Engineering"))
.execute(db)
}
try await Task.sleep(nanoseconds: 100_000_000)
try await $syncUps.load()
#expect(syncUps == [SyncUp(id: 1, isActive: true, title: "Engineering")])
}
}
Expand Down
14 changes: 5 additions & 9 deletions Tests/SharingGRDBTests/SharingGRDBTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ import Testing

@Suite struct GRDBSharingTests {
@Test
func fetchOne() async throws {
try await withDependencies {
func fetchOne() throws {
try withDependencies {
$0.defaultDatabase = try DatabaseQueue()
} operation: {
@FetchOne(#sql("SELECT 1")) var bool = false
try await Task.sleep(nanoseconds: 100_000_000)
#expect(bool)
#expect($bool.loadError == nil)
}
Expand All @@ -30,13 +29,12 @@ import Testing
}
}

@Test func fetchSyntaxError() async throws {
try await withDependencies {
@Test func fetchSyntaxError() throws {
try withDependencies {
$0.defaultDatabase = try DatabaseQueue()
} operation: {
@FetchOne(#sql("SELEC 1")) var bool = false
#expect(bool == false)
try await Task.sleep(nanoseconds: 100_000_000)
#expect($bool.loadError is DatabaseError?)
let error = try #require($bool.loadError as? DatabaseError)
#expect(error.message == #"near "SELEC": syntax error"#)
Expand All @@ -49,20 +47,18 @@ import Testing
$0.defaultDatabase = try .database(named: name)
} operation: {
@SharedReader(.fetchAll(sql: "SELECT * FROM records")) var records1: [Record] = []
try await Task.sleep(nanoseconds: 100_000_000)
#expect(records1.map(\.id) == [1, 2, 3])

try await withDependencies {
$0.defaultDatabase = try .database(named: name)
} operation: {
@Dependency(\.defaultDatabase) var database2
@SharedReader(.fetchAll(sql: "SELECT * FROM records")) var records2: [Record] = []
try await Task.sleep(nanoseconds: 100_000_000)
#expect(records2.map(\.id) == [1, 2, 3])
try await database2.write { db in
_ = try Record.deleteOne(db, key: 1)
}
try await Task.sleep(nanoseconds: 100_000_000)
try await $records2.load()
#expect(records1.map(\.id) == [1, 2, 3])
#expect(records2.map(\.id) == [2, 3])
}
Expand Down