Skip to content

Commit 23dc8e4

Browse files
Add make, remove and get uri endpoints to local storage
1 parent 01070e1 commit 23dc8e4

File tree

5 files changed

+76
-48
lines changed

5 files changed

+76
-48
lines changed

packages/attachments/src/AttachmentQueue.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,6 @@ export class AttachmentQueue {
158158
this.watchActiveAbortController?.abort();
159159
}
160160

161-
getLocalUri(filePath: string): string {
162-
return `${this.localStorage.getUserStorageDirectory()}/${filePath}`;
163-
}
164-
165161
async saveFile({
166162
data,
167163
fileExtension,
@@ -177,7 +173,7 @@ export class AttachmentQueue {
177173
}): Promise<AttachmentRecord> {
178174
const resolvedId = id ?? (await this.context.db.get<{ id: string }>('SELECT uuid() as id')).id;
179175
const filename = `${resolvedId}.${fileExtension}`;
180-
const localUri = this.getLocalUri(filename);
176+
const localUri = this.localStorage.getLocalUri(filename);
181177
const size = await this.localStorage.saveFile(localUri, data);
182178

183179
const attachment: AttachmentRecord = {
@@ -214,7 +210,7 @@ export class AttachmentQueue {
214210
continue;
215211
}
216212

217-
const newLocalUri = this.getLocalUri(attachment.filename);
213+
const newLocalUri = this.localStorage.getLocalUri(attachment.filename);
218214
const newExists = await this.localStorage.fileExists(newLocalUri);
219215
if (newExists) {
220216
// The file exists but the localUri is broken, lets update it.

packages/attachments/src/LocalStorageAdapter.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export interface LocalStorageAdapter {
88
* Saves buffer data to a local file.
99
* @param filePath Path where the file will be stored
1010
* @param data Data string to store
11-
* @returns number of bytes written
11+
* @returns Number of bytes written
1212
*/
1313
saveFile(filePath: string, data: ArrayBuffer | Blob | string): Promise<number>;
1414

@@ -28,9 +28,24 @@ export interface LocalStorageAdapter {
2828
/**
2929
* Checks if a file exists at the given path.
3030
* @param filePath Path where the file is stored
31+
* @returns True if the file exists, false otherwise
3132
*/
3233
fileExists(filePath: string): Promise<boolean>;
3334

35+
/**
36+
* Creates a directory at the specified path.
37+
* @param path The full path to the directory
38+
* @throws PowerSyncAttachmentError if creation fails
39+
*/
40+
makeDir(path: string): Promise<void>;
41+
42+
/**
43+
* Removes a directory at the specified path.
44+
* @param path The full path to the directory
45+
* @throws PowerSyncAttachmentError if removal fails
46+
*/
47+
rmDir(path: string): Promise<void>;
48+
3449
/**
3550
* Initializes the storage adapter (e.g., creating necessary directories).
3651
*/
@@ -42,8 +57,9 @@ export interface LocalStorageAdapter {
4257
clear(): Promise<void>;
4358

4459
/**
45-
* Get the base directory used by the storage adapter.
46-
* @returns The base directory path as a string.
60+
* Returns the file path of the provided filename in the user storage directory.
61+
* @param filename The filename to get the path for
62+
* @returns The full file path
4763
*/
48-
getUserStorageDirectory(): string;
49-
}
64+
getLocalUri(filename: string): string;
65+
}

packages/attachments/src/StorageService.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,8 @@ export class StorageService {
9292
reader.onerror = reject;
9393
reader.readAsDataURL(fileBlob);
9494
});
95-
const userDir = this.localStorage.getUserStorageDirectory();
96-
const localUri = `${userDir}${attachment.id}`;
9795

96+
const localUri = this.localStorage.getLocalUri(attachment.filename);
9897
await this.localStorage.saveFile(localUri, base64Data);
9998

10099
return {

packages/attachments/src/storageAdapters/IndexDBFileSystemAdapter.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EncodingType, LocalStorageAdapter } from 'src/LocalStorageAdapter.js';
1+
import { EncodingType, LocalStorageAdapter } from '../LocalStorageAdapter.js';
22

33
export class IndexDBFileSystemStorageAdapter implements LocalStorageAdapter {
44
private dbPromise: Promise<IDBDatabase>;
@@ -14,6 +14,21 @@ export class IndexDBFileSystemStorageAdapter implements LocalStorageAdapter {
1414
});
1515
}
1616

17+
clear(): Promise<void> {
18+
return new Promise(async (resolve, reject) => {
19+
const db = await this.dbPromise;
20+
const tx = db.transaction('files', 'readwrite');
21+
const store = tx.objectStore('files');
22+
const req = store.clear();
23+
req.onsuccess = () => resolve();
24+
req.onerror = () => reject(req.error);
25+
});
26+
}
27+
28+
getLocalUri(filename: string): string {
29+
return `indexeddb://PowerSyncFiles/files/${filename}`;
30+
}
31+
1732
private async getStore(mode: IDBTransactionMode = 'readonly'): Promise<IDBObjectStore> {
1833
const db = await this.dbPromise;
1934
const tx = db.transaction('files', mode);
@@ -54,24 +69,26 @@ export class IndexDBFileSystemStorageAdapter implements LocalStorageAdapter {
5469
return;
5570
}
5671

57-
if (options?.encoding === EncodingType.Base64) {
58-
const base64String = req.result.replace(/^data:\w+;base64,/, '');
59-
const binaryString = atob(base64String);
60-
const len = binaryString.length;
61-
const bytes = new Uint8Array(len);
62-
for (let i = 0; i < len; i++) {
63-
bytes[i] = binaryString.charCodeAt(i);
64-
}
65-
resolve(bytes.buffer);
66-
}
72+
// if (options?.encoding === EncodingType.Base64) {
73+
// }
6774

6875
if (options?.encoding === EncodingType.UTF8) {
6976
const encoder = new TextEncoder();
7077
const arrayBuffer = encoder.encode(req.result).buffer;
7178
resolve(arrayBuffer);
7279
}
7380

74-
reject(new Error('Unsupported encoding'));
81+
// Default base64 encoding
82+
const base64String = req.result.replace(/^data:\w+;base64,/, '');
83+
const binaryString = atob(base64String);
84+
const len = binaryString.length;
85+
const bytes = new Uint8Array(len);
86+
for (let i = 0; i < len; i++) {
87+
bytes[i] = binaryString.charCodeAt(i);
88+
}
89+
resolve(bytes.buffer);
90+
91+
// reject(new Error('Unsupported encoding'));
7592
};
7693
req.onerror = () => reject(req.error);
7794
});
@@ -95,19 +112,11 @@ export class IndexDBFileSystemStorageAdapter implements LocalStorageAdapter {
95112
});
96113
}
97114

98-
getUserStorageDirectory(): string {
99-
// Not applicable for web, but return a logical root
100-
return 'indexeddb://PowerSyncFiles/files';
115+
async makeDir(path: string): Promise<void> {
116+
// No-op for IndexedDB
101117
}
102118

103-
clear(): Promise<void> {
104-
return new Promise(async (resolve, reject) => {
105-
const db = await this.dbPromise;
106-
const tx = db.transaction('files', 'readwrite');
107-
const store = tx.objectStore('files');
108-
const req = store.clear();
109-
req.onsuccess = () => resolve();
110-
req.onerror = () => reject(req.error);
111-
});
119+
async rmDir(path: string): Promise<void> {
120+
// No-op for IndexedDB
112121
}
113122
}

packages/attachments/src/storageAdapters/NodeFileSystemAdapter.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
import { promises as fs } from 'fs';
22
import * as path from 'path';
3-
import { EncodingType, LocalStorageAdapter } from 'src/LocalStorageAdapter.js';
3+
import { EncodingType, LocalStorageAdapter } from '../LocalStorageAdapter.js';
44

55
export class NodeFileSystemAdapter implements LocalStorageAdapter {
6+
async initialize(): Promise<void> {
7+
// const dir = this.getUserStorageDirectory();
8+
const dir = path.resolve('./user_data');
9+
await fs.mkdir(dir, { recursive: true });
10+
}
11+
12+
async clear(): Promise<void> {
13+
// const dir = this.getUserStorageDirectory();
14+
const dir = path.resolve('./user_data');
15+
await fs.rmdir(dir, { recursive: true });
16+
}
17+
18+
getLocalUri(filename: string): string {
19+
return path.join(path.resolve('./user_data'), filename);
20+
}
21+
622
async uploadFile(filePath: string, data: ArrayBuffer, options?: { encoding: EncodingType }): Promise<void> {
723
const buffer = Buffer.from(data);
824
await fs.writeFile(filePath, buffer, {
@@ -57,15 +73,7 @@ export class NodeFileSystemAdapter implements LocalStorageAdapter {
5773
await fs.mkdir(path, { recursive: true });
5874
}
5975

60-
async rmDir(filePath: string): Promise<void> {
61-
await fs.rmdir(filePath, { recursive: true });
62-
}
63-
64-
async copyFile(sourcePath: string, targetPath: string): Promise<void> {
65-
await fs.copyFile(sourcePath, targetPath);
66-
}
67-
68-
getUserStorageDirectory(): string {
69-
return path.resolve('./user_data') + path.sep;
76+
async rmDir(path: string): Promise<void> {
77+
await fs.rmdir(path, { recursive: true });
7078
}
7179
}

0 commit comments

Comments
 (0)