import { AbstractPowerSyncDatabase } from '../client/AbstractPowerSyncDatabase.js'; import { DifferentialWatchedQuery } from '../client/watched/processors/DifferentialQueryProcessor.js'; import { ILogger } from '../utils/Logger.js'; import { Mutex } from '../utils/mutex.js'; import { AttachmentContext } from './AttachmentContext.js'; import { AttachmentRecord, AttachmentState } from './Schema.js'; /** * Service for querying and watching attachment records in the database. * * @internal */ export class AttachmentService { private mutex = new Mutex(); private context: AttachmentContext; constructor( private db: AbstractPowerSyncDatabase, private logger: ILogger, private tableName: string = 'attachments', archivedCacheLimit: number = 100 ) { this.context = new AttachmentContext(db, tableName, logger, archivedCacheLimit); } /** * Creates a differential watch query for active attachments requiring synchronization. * @returns Watch query that emits changes for queued uploads, downloads, and deletes */ watchActiveAttachments({ throttleMs }: { throttleMs?: number } = {}): DifferentialWatchedQuery { this.logger.info('Watching active attachments...'); const watch = this.db .query({ sql: /* sql */ ` SELECT * FROM ${this.tableName} WHERE state = ? OR state = ? OR state = ? ORDER BY timestamp ASC `, parameters: [AttachmentState.QUEUED_UPLOAD, AttachmentState.QUEUED_DOWNLOAD, AttachmentState.QUEUED_DELETE] }) .differentialWatch({ throttleMs }); return watch; } /** * Executes a callback with exclusive access to the attachment context. */ async withContext(callback: (context: AttachmentContext) => Promise): Promise { return this.mutex.runExclusive(async () => { return callback(this.context); }); } }