Skip to content

Commit c20fd44

Browse files
committed
Update @journeyapps/powersync-sdk-common to latest 0.1.0. Make newAttachmentRecord async
1 parent 2032643 commit c20fd44

File tree

4 files changed

+55
-114
lines changed

4 files changed

+55
-114
lines changed

packages/powersync-attachments/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
## 0.0.1
44

5-
Initial release.
5+
Initial version.

packages/powersync-attachments/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"devDependencies": {
2020
},
2121
"dependencies": {
22-
"@journeyapps/powersync-sdk-common": "0.0.2"
22+
"@journeyapps/powersync-sdk-common": "0.1.0"
2323
},
2424
"repository": "https://github.com/journeyapps/powersync-react-native-sdk",
2525
"author": "JOURNEYAPPS",

packages/powersync-attachments/src/AbstractAttachmentQueue.ts

Lines changed: 53 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
import {
2-
AbstractPowerSyncDatabase,
3-
Transaction,
4-
} from "@journeyapps/powersync-sdk-common";
5-
import { ATTACHMENT_TABLE, AttachmentRecord, AttachmentState } from "./Schema";
6-
import { EncodingType, StorageAdapter } from "./StorageAdapter";
1+
import { AbstractPowerSyncDatabase, Transaction } from '@journeyapps/powersync-sdk-common';
2+
import { ATTACHMENT_TABLE, AttachmentRecord, AttachmentState } from './Schema';
3+
import { EncodingType, StorageAdapter } from './StorageAdapter';
74

85
export interface AttachmentQueueOptions {
96
powersync: AbstractPowerSyncDatabase;
@@ -16,24 +13,24 @@ export interface AttachmentQueueOptions {
1613
* How many attachments to keep in the cache
1714
*/
1815
cacheLimit?: number;
16+
/**
17+
* The name of the directory where attachments are stored on the device, not the full path
18+
*/
1919
attachmentDirectoryName?: string;
2020
/**
2121
* Whether to mark the initial watched attachment IDs to be synced
2222
*/
2323
performInitialSync?: boolean;
2424
}
2525

26-
export const DEFAULT_ATTACHMENT_QUEUE_OPTIONS: Partial<AttachmentQueueOptions> =
27-
{
28-
attachmentDirectoryName: "attachments",
29-
syncInterval: 30_000,
30-
cacheLimit: 100,
31-
performInitialSync: true,
32-
};
33-
34-
export abstract class AbstractAttachmentQueue<
35-
T extends AttachmentQueueOptions = AttachmentQueueOptions
36-
> {
26+
export const DEFAULT_ATTACHMENT_QUEUE_OPTIONS: Partial<AttachmentQueueOptions> = {
27+
attachmentDirectoryName: 'attachments',
28+
syncInterval: 30_000,
29+
cacheLimit: 100,
30+
performInitialSync: true
31+
};
32+
33+
export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions = AttachmentQueueOptions> {
3734
uploading: boolean;
3835
downloading: boolean;
3936
initialSync: boolean;
@@ -43,7 +40,7 @@ export abstract class AbstractAttachmentQueue<
4340
constructor(options: T) {
4441
this.options = {
4542
...DEFAULT_ATTACHMENT_QUEUE_OPTIONS,
46-
...options,
43+
...options
4744
};
4845
this.downloadQueue = new Set<string>();
4946
this.uploading = false;
@@ -65,9 +62,7 @@ export abstract class AbstractAttachmentQueue<
6562
/**
6663
* Create a new AttachmentRecord, this gets called when the attachment id is not found in the database.
6764
*/
68-
abstract newAttachmentRecord(
69-
record?: Partial<AttachmentRecord>
70-
): AttachmentRecord;
65+
abstract newAttachmentRecord(record?: Partial<AttachmentRecord>): Promise<AttachmentRecord>;
7166

7267
protected get powersync() {
7368
return this.options.powersync;
@@ -82,9 +77,7 @@ export abstract class AbstractAttachmentQueue<
8277
}
8378

8479
get storageDirectory() {
85-
return `${this.storage.getUserStorageDirectory()}${
86-
this.options.attachmentDirectoryName
87-
}`;
80+
return `${this.storage.getUserStorageDirectory()}${this.options.attachmentDirectoryName}`;
8881
}
8982

9083
async init() {
@@ -110,7 +103,7 @@ export abstract class AbstractAttachmentQueue<
110103

111104
async watchAttachmentIds() {
112105
for await (const ids of this.attachmentIds()) {
113-
const _ids = `${ids.map((id) => `'${id}'`).join(",")}`;
106+
const _ids = `${ids.map((id) => `'${id}'`).join(',')}`;
114107
console.debug(`Queuing for sync, attachment IDs: [${_ids}]`);
115108

116109
if (this.initialSync) {
@@ -127,55 +120,43 @@ export abstract class AbstractAttachmentQueue<
127120
);
128121
}
129122

130-
const attachmentsInDatabase =
131-
await this.powersync.getAll<AttachmentRecord>(
132-
`SELECT * FROM ${this.table} WHERE state < ${AttachmentState.ARCHIVED}`
133-
);
123+
const attachmentsInDatabase = await this.powersync.getAll<AttachmentRecord>(
124+
`SELECT * FROM ${this.table} WHERE state < ${AttachmentState.ARCHIVED}`
125+
);
134126

135127
for (const id of ids) {
136128
const record = attachmentsInDatabase.find((r) => r.id == id);
137129
// 1. ID is not in the database
138130
if (!record) {
139-
const newRecord = this.newAttachmentRecord({
131+
const newRecord = await this.newAttachmentRecord({
140132
id: id,
141-
state: AttachmentState.QUEUED_SYNC,
133+
state: AttachmentState.QUEUED_SYNC
142134
});
143-
console.debug(
144-
`Attachment (${id}) not found in database, creating new record`
145-
);
135+
console.debug(`Attachment (${id}) not found in database, creating new record`);
146136
await this.saveToQueue(newRecord);
147-
} else if (
148-
record.local_uri == null ||
149-
!(await this.storage.fileExists(record.local_uri))
150-
) {
137+
} else if (record.local_uri == null || !(await this.storage.fileExists(record.local_uri))) {
151138
// 2. Attachment in database but no local file, mark as queued download
152-
console.debug(
153-
`Attachment (${id}) found in database but no local file, marking as queued download`
154-
);
139+
console.debug(`Attachment (${id}) found in database but no local file, marking as queued download`);
155140
await this.update({
156141
...record,
157-
state: AttachmentState.QUEUED_DOWNLOAD,
142+
state: AttachmentState.QUEUED_DOWNLOAD
158143
});
159144
}
160145
}
161146

162147
// 3. Attachment in database and not in AttachmentIds, mark as archived
163148
await this.powersync.execute(
164-
`UPDATE ${this.table} SET state = ${
149+
`UPDATE ${this.table} SET state = ${AttachmentState.ARCHIVED} WHERE state < ${
165150
AttachmentState.ARCHIVED
166-
} WHERE state < ${AttachmentState.ARCHIVED} AND id NOT IN (${ids
167-
.map((id) => `'${id}'`)
168-
.join(",")})`
151+
} AND id NOT IN (${ids.map((id) => `'${id}'`).join(',')})`
169152
);
170153
}
171154
}
172155

173-
async saveToQueue(
174-
record: Omit<AttachmentRecord, "timestamp">
175-
): Promise<AttachmentRecord> {
156+
async saveToQueue(record: Omit<AttachmentRecord, 'timestamp'>): Promise<AttachmentRecord> {
176157
const updatedRecord: AttachmentRecord = {
177158
...record,
178-
timestamp: new Date().getTime(),
159+
timestamp: new Date().getTime()
179160
};
180161

181162
await this.powersync.execute(
@@ -187,21 +168,18 @@ export abstract class AbstractAttachmentQueue<
187168
updatedRecord.local_uri || null,
188169
updatedRecord.media_type || null,
189170
updatedRecord.size || null,
190-
updatedRecord.state,
171+
updatedRecord.state
191172
]
192173
);
193174

194175
return updatedRecord;
195176
}
196177

197178
async record(id: string): Promise<AttachmentRecord | null> {
198-
return this.powersync.getOptional<AttachmentRecord>(
199-
`SELECT * FROM ${this.table} WHERE id = ?`,
200-
[id]
201-
);
179+
return this.powersync.getOptional<AttachmentRecord>(`SELECT * FROM ${this.table} WHERE id = ?`, [id]);
202180
}
203181

204-
async update(record: Omit<AttachmentRecord, "timestamp">): Promise<void> {
182+
async update(record: Omit<AttachmentRecord, 'timestamp'>): Promise<void> {
205183
const timestamp = new Date().getTime();
206184
await this.powersync.execute(
207185
`UPDATE ${this.table}
@@ -213,15 +191,7 @@ export abstract class AbstractAttachmentQueue<
213191
media_type = ?,
214192
state = ?
215193
WHERE id = ?`,
216-
[
217-
timestamp,
218-
record.filename,
219-
record.local_uri || null,
220-
record.size,
221-
record.media_type,
222-
record.state,
223-
record.id,
224-
]
194+
[timestamp, record.filename, record.local_uri || null, record.size, record.media_type, record.state, record.id]
225195
);
226196
}
227197

@@ -246,7 +216,7 @@ export abstract class AbstractAttachmentQueue<
246216
try {
247217
// Delete file on storage
248218
await this.storage.deleteFile(uri, {
249-
filename: record.filename,
219+
filename: record.filename
250220
});
251221
} catch (e) {
252222
console.error(e);
@@ -269,41 +239,37 @@ export abstract class AbstractAttachmentQueue<
269239

270240
async uploadAttachment(record: AttachmentRecord) {
271241
if (!record.local_uri) {
272-
throw new Error(
273-
`No local_uri for record ${JSON.stringify(record, null, 2)}`
274-
);
242+
throw new Error(`No local_uri for record ${JSON.stringify(record, null, 2)}`);
275243
}
276244
try {
277245
if (!(await this.storage.fileExists(record.local_uri))) {
278246
console.warn(`File for ${record.id} does not exist, skipping upload`);
279247
await this.update({
280248
...record,
281-
state: AttachmentState.QUEUED_DOWNLOAD,
249+
state: AttachmentState.QUEUED_DOWNLOAD
282250
});
283251
return true;
284252
}
285253

286254
const fileBuffer = await this.storage.readFile(record.local_uri, {
287255
encoding: EncodingType.Base64,
288-
mediaType: record.media_type,
256+
mediaType: record.media_type
289257
});
290258

291259
await this.storage.uploadFile(record.filename, fileBuffer, {
292-
mediaType: record.media_type,
260+
mediaType: record.media_type
293261
});
294262
// Mark as uploaded
295263
await this.update({ ...record, state: AttachmentState.SYNCED });
296264
console.debug(`Uploaded attachment "${record.id}" to Cloud Storage`);
297265
return true;
298266
} catch (e: any) {
299-
if (e.error == "Duplicate") {
267+
if (e.error == 'Duplicate') {
300268
console.debug(`File already uploaded, marking ${record.id} as synced`);
301269
await this.update({ ...record, state: AttachmentState.SYNCED });
302270
return false;
303271
}
304-
console.error(
305-
`UploadAttachment error for record ${JSON.stringify(record, null, 2)}`
306-
);
272+
console.error(`UploadAttachment error for record ${JSON.stringify(record, null, 2)}`);
307273
return false;
308274
}
309275
}
@@ -313,9 +279,7 @@ export abstract class AbstractAttachmentQueue<
313279
record.local_uri = this.getLocalUri(record.filename);
314280
}
315281
if (await this.storage.fileExists(record.local_uri)) {
316-
console.debug(
317-
`Local file already downloaded, marking "${record.id}" as synced`
318-
);
282+
console.debug(`Local file already downloaded, marking "${record.id}" as synced`);
319283
await this.update({ ...record, state: AttachmentState.SYNCED });
320284
return true;
321285
}
@@ -328,37 +292,28 @@ export abstract class AbstractAttachmentQueue<
328292
const reader = new FileReader();
329293
reader.onloadend = () => {
330294
// remove the header from the result: 'data:*/*;base64,'
331-
resolve(
332-
reader.result?.toString().replace(/^data:.+;base64,/, "") || ""
333-
);
295+
resolve(reader.result?.toString().replace(/^data:.+;base64,/, '') || '');
334296
};
335297
reader.onerror = reject;
336298
reader.readAsDataURL(fileBlob);
337299
});
338300

339301
// Ensure directory exists
340-
await this.storage.makeDir(record.local_uri.replace(record.filename, ""));
302+
await this.storage.makeDir(record.local_uri.replace(record.filename, ''));
341303
// Write the file
342304
await this.storage.writeFile(record.local_uri, base64Data, {
343-
encoding: EncodingType.Base64,
305+
encoding: EncodingType.Base64
344306
});
345307

346308
await this.update({
347309
...record,
348310
media_type: fileBlob.type,
349-
state: AttachmentState.SYNCED,
311+
state: AttachmentState.SYNCED
350312
});
351313
console.debug(`Downloaded attachment "${record.id}"`);
352314
return true;
353315
} catch (e) {
354-
console.error(
355-
`Download attachment error for record ${JSON.stringify(
356-
record,
357-
null,
358-
2
359-
)}`,
360-
e
361-
);
316+
console.error(`Download attachment error for record ${JSON.stringify(record, null, 2)}`, e);
362317
}
363318
return false;
364319
}
@@ -409,9 +364,9 @@ export abstract class AbstractAttachmentQueue<
409364
}
410365
record = await this.getNextUploadRecord();
411366
}
412-
console.debug("Finished uploading attachments");
367+
console.debug('Finished uploading attachments');
413368
} catch (error) {
414-
console.error("Upload failed:", error);
369+
console.error('Upload failed:', error);
415370
} finally {
416371
this.uploading = false;
417372
}
@@ -473,9 +428,9 @@ export abstract class AbstractAttachmentQueue<
473428
}
474429
await this.downloadRecord(record);
475430
}
476-
console.debug("Finished downloading attachments");
431+
console.debug('Finished downloading attachments');
477432
} catch (e) {
478-
console.error("Downloads failed:", e);
433+
console.error('Downloads failed:', e);
479434
} finally {
480435
this.downloading = false;
481436
}
@@ -486,8 +441,7 @@ export abstract class AbstractAttachmentQueue<
486441
}
487442

488443
async expireCache() {
489-
const res = await this.powersync
490-
.getAll<AttachmentRecord>(`SELECT * FROM ${this.table}
444+
const res = await this.powersync.getAll<AttachmentRecord>(`SELECT * FROM ${this.table}
491445
WHERE
492446
state = ${AttachmentState.SYNCED} OR state = ${AttachmentState.ARCHIVED}
493447
ORDER BY

yarn.lock

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,19 +2141,6 @@
21412141
dependencies:
21422142
"@journeyapps/powersync-sdk-common" "^0.0.1"
21432143

2144-
"@journeyapps/powersync-sdk-common@0.0.2":
2145-
version "0.0.2"
2146-
resolved "https://registry.yarnpkg.com/@journeyapps/powersync-sdk-common/-/powersync-sdk-common-0.0.2.tgz#2a7073f21491e85b4bb434c46b9833f5401579bd"
2147-
integrity sha512-J90yVpv1L+zmVy8PnMCo1KMur9Zq1IwNngyuhais2rmOIMzZzMzTE6sdcUlioq/cphI0wOagUEXcyE8+iLbptA==
2148-
dependencies:
2149-
async-mutex "^0.4.0"
2150-
can-ndjson-stream "^1.0.2"
2151-
event-iterator "^2.0.0"
2152-
js-logger "^1.6.1"
2153-
lodash "^4.17.21"
2154-
object-hash "^3.0.0"
2155-
uuid "^3.0.0"
2156-
21572144
"@journeyapps/powersync-sdk-common@^0.0.1", "@journeyapps/powersync-sdk-common@^0.0.1-alpha.0":
21582145
version "0.0.1"
21592146
resolved "https://registry.yarnpkg.com/@journeyapps/powersync-sdk-common/-/powersync-sdk-common-0.0.1.tgz#8ff1a440a91ef7bbc488a1b3752cc344f4a6ee35"

0 commit comments

Comments
 (0)