|
| 1 | +import type { SyncStatus } from "./SyncStatus.js"; |
| 2 | + |
| 3 | +// (bucket, progress) pairs |
| 4 | +export type InternalProgressInformation = Record<string, { |
| 5 | + priority: number, // Priority of the associated buckets |
| 6 | + atLast: number, // Total ops at last completed sync, or 0 |
| 7 | + sinceLast: number, // Total ops _since_ the last completed sync. |
| 8 | + targetCount: number, // Total opcount for next checkpoint as indicated by service. |
| 9 | + }>; |
| 10 | + |
| 11 | +/** |
| 12 | + * The priority used by the core extension to indicate that a full sync was completed. |
| 13 | + */ |
| 14 | +export const FULL_SYNC_PRIORITY = 2147483647; |
| 15 | + |
| 16 | +/** |
| 17 | + * Information about a progressing download made by the PowerSync SDK. |
| 18 | + * |
| 19 | + * To obtain these values, use {@link SyncProgress}, available through |
| 20 | + * {@link SyncStatus#downloadProgress}. |
| 21 | + */ |
| 22 | +export interface ProgressWithOperations { |
| 23 | + /** |
| 24 | + * The total amount of operations to download for the current sync iteration |
| 25 | + * to complete. |
| 26 | + */ |
| 27 | + total: number; |
| 28 | + /** |
| 29 | + * The amount of operations that have already been downloaded. |
| 30 | + */ |
| 31 | + completed: number; |
| 32 | + |
| 33 | + /** |
| 34 | + * Relative progress, as {@link completed} of {@link total}. This will be a number |
| 35 | + * between `0.0` and `1.0`. |
| 36 | + */ |
| 37 | + fraction: number; |
| 38 | +}; |
| 39 | + |
| 40 | +/** |
| 41 | + * Provides realtime progress on how PowerSync is downloading rows. |
| 42 | + * |
| 43 | + * The reported progress always reflects the status towards th end of a sync iteration (after |
| 44 | + * which a consistent snapshot of all buckets is available locally). |
| 45 | + * |
| 46 | + * In rare cases (in particular, when a [compacting](https://docs.powersync.com/usage/lifecycle-maintenance/compacting-buckets) |
| 47 | + * operation takes place between syncs), it's possible for the returned numbers to be slightly |
| 48 | + * inaccurate. For this reason, {@link SyncProgress} should be seen as an approximation of progress. |
| 49 | + * The information returned is good enough to build progress bars, but not exact enough to track |
| 50 | + * individual download counts. |
| 51 | + * |
| 52 | + * Also note that data is downloaded in bulk, which means that individual counters are unlikely |
| 53 | + * to be updated one-by-one. |
| 54 | + */ |
| 55 | +export class SyncProgress { |
| 56 | + constructor(protected internal: InternalProgressInformation) {} |
| 57 | + |
| 58 | + get untilCompletion(): ProgressWithOperations { |
| 59 | + return this.untilPriority(FULL_SYNC_PRIORITY); |
| 60 | + } |
| 61 | + |
| 62 | + untilPriority(priority: number): ProgressWithOperations { |
| 63 | + let total = 0; |
| 64 | + let downloaded = 0; |
| 65 | + |
| 66 | + for (const progress of Object.values(this.internal)) { |
| 67 | + // Include higher-priority buckets, which are represented by lower numbers. |
| 68 | + if (progress.priority <= priority) { |
| 69 | + downloaded += progress.sinceLast; |
| 70 | + total += progress.targetCount - progress.atLast; |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + let progress = total == 0 ? 0.0 : downloaded / total; |
| 75 | + return { |
| 76 | + total, |
| 77 | + completed: downloaded, |
| 78 | + fraction: progress, |
| 79 | + } |
| 80 | + } |
| 81 | +} |
0 commit comments