@@ -73,6 +73,7 @@ public final class SQLiteDatabase: DatabaseProtocol, @unchecked Sendable {
7373 self . sqliteVersion = sqliteVersion. description
7474 changeNotifier = CrossProcessChangeNotifier (
7575 databasePath: path,
76+ databaseChangePublisher: database. databaseChangePublisher ( ) ,
7677 onRemoteChange: { [ weak self] in
7778 self ? . triggerObservers. send ( )
7879 }
@@ -85,6 +86,10 @@ public final class SQLiteDatabase: DatabaseProtocol, @unchecked Sendable {
8586 changeNotifier. start ( )
8687 }
8788
89+ deinit {
90+ changeNotifier. stop ( )
91+ }
92+
8893 func resume( ) {
8994 NotificationCenter . default. post (
9095 name: Self . resumeNotification,
@@ -808,6 +813,14 @@ private enum Database {
808813 . mapToSQLiteError ( sql: sql)
809814 . eraseToAnyPublisher ( )
810815 }
816+
817+ func databaseChangePublisher( ) -> AnyPublisher < Void , Error > {
818+ let observation = DatabaseRegionObservation ( tracking: . fullDatabase)
819+ return observation
820+ . publisher ( in: writer)
821+ . map { _ in }
822+ . eraseToAnyPublisher ( )
823+ }
811824}
812825
813826private final class SQLitePublisher : Publisher , @unchecked Sendable {
@@ -817,8 +830,6 @@ private final class SQLitePublisher: Publisher, @unchecked Sendable {
817830 private let sql : SQL
818831 private let arguments : SQLiteArguments
819832 private let request : SQLRequest < Row >
820- private let trigger : AnyPublisher < Void , Never >
821- private let queue : DispatchQueue
822833
823834 private let subject = CurrentValueSubject < Output , Failure > ( [ ] )
824835 private var subscriptions = Locked < Set < AnyCancellable > > ( [ ] )
@@ -836,34 +847,31 @@ private final class SQLitePublisher: Publisher, @unchecked Sendable {
836847 sql: sql,
837848 arguments: arguments. statementArguments
838849 )
839- self . trigger = trigger
840- self . queue = queue
841850
842- var didFetchInitialValue = false
851+ let demands = Locked ( Demands { [ database, subject] in
852+ do {
853+ subject. send ( try database. read (
854+ sql, arguments: arguments
855+ ) )
856+ } catch {
857+ subject. send ( completion: . failure( error) )
858+ }
859+ } )
860+
843861 let observationSub = DatabaseRegionObservation ( tracking: [ request] )
844862 . publisher ( in: database. writer)
863+ . handleEvents ( receiveRequest: { demand in
864+ demands. access { demands in
865+ demands. receiveObservationDemand ( demand)
866+ }
867+ } )
845868 . receive ( on: queue)
846869 . tryMap { _ in try database. read ( sql, arguments: arguments) }
847- . handleEvents (
848- receiveRequest: { [ subject] demand in
849- // NOTE: To match the previous version's behavior, we
850- // fetch the initial value as soon as a downstream
851- // publisher requests some values.
852- guard !didFetchInitialValue,
853- demand > . none
854- else { return }
855-
856- didFetchInitialValue = true
857-
858- do {
859- subject. send ( try database. read (
860- sql, arguments: arguments
861- ) )
862- } catch {
863- subject. send ( completion: . failure( error) )
864- }
870+ . handleEvents ( receiveRequest: { demand in
871+ demands. access { demands in
872+ demands. receiveObservationDownstreamDemand ( demand)
865873 }
866- )
874+ } )
867875 . sink (
868876 receiveCompletion: { [ subject] completion in
869877 subject. send ( completion: completion)
@@ -874,6 +882,11 @@ private final class SQLitePublisher: Publisher, @unchecked Sendable {
874882 )
875883
876884 let triggerSub = trigger
885+ . handleEvents ( receiveRequest: { demand in
886+ demands. access { demands in
887+ demands. receiveTriggerDemand ( demand)
888+ }
889+ } )
877890 . receive ( on: queue)
878891 . tryMap { _ in try database. read ( sql, arguments: arguments) }
879892 . sink (
@@ -963,3 +976,62 @@ private extension GRDB.Database {
963976 }
964977 }
965978}
979+
980+ private enum Demands {
981+ struct Source : OptionSet {
982+ let rawValue : Int
983+
984+ static let observation = Source ( rawValue: 1 << 0 )
985+ static let observationDownstream = Source ( rawValue: 1 << 1 )
986+ static let trigger = Source ( rawValue: 1 << 2 )
987+
988+ var isComplete : Bool {
989+ self == [ . observation, . observationDownstream, . trigger]
990+ }
991+ }
992+
993+ case finished
994+ case waiting( Source , ( ) -> Void )
995+
996+ init ( _ block: @escaping ( ) -> Void ) {
997+ self = . waiting( Source ( ) , block)
998+ }
999+
1000+ mutating func receiveObservationDemand(
1001+ _ demand: Subscribers . Demand
1002+ ) {
1003+ receiveDemand ( demand, source: . observation)
1004+ }
1005+
1006+ mutating func receiveObservationDownstreamDemand(
1007+ _ demand: Subscribers . Demand
1008+ ) {
1009+ receiveDemand ( demand, source: . observationDownstream)
1010+ }
1011+
1012+ mutating func receiveTriggerDemand(
1013+ _ demand: Subscribers . Demand
1014+ ) {
1015+ receiveDemand ( demand, source: . trigger)
1016+ }
1017+
1018+ private mutating func receiveDemand(
1019+ _ demand: Subscribers . Demand ,
1020+ source: Source
1021+ ) {
1022+ guard case . waiting( var sources, let block) = self ,
1023+ demand > . none
1024+ else {
1025+ return
1026+ }
1027+
1028+ sources. insert ( source)
1029+
1030+ if sources. isComplete {
1031+ self = . finished
1032+ block ( )
1033+ } else {
1034+ self = . waiting( sources, block)
1035+ }
1036+ }
1037+ }
0 commit comments