Skip to content

Commit

Permalink
Add mobile support electric-sql#2
Browse files Browse the repository at this point in the history
Add support for mobile filesystem using Expo FileSystem API.

* **Add MobileFS class:**
  * Create `mobilefs.ts` file in `packages/pglite/src/fs/`.
  * Implement `MobileFS` class extending `FilesystemBase`.
  * Implement methods for reading, writing, and deleting files using Expo FileSystem API.

* **Update fs index:**
  * Import `MobileFS` class in `packages/pglite/src/fs/index.ts`.
  * Add case for `mobilefs` in `parseDataDir` function.
  * Add case for `mobilefs` in `loadFs` function.

* **Add tests for MobileFS:**
  * Create `mobile-fs.test.js` in `packages/pglite/tests/targets/`.
  * Write tests for reading, writing, and deleting files using MobileFS and Expo FileSystem API.
  • Loading branch information
Mike-FreeAI committed Aug 13, 2024
1 parent dd698b7 commit 48a62f2
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
7 changes: 7 additions & 0 deletions packages/pglite/src/fs/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { FsType, Filesystem } from './types.js'
import { IdbFs } from './idbfs.js'
import { MemoryFS } from './memoryfs.js'
import { MobileFS } from './mobilefs.js'

export type * from './types.js'

Expand All @@ -24,6 +25,10 @@ export function parseDataDir(dataDir?: string) {
// Remove the opfsahp:// prefix, and use opfs access handle pool filesystem
dataDir = dataDir.slice(11)
fsType = 'opfs-ahp'
} else if (dataDir?.startsWith('mobile://')) {
// Remove the mobile:// prefix, and use mobile filesystem
dataDir = dataDir.slice(9)
fsType = 'mobilefs'
} else if (!dataDir || dataDir?.startsWith('memory://')) {
// Use in-memory filesystem
fsType = 'memoryfs'
Expand All @@ -46,6 +51,8 @@ export async function loadFs(dataDir?: string, fsType?: FsType) {
// Lazy load the opfs-ahp to so that it's optional in the bundle
const { OpfsAhpFS } = await import('./opfs-ahp/index.js')
fs = new OpfsAhpFS(dataDir)
} else if (dataDir && fsType === 'mobilefs') {
fs = new MobileFS(dataDir)
} else {
fs = new MemoryFS()
}
Expand Down
40 changes: 40 additions & 0 deletions packages/pglite/src/fs/mobilefs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as FileSystem from 'expo-file-system';
import { FilesystemBase } from './types.js';
import type { PostgresMod, FS } from '../postgresMod.js';
import { dumpTar } from './tarUtils.js';

export class MobileFS extends FilesystemBase {
async emscriptenOpts(opts: Partial<PostgresMod>) {
const options: Partial<PostgresMod> = {
...opts,
preRun: [
...(opts.preRun || []),
(mod: any) => {
mod.FS.mkdir('/mobilefs');
mod.FS.mount(mod.FS.filesystems.NODEFS, { root: this.dataDir }, '/mobilefs');
},
],
};
return options;
}

async dumpTar(mod: FS, dbname: string) {
return dumpTar(mod, dbname);
}

async close(FS: FS): Promise<void> {
FS.quit();
}

async readFile(path: string): Promise<string> {
return await FileSystem.readAsStringAsync(path);
}

async writeFile(path: string, contents: string): Promise<void> {
await FileSystem.writeAsStringAsync(path, contents);
}

async deleteFile(path: string): Promise<void> {
await FileSystem.deleteAsync(path);
}
}
54 changes: 54 additions & 0 deletions packages/pglite/tests/targets/mobile-fs.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import test from '../polytest.js'
import { PGlite } from '../../dist/index.js'
import { MobileFS } from '../../dist/fs/mobilefs.js'
import * as FileSystem from 'expo-file-system'

test('MobileFS read, write, delete', async (t) => {
const db = new PGlite({
fs: new MobileFS(FileSystem.documentDirectory + 'pgdata'),
})

await db.exec(`
CREATE TABLE IF NOT EXISTS test (
id SERIAL PRIMARY KEY,
name TEXT
);
`)

await db.exec("INSERT INTO test (name) VALUES ('test');")

const res = await db.query(`
SELECT * FROM test;
`)

t.deepEqual(res, {
rows: [
{
id: 1,
name: 'test',
},
],
fields: [
{
name: 'id',
dataTypeID: 23,
},
{
name: 'name',
dataTypeID: 25,
},
],
affectedRows: 0,
})

// Test reading file
const filePath = FileSystem.documentDirectory + 'pgdata/test.txt'
await FileSystem.writeAsStringAsync(filePath, 'Hello, world!')
const fileContent = await FileSystem.readAsStringAsync(filePath)
t.is(fileContent, 'Hello, world!')

// Test deleting file
await FileSystem.deleteAsync(filePath)
const fileExists = await FileSystem.getInfoAsync(filePath)
t.false(fileExists.exists)
})

0 comments on commit 48a62f2

Please sign in to comment.