Skip to content
Merged
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
31 changes: 13 additions & 18 deletions PowerSync/PowerSync.Common/Attachments/SyncingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,40 +113,36 @@ private async Task StopSyncInternalAsync()
/// Runs one sync pass: fetches active attachments, processes them, then prunes archived rows.
/// </summary>
/// <returns>A task that completes when the pass has finished.</returns>
public Task RunSyncPassAsync() => attachmentService.WithContextAsync(async ctx =>
public async Task RunSyncPassAsync()
{
var active = await ctx.GetActiveAttachmentsAsync();
await ProcessAttachmentsAsync(active, ctx);
await DeleteArchivedAttachmentsAsync(ctx);
});
var active = await attachmentService.WithContextAsync(ctx => ctx.GetActiveAttachmentsAsync());
await ProcessAttachmentsAsync(active);
await attachmentService.WithContextAsync(ctx => DeleteArchivedAttachmentsAsync(ctx));
Comment on lines +118 to +120
}

/// <summary>
/// Processes attachments based on their state. Updates are saved in a single batch.
/// Processes attachments based on their state. Each state change is persisted as soon as its
/// transfer completes.
/// </summary>
/// <param name="attachments">Attachment records to process.</param>
/// <param name="context">Attachment context for database operations.</param>
/// <returns>A task that completes once all attachments have been processed and saved.</returns>
public async Task ProcessAttachmentsAsync(IReadOnlyList<Attachment> attachments, AttachmentContext context)
/// <returns>A task that completes once all attachments have been processed.</returns>
public async Task ProcessAttachmentsAsync(IReadOnlyList<Attachment> attachments)
{
var updates = new List<Attachment>();

foreach (var attachment in attachments)
{
Attachment? changed = attachment.State switch
{
AttachmentState.QueuedUpload => await UploadAttachmentAsync(attachment),
AttachmentState.QueuedDownload => await DownloadAttachmentAsync(attachment),
AttachmentState.QueuedDelete => await DeleteAttachmentAsync(attachment, context),
AttachmentState.QueuedDelete => await DeleteAttachmentAsync(attachment),
_ => null,
};

if (changed is not null)
{
updates.Add(changed);
await attachmentService.WithContextAsync(ctx => ctx.SaveAttachmentsAsync([changed]));
Comment on lines 133 to +143
}
}

await context.SaveAttachmentsAsync(updates);
}

/// <summary>
Expand Down Expand Up @@ -231,9 +227,8 @@ public async Task ProcessAttachmentsAsync(IReadOnlyList<Attachment> attachments,
/// On failure, defers to <see cref="IAttachmentErrorHandler"/> or archives.
/// </summary>
/// <param name="attachment">The attachment to delete.</param>
/// <param name="context">The attachment context for database operations.</param>
/// <returns>The archived attachment, or <c>null</c> on success or retry.</returns>
public async Task<Attachment?> DeleteAttachmentAsync(Attachment attachment, AttachmentContext context)
public async Task<Attachment?> DeleteAttachmentAsync(Attachment attachment)
{
try
{
Expand All @@ -243,7 +238,7 @@ public async Task ProcessAttachmentsAsync(IReadOnlyList<Attachment> attachments,
await localStorage.DeleteFileAsync(attachment.LocalUri);
}

await context.DeleteAttachmentAsync(attachment.Id);
await attachmentService.WithContextAsync(ctx => ctx.DeleteAttachmentAsync(attachment.Id));
return null;
}
catch (Exception error)
Expand Down
Loading