Skip to content

Commit 7c0c6c7

Browse files
committed
Load core extension in node demo
1 parent 5923f6f commit 7c0c6c7

File tree

11 files changed

+357
-159
lines changed

11 files changed

+357
-159
lines changed

demos/example-node/package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "example-node",
3+
"version": "1.0.0",
4+
"description": "",
5+
"type": "module",
6+
"scripts": {
7+
"build": "tsc -b",
8+
"run": "node --loader ts-node/esm src/main.ts"
9+
},
10+
"dependencies": {
11+
"@powersync/node": "workspace:*",
12+
"better-sqlite3": "any"
13+
},
14+
"devDependencies": {
15+
"ts-node": "^10.9.2",
16+
"typescript": "^5.8.2"
17+
}
18+
}

demos/example-node/src/main.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { column, PowerSyncDatabase, Schema, Table } from "@powersync/node";
2+
3+
const main = async () => {
4+
const db = new PowerSyncDatabase({
5+
schema: AppSchema,
6+
database: {
7+
dbFilename: 'test.db',
8+
},
9+
});
10+
console.log(await db.get('SELECT powersync_rs_version();'));
11+
};
12+
13+
export const LIST_TABLE = 'lists';
14+
export const TODO_TABLE = 'todos';
15+
16+
const todos = new Table(
17+
{
18+
list_id: column.text,
19+
created_at: column.text,
20+
completed_at: column.text,
21+
description: column.text,
22+
created_by: column.text,
23+
completed_by: column.text,
24+
completed: column.integer,
25+
photo_id: column.text
26+
},
27+
{ indexes: { list: ['list_id'] } }
28+
);
29+
30+
const lists = new Table({
31+
created_at: column.text,
32+
name: column.text,
33+
owner_id: column.text
34+
});
35+
36+
export const AppSchema = new Schema({
37+
lists,
38+
todos
39+
});
40+
41+
export type Database = (typeof AppSchema)['types'];
42+
export type TodoRecord = Database['todos'];
43+
export type ListRecord = Database['lists'];
44+
45+
await main();

demos/example-node/tsconfig.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"extends": "../../tsconfig.base",
3+
"compilerOptions": {
4+
"baseUrl": ".",
5+
"rootDir": "src",
6+
"outDir": "lib",
7+
"strictNullChecks": true
8+
},
9+
"references": [
10+
{
11+
"path": "../../packages/node"
12+
}
13+
]
14+
}

packages/node/download_core.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// TODO: Make this a pre-publish hook and just bundle everything
2+
import * as OS from 'node:os';
3+
import * as fs from 'node:fs/promises';
4+
import * as path from 'node:path';
5+
import { Readable } from 'node:stream';
6+
import { finished } from 'node:stream/promises';
7+
import { exit } from 'node:process';
8+
9+
const version = '0.3.11';
10+
11+
const platform = OS.platform();
12+
let destination;
13+
let asset;
14+
15+
if (platform === "win32") {
16+
asset = "powersync_x64.dll";
17+
destination = 'powersync.dll';
18+
} else if (platform === "linux") {
19+
asset = OS.arch() === 'x64' ? 'libpowersync_x64.so' : 'libpowersync_aarch64.so';
20+
destination = 'libpowersync.so';
21+
} else if (platform === "darwin") {
22+
asset = OS.arch() === 'x64' ? 'libpowersync_x64.dylib' : 'libpowersync_aarch64.dylib';
23+
destination = 'libpowersync.dylib';
24+
}
25+
26+
const destinationPath = path.resolve("lib", destination)
27+
try {
28+
await fs.access(destinationPath);
29+
exit(0);
30+
} catch {}
31+
32+
const url = `https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v${version}/${asset}`;
33+
const response = await fetch(url);
34+
if (response.status != 200) {
35+
throw `Could not download ${url}`;
36+
}
37+
38+
try {
39+
await fs.access("lib")
40+
} catch {
41+
await fs.mkdir("lib");
42+
}
43+
44+
const file = await fs.open(destinationPath, "w");
45+
await finished(Readable.fromWeb(response.body).pipe(file.createWriteStream()));
46+
await file.close();

packages/node/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
"dist"
1515
],
1616
"scripts": {
17+
"install": "node download_core.js",
1718
"build": "tsc -b",
1819
"build:prod": "tsc -b --sourceMap false",
1920
"clean": "rm -rf lib dist tsconfig.tsbuildinfo dist",
2021
"watch": "tsc -b -w"
2122
},
23+
"type": "module",
2224
"repository": {
2325
"type": "git",
2426
"url": "git+https://github.com/powersync-ja/powersync-js.git"

packages/node/src/db/BetterSQLite3DBAdapter.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import path from 'node:path';
1+
import * as path from 'node:path';
2+
import * as OS from 'node:os';
3+
import * as url from 'node:url';
24

35
import BetterSQLite3Database from 'better-sqlite3';
46

@@ -49,7 +51,24 @@ export class BetterSQLite3DBAdapter extends BaseObserver<DBAdapterListener> impl
4951
dbFilePath = path.join(options.dbLocation, dbFilePath);
5052
}
5153

54+
const platform = OS.platform();
55+
let extensionPath: string;
56+
if (platform === "win32") {
57+
extensionPath = 'powersync.dll';
58+
} else if (platform === "linux") {
59+
extensionPath = 'libpowersync.so';
60+
} else if (platform === "darwin") {
61+
extensionPath = 'libpowersync.dylib';
62+
}
63+
5264
const baseDB = new BetterSQLite3Database(dbFilePath);
65+
66+
const loadExtension = (db: BetterSQLite3Database) => {
67+
const resolved = url.fileURLToPath(new URL(`../${extensionPath}`, import.meta.url));
68+
db.loadExtension(resolved, 'sqlite3_powersync_init');
69+
}
70+
71+
loadExtension(baseDB);
5372
baseDB.pragma('journal_mode = WAL');
5473

5574
baseDB.updateHook((_op, _dbName, tableName, _rowid) => {
@@ -71,6 +90,7 @@ export class BetterSQLite3DBAdapter extends BaseObserver<DBAdapterListener> impl
7190
this.readConnections = [];
7291
for (let i = 0; i < READ_CONNECTIONS; i++) {
7392
const baseDB = new BetterSQLite3Database(dbFilePath);
93+
loadExtension(baseDB);
7494
baseDB.pragma('query_only = true');
7595
this.readConnections.push(new Connection(baseDB));
7696
}
@@ -253,7 +273,7 @@ class Connection implements BetterSQLite3LockContext {
253273
async execute(query: string, params?: any[]): Promise<QueryResult> {
254274
const stmt = this.baseDB.prepare(query);
255275
if (stmt.reader) {
256-
const rows = stmt.all(params);
276+
const rows = stmt.all(params ?? []);
257277
return {
258278
rowsAffected: 0,
259279
rows: {
@@ -263,7 +283,7 @@ class Connection implements BetterSQLite3LockContext {
263283
},
264284
};
265285
} else {
266-
const info = stmt.run(params);
286+
const info = stmt.run(params ?? []);
267287
return {
268288
rowsAffected: info.changes,
269289
insertId: Number(info.lastInsertRowid),

packages/node/src/db/PowerSyncDatabase.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import {
88
SqliteBucketStorage
99
} from '@powersync/common';
1010

11-
import { NodeRemote } from '../sync/stream/NodeRemote';
12-
import { NodeStreamingSyncImplementation } from '../sync/stream/NodeStreamingSyncImplementation';
11+
import { NodeRemote } from '../sync/stream/NodeRemote.js';
12+
import { NodeStreamingSyncImplementation } from '../sync/stream/NodeStreamingSyncImplementation.js';
1313

14-
import { BetterSQLite3DBAdapter } from './BetterSQLite3DBAdapter';
14+
import { BetterSQLite3DBAdapter } from './BetterSQLite3DBAdapter.js';
1515

1616
/**
1717
* A PowerSync database which provides SQLite functionality

packages/node/src/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// Re export to only require one import in client side code
22
export * from '@powersync/common';
33

4-
export * from './db/BetterSQLite3DBAdapter';
5-
export * from './db/PowerSyncDatabase';
4+
export * from './db/BetterSQLite3DBAdapter.js';
5+
export * from './db/PowerSyncDatabase.js';
66

7-
export * from './sync/stream/NodeRemote';
8-
export * from './sync/stream/NodeStreamingSyncImplementation';
7+
export * from './sync/stream/NodeRemote.js';
8+
export * from './sync/stream/NodeStreamingSyncImplementation.js';

packages/node/src/sync/stream/NodeRemote.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import os from 'node:os';
1+
import * as os from 'node:os';
22

33
import { ILogger } from 'js-logger';
44

packages/node/tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,20 @@
22
"extends": "../../tsconfig.base",
33
"compilerOptions": {
44
"baseUrl": "./",
5+
"jsx": "react",
6+
"types": ["node"],
57
"rootDir": "src",
68
"outDir": "./lib",
9+
"lib": ["esnext"],
10+
"declaration": true,
11+
"module": "NodeNext",
12+
"moduleResolution": "nodenext",
13+
"preserveConstEnums": true,
14+
"esModuleInterop": false,
15+
"skipLibCheck": false,
716
"strictNullChecks": true
817
},
18+
"include": ["src/**/*"],
919
"references": [
1020
{
1121
"path": "../common"

0 commit comments

Comments
 (0)