From c20fd44d47bf8f9ed22d27b8d3f2f1ab3b66c173 Mon Sep 17 00:00:00 2001 From: Manrich121 Date: Wed, 1 Nov 2023 14:46:45 +0200 Subject: [PATCH] Update @journeyapps/powersync-sdk-common to latest 0.1.0. Make `newAttachmentRecord` async --- packages/powersync-attachments/CHANGELOG.md | 2 +- packages/powersync-attachments/package.json | 2 +- .../src/AbstractAttachmentQueue.ts | 152 ++++++------------ yarn.lock | 13 -- 4 files changed, 55 insertions(+), 114 deletions(-) diff --git a/packages/powersync-attachments/CHANGELOG.md b/packages/powersync-attachments/CHANGELOG.md index c41278c6..61071b17 100644 --- a/packages/powersync-attachments/CHANGELOG.md +++ b/packages/powersync-attachments/CHANGELOG.md @@ -2,4 +2,4 @@ ## 0.0.1 -Initial release. \ No newline at end of file +Initial version. \ No newline at end of file diff --git a/packages/powersync-attachments/package.json b/packages/powersync-attachments/package.json index 37cd96b3..27d23f30 100644 --- a/packages/powersync-attachments/package.json +++ b/packages/powersync-attachments/package.json @@ -19,7 +19,7 @@ "devDependencies": { }, "dependencies": { - "@journeyapps/powersync-sdk-common": "0.0.2" + "@journeyapps/powersync-sdk-common": "0.1.0" }, "repository": "https://github.com/journeyapps/powersync-react-native-sdk", "author": "JOURNEYAPPS", diff --git a/packages/powersync-attachments/src/AbstractAttachmentQueue.ts b/packages/powersync-attachments/src/AbstractAttachmentQueue.ts index 3aee85f0..a6ea5d67 100644 --- a/packages/powersync-attachments/src/AbstractAttachmentQueue.ts +++ b/packages/powersync-attachments/src/AbstractAttachmentQueue.ts @@ -1,9 +1,6 @@ -import { - AbstractPowerSyncDatabase, - Transaction, -} from "@journeyapps/powersync-sdk-common"; -import { ATTACHMENT_TABLE, AttachmentRecord, AttachmentState } from "./Schema"; -import { EncodingType, StorageAdapter } from "./StorageAdapter"; +import { AbstractPowerSyncDatabase, Transaction } from '@journeyapps/powersync-sdk-common'; +import { ATTACHMENT_TABLE, AttachmentRecord, AttachmentState } from './Schema'; +import { EncodingType, StorageAdapter } from './StorageAdapter'; export interface AttachmentQueueOptions { powersync: AbstractPowerSyncDatabase; @@ -16,6 +13,9 @@ export interface AttachmentQueueOptions { * How many attachments to keep in the cache */ cacheLimit?: number; + /** + * The name of the directory where attachments are stored on the device, not the full path + */ attachmentDirectoryName?: string; /** * Whether to mark the initial watched attachment IDs to be synced @@ -23,17 +23,14 @@ export interface AttachmentQueueOptions { performInitialSync?: boolean; } -export const DEFAULT_ATTACHMENT_QUEUE_OPTIONS: Partial = - { - attachmentDirectoryName: "attachments", - syncInterval: 30_000, - cacheLimit: 100, - performInitialSync: true, - }; - -export abstract class AbstractAttachmentQueue< - T extends AttachmentQueueOptions = AttachmentQueueOptions -> { +export const DEFAULT_ATTACHMENT_QUEUE_OPTIONS: Partial = { + attachmentDirectoryName: 'attachments', + syncInterval: 30_000, + cacheLimit: 100, + performInitialSync: true +}; + +export abstract class AbstractAttachmentQueue { uploading: boolean; downloading: boolean; initialSync: boolean; @@ -43,7 +40,7 @@ export abstract class AbstractAttachmentQueue< constructor(options: T) { this.options = { ...DEFAULT_ATTACHMENT_QUEUE_OPTIONS, - ...options, + ...options }; this.downloadQueue = new Set(); this.uploading = false; @@ -65,9 +62,7 @@ export abstract class AbstractAttachmentQueue< /** * Create a new AttachmentRecord, this gets called when the attachment id is not found in the database. */ - abstract newAttachmentRecord( - record?: Partial - ): AttachmentRecord; + abstract newAttachmentRecord(record?: Partial): Promise; protected get powersync() { return this.options.powersync; @@ -82,9 +77,7 @@ export abstract class AbstractAttachmentQueue< } get storageDirectory() { - return `${this.storage.getUserStorageDirectory()}${ - this.options.attachmentDirectoryName - }`; + return `${this.storage.getUserStorageDirectory()}${this.options.attachmentDirectoryName}`; } async init() { @@ -110,7 +103,7 @@ export abstract class AbstractAttachmentQueue< async watchAttachmentIds() { for await (const ids of this.attachmentIds()) { - const _ids = `${ids.map((id) => `'${id}'`).join(",")}`; + const _ids = `${ids.map((id) => `'${id}'`).join(',')}`; console.debug(`Queuing for sync, attachment IDs: [${_ids}]`); if (this.initialSync) { @@ -127,55 +120,43 @@ export abstract class AbstractAttachmentQueue< ); } - const attachmentsInDatabase = - await this.powersync.getAll( - `SELECT * FROM ${this.table} WHERE state < ${AttachmentState.ARCHIVED}` - ); + const attachmentsInDatabase = await this.powersync.getAll( + `SELECT * FROM ${this.table} WHERE state < ${AttachmentState.ARCHIVED}` + ); for (const id of ids) { const record = attachmentsInDatabase.find((r) => r.id == id); // 1. ID is not in the database if (!record) { - const newRecord = this.newAttachmentRecord({ + const newRecord = await this.newAttachmentRecord({ id: id, - state: AttachmentState.QUEUED_SYNC, + state: AttachmentState.QUEUED_SYNC }); - console.debug( - `Attachment (${id}) not found in database, creating new record` - ); + console.debug(`Attachment (${id}) not found in database, creating new record`); await this.saveToQueue(newRecord); - } else if ( - record.local_uri == null || - !(await this.storage.fileExists(record.local_uri)) - ) { + } else if (record.local_uri == null || !(await this.storage.fileExists(record.local_uri))) { // 2. Attachment in database but no local file, mark as queued download - console.debug( - `Attachment (${id}) found in database but no local file, marking as queued download` - ); + console.debug(`Attachment (${id}) found in database but no local file, marking as queued download`); await this.update({ ...record, - state: AttachmentState.QUEUED_DOWNLOAD, + state: AttachmentState.QUEUED_DOWNLOAD }); } } // 3. Attachment in database and not in AttachmentIds, mark as archived await this.powersync.execute( - `UPDATE ${this.table} SET state = ${ + `UPDATE ${this.table} SET state = ${AttachmentState.ARCHIVED} WHERE state < ${ AttachmentState.ARCHIVED - } WHERE state < ${AttachmentState.ARCHIVED} AND id NOT IN (${ids - .map((id) => `'${id}'`) - .join(",")})` + } AND id NOT IN (${ids.map((id) => `'${id}'`).join(',')})` ); } } - async saveToQueue( - record: Omit - ): Promise { + async saveToQueue(record: Omit): Promise { const updatedRecord: AttachmentRecord = { ...record, - timestamp: new Date().getTime(), + timestamp: new Date().getTime() }; await this.powersync.execute( @@ -187,7 +168,7 @@ export abstract class AbstractAttachmentQueue< updatedRecord.local_uri || null, updatedRecord.media_type || null, updatedRecord.size || null, - updatedRecord.state, + updatedRecord.state ] ); @@ -195,13 +176,10 @@ export abstract class AbstractAttachmentQueue< } async record(id: string): Promise { - return this.powersync.getOptional( - `SELECT * FROM ${this.table} WHERE id = ?`, - [id] - ); + return this.powersync.getOptional(`SELECT * FROM ${this.table} WHERE id = ?`, [id]); } - async update(record: Omit): Promise { + async update(record: Omit): Promise { const timestamp = new Date().getTime(); await this.powersync.execute( `UPDATE ${this.table} @@ -213,15 +191,7 @@ export abstract class AbstractAttachmentQueue< media_type = ?, state = ? WHERE id = ?`, - [ - timestamp, - record.filename, - record.local_uri || null, - record.size, - record.media_type, - record.state, - record.id, - ] + [timestamp, record.filename, record.local_uri || null, record.size, record.media_type, record.state, record.id] ); } @@ -246,7 +216,7 @@ export abstract class AbstractAttachmentQueue< try { // Delete file on storage await this.storage.deleteFile(uri, { - filename: record.filename, + filename: record.filename }); } catch (e) { console.error(e); @@ -269,41 +239,37 @@ export abstract class AbstractAttachmentQueue< async uploadAttachment(record: AttachmentRecord) { if (!record.local_uri) { - throw new Error( - `No local_uri for record ${JSON.stringify(record, null, 2)}` - ); + throw new Error(`No local_uri for record ${JSON.stringify(record, null, 2)}`); } try { if (!(await this.storage.fileExists(record.local_uri))) { console.warn(`File for ${record.id} does not exist, skipping upload`); await this.update({ ...record, - state: AttachmentState.QUEUED_DOWNLOAD, + state: AttachmentState.QUEUED_DOWNLOAD }); return true; } const fileBuffer = await this.storage.readFile(record.local_uri, { encoding: EncodingType.Base64, - mediaType: record.media_type, + mediaType: record.media_type }); await this.storage.uploadFile(record.filename, fileBuffer, { - mediaType: record.media_type, + mediaType: record.media_type }); // Mark as uploaded await this.update({ ...record, state: AttachmentState.SYNCED }); console.debug(`Uploaded attachment "${record.id}" to Cloud Storage`); return true; } catch (e: any) { - if (e.error == "Duplicate") { + if (e.error == 'Duplicate') { console.debug(`File already uploaded, marking ${record.id} as synced`); await this.update({ ...record, state: AttachmentState.SYNCED }); return false; } - console.error( - `UploadAttachment error for record ${JSON.stringify(record, null, 2)}` - ); + console.error(`UploadAttachment error for record ${JSON.stringify(record, null, 2)}`); return false; } } @@ -313,9 +279,7 @@ export abstract class AbstractAttachmentQueue< record.local_uri = this.getLocalUri(record.filename); } if (await this.storage.fileExists(record.local_uri)) { - console.debug( - `Local file already downloaded, marking "${record.id}" as synced` - ); + console.debug(`Local file already downloaded, marking "${record.id}" as synced`); await this.update({ ...record, state: AttachmentState.SYNCED }); return true; } @@ -328,37 +292,28 @@ export abstract class AbstractAttachmentQueue< const reader = new FileReader(); reader.onloadend = () => { // remove the header from the result: 'data:*/*;base64,' - resolve( - reader.result?.toString().replace(/^data:.+;base64,/, "") || "" - ); + resolve(reader.result?.toString().replace(/^data:.+;base64,/, '') || ''); }; reader.onerror = reject; reader.readAsDataURL(fileBlob); }); // Ensure directory exists - await this.storage.makeDir(record.local_uri.replace(record.filename, "")); + await this.storage.makeDir(record.local_uri.replace(record.filename, '')); // Write the file await this.storage.writeFile(record.local_uri, base64Data, { - encoding: EncodingType.Base64, + encoding: EncodingType.Base64 }); await this.update({ ...record, media_type: fileBlob.type, - state: AttachmentState.SYNCED, + state: AttachmentState.SYNCED }); console.debug(`Downloaded attachment "${record.id}"`); return true; } catch (e) { - console.error( - `Download attachment error for record ${JSON.stringify( - record, - null, - 2 - )}`, - e - ); + console.error(`Download attachment error for record ${JSON.stringify(record, null, 2)}`, e); } return false; } @@ -409,9 +364,9 @@ export abstract class AbstractAttachmentQueue< } record = await this.getNextUploadRecord(); } - console.debug("Finished uploading attachments"); + console.debug('Finished uploading attachments'); } catch (error) { - console.error("Upload failed:", error); + console.error('Upload failed:', error); } finally { this.uploading = false; } @@ -473,9 +428,9 @@ export abstract class AbstractAttachmentQueue< } await this.downloadRecord(record); } - console.debug("Finished downloading attachments"); + console.debug('Finished downloading attachments'); } catch (e) { - console.error("Downloads failed:", e); + console.error('Downloads failed:', e); } finally { this.downloading = false; } @@ -486,8 +441,7 @@ export abstract class AbstractAttachmentQueue< } async expireCache() { - const res = await this.powersync - .getAll(`SELECT * FROM ${this.table} + const res = await this.powersync.getAll(`SELECT * FROM ${this.table} WHERE state = ${AttachmentState.SYNCED} OR state = ${AttachmentState.ARCHIVED} ORDER BY diff --git a/yarn.lock b/yarn.lock index 0f6bbb49..61188976 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2141,19 +2141,6 @@ dependencies: "@journeyapps/powersync-sdk-common" "^0.0.1" -"@journeyapps/powersync-sdk-common@0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@journeyapps/powersync-sdk-common/-/powersync-sdk-common-0.0.2.tgz#2a7073f21491e85b4bb434c46b9833f5401579bd" - integrity sha512-J90yVpv1L+zmVy8PnMCo1KMur9Zq1IwNngyuhais2rmOIMzZzMzTE6sdcUlioq/cphI0wOagUEXcyE8+iLbptA== - dependencies: - async-mutex "^0.4.0" - can-ndjson-stream "^1.0.2" - event-iterator "^2.0.0" - js-logger "^1.6.1" - lodash "^4.17.21" - object-hash "^3.0.0" - uuid "^3.0.0" - "@journeyapps/powersync-sdk-common@^0.0.1", "@journeyapps/powersync-sdk-common@^0.0.1-alpha.0": version "0.0.1" resolved "https://registry.yarnpkg.com/@journeyapps/powersync-sdk-common/-/powersync-sdk-common-0.0.1.tgz#8ff1a440a91ef7bbc488a1b3752cc344f4a6ee35"