|
| 1 | +import Foundation |
| 2 | + |
| 3 | +/// Information uniquely identifying a sync stream that can be subscribed to. |
| 4 | +public protocol SyncStreamDescription: Sendable { |
| 5 | + /// The name of the sync stream as it appeaers in the stream definition for the PowerSync service. |
| 6 | + var name: String { get } |
| 7 | + /// The parameters used to subscribe to the stream, if any. |
| 8 | + /// |
| 9 | + /// The same stream can be subscribed to multiple times with different parameters. |
| 10 | + var parameters: JsonParam? { get } |
| 11 | +} |
| 12 | + |
| 13 | +/// A handle to a ``SyncStreamDescription`` that allows subscribing to the stream. |
| 14 | +/// |
| 15 | +/// To obtain an instance of ``SyncStream``, call ``PowerSyncDatabase/syncStream``. |
| 16 | +public protocol SyncStream: SyncStreamDescription { |
| 17 | + /// Creates a new subscription on this stream. |
| 18 | + /// |
| 19 | + /// As long as a subscription is active on the stream, the sync client will request it from the sync service. |
| 20 | + /// |
| 21 | + /// This call is generally quite cheap and can be issued frequently, e.g. when a view needing data from the stream is activated. |
| 22 | + func subscribe(ttl: TimeInterval?, priority: BucketPriority?) async throws -> any SyncStreamSubscription |
| 23 | + |
| 24 | + /// Unsubscribes all existing subscriptions on this stream. |
| 25 | + /// |
| 26 | + /// This is a potentially unsafe method since it interferes with other subscriptions. A better option is to call |
| 27 | + /// ``SyncStreamSubscription/unsubscribe``. |
| 28 | + func unsubscribeAll() async throws |
| 29 | +} |
| 30 | + |
| 31 | +extension SyncStream { |
| 32 | + |
| 33 | + public func subscribe() async throws -> any SyncStreamSubscription { |
| 34 | + return try await subscribe(ttl: nil, priority: nil) |
| 35 | + } |
| 36 | +} |
| 37 | + |
| 38 | +/// A ``SyncStream`` that has an active subscription. |
| 39 | +public protocol SyncStreamSubscription: SyncStreamDescription { |
| 40 | + /// An asynchronous function that completes once data on this stream has been synced. |
| 41 | + func waitForFirstSync() async throws |
| 42 | + /// Removes this subscription. |
| 43 | + /// |
| 44 | + /// Once all ``SyncStreamSubscription``s for a ``SyncStream`` have been unsubscribed, the `ttl` |
| 45 | + /// for that stream thats running. When it expires without subscribing again, the stream will be evicted. |
| 46 | + func unsubscribe() async throws |
| 47 | +} |
| 48 | + |
| 49 | +/// Information about a subscribed sync stream. |
| 50 | +/// |
| 51 | +/// This includes the ``SyncStreamDescription`` along with information about the current sync status. |
| 52 | +public struct SyncSubscriptionDescription: SyncStreamDescription { |
| 53 | + public let name: String |
| 54 | + public let parameters: JsonParam? |
| 55 | + /// Whether this stream is active, meaning that the subscription has been acknowledged by the sync service. |
| 56 | + public let active: Bool |
| 57 | + /// Whether this stream subscription is included by default, regardless of whether the stream has explicitly |
| 58 | + /// been subscribed to or not. |
| 59 | + /// |
| 60 | + /// Default streams are created by applying `auto_subscribe: true` in their definition on the sync service. |
| 61 | + /// |
| 62 | + /// It's possible for both ``SyncSubscriptionDescription/isDefault`` and |
| 63 | + /// ``SyncSubscriptionDescription/hasExplicitSubscription`` to be true at the same time. This |
| 64 | + /// happens when a default stream was subscribed to explicitly. |
| 65 | + public let isDefault: Bool |
| 66 | + /// Whether this stream has been subscribed to explicitly. |
| 67 | + /// |
| 68 | + /// It's possible for both ``SyncSubscriptionDescription/isDefault`` and |
| 69 | + /// ``SyncSubscriptionDescription/hasExplicitSubscription`` to be true at the same time. This |
| 70 | + /// happens when a default stream was subscribed to explicitly. |
| 71 | + public let hasExplicitSubscription: Bool |
| 72 | + /// For sync streams that have a time-to-live, the current time at which the stream would expire if not subscribed to |
| 73 | + /// again. |
| 74 | + public let expiresAt: TimeInterval? |
| 75 | + /// If ``SyncSubscriptionDescription/hasSynced`` is true, the last time data from this stream has been synced. |
| 76 | + public let lastSyncedAt: TimeInterval? |
| 77 | + |
| 78 | + /// Whether this stream has been synced at least once. |
| 79 | + public var hasSynced: Bool { |
| 80 | + get { |
| 81 | + return self.expiresAt != nil |
| 82 | + } |
| 83 | + } |
| 84 | +} |
0 commit comments