mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-24 03:34:18 +01:00
wip
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -4326,6 +4326,7 @@ dependencies = [
|
|||||||
"napi",
|
"napi",
|
||||||
"napi-build",
|
"napi-build",
|
||||||
"napi-derive",
|
"napi-derive",
|
||||||
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"turso_core",
|
"turso_core",
|
||||||
"turso_node",
|
"turso_node",
|
||||||
|
|||||||
335
bindings/javascript/examples/browser/package-lock.json
generated
Normal file
335
bindings/javascript/examples/browser/package-lock.json
generated
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
{
|
||||||
|
"name": "wasm",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "wasm",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@tursodatabase/database-browser": "../../packages/browser"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^7.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../../packages/browser": {
|
||||||
|
"name": "@tursodatabase/database-browser",
|
||||||
|
"version": "0.1.5",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@napi-rs/wasm-runtime": "^1.0.3",
|
||||||
|
"@tursodatabase/database-browser-common": "^0.1.5",
|
||||||
|
"@tursodatabase/database-common": "^0.1.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@napi-rs/cli": "^3.1.5",
|
||||||
|
"@vitest/browser": "^3.2.4",
|
||||||
|
"playwright": "^1.55.0",
|
||||||
|
"typescript": "^5.9.2",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
|
"version": "0.25.9",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
|
"version": "4.50.0",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
|
"version": "4.50.0",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@tursodatabase/database-browser": {
|
||||||
|
"resolved": "../../packages/browser",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/@types/estree": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/esbuild": {
|
||||||
|
"version": "0.25.9",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/aix-ppc64": "0.25.9",
|
||||||
|
"@esbuild/android-arm": "0.25.9",
|
||||||
|
"@esbuild/android-arm64": "0.25.9",
|
||||||
|
"@esbuild/android-x64": "0.25.9",
|
||||||
|
"@esbuild/darwin-arm64": "0.25.9",
|
||||||
|
"@esbuild/darwin-x64": "0.25.9",
|
||||||
|
"@esbuild/freebsd-arm64": "0.25.9",
|
||||||
|
"@esbuild/freebsd-x64": "0.25.9",
|
||||||
|
"@esbuild/linux-arm": "0.25.9",
|
||||||
|
"@esbuild/linux-arm64": "0.25.9",
|
||||||
|
"@esbuild/linux-ia32": "0.25.9",
|
||||||
|
"@esbuild/linux-loong64": "0.25.9",
|
||||||
|
"@esbuild/linux-mips64el": "0.25.9",
|
||||||
|
"@esbuild/linux-ppc64": "0.25.9",
|
||||||
|
"@esbuild/linux-riscv64": "0.25.9",
|
||||||
|
"@esbuild/linux-s390x": "0.25.9",
|
||||||
|
"@esbuild/linux-x64": "0.25.9",
|
||||||
|
"@esbuild/netbsd-arm64": "0.25.9",
|
||||||
|
"@esbuild/netbsd-x64": "0.25.9",
|
||||||
|
"@esbuild/openbsd-arm64": "0.25.9",
|
||||||
|
"@esbuild/openbsd-x64": "0.25.9",
|
||||||
|
"@esbuild/openharmony-arm64": "0.25.9",
|
||||||
|
"@esbuild/sunos-x64": "0.25.9",
|
||||||
|
"@esbuild/win32-arm64": "0.25.9",
|
||||||
|
"@esbuild/win32-ia32": "0.25.9",
|
||||||
|
"@esbuild/win32-x64": "0.25.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fdir": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"picomatch": "^3 || ^4"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"picomatch": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.11",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.5.6",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.11",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"source-map-js": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rollup": {
|
||||||
|
"version": "4.50.0",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/estree": "1.0.8"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rollup": "dist/bin/rollup"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0",
|
||||||
|
"npm": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@rollup/rollup-android-arm-eabi": "4.50.0",
|
||||||
|
"@rollup/rollup-android-arm64": "4.50.0",
|
||||||
|
"@rollup/rollup-darwin-arm64": "4.50.0",
|
||||||
|
"@rollup/rollup-darwin-x64": "4.50.0",
|
||||||
|
"@rollup/rollup-freebsd-arm64": "4.50.0",
|
||||||
|
"@rollup/rollup-freebsd-x64": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-arm-gnueabihf": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-arm-musleabihf": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-arm64-gnu": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-arm64-musl": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-loongarch64-gnu": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-ppc64-gnu": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-riscv64-gnu": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-riscv64-musl": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-s390x-gnu": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-x64-gnu": "4.50.0",
|
||||||
|
"@rollup/rollup-linux-x64-musl": "4.50.0",
|
||||||
|
"@rollup/rollup-openharmony-arm64": "4.50.0",
|
||||||
|
"@rollup/rollup-win32-arm64-msvc": "4.50.0",
|
||||||
|
"@rollup/rollup-win32-ia32-msvc": "4.50.0",
|
||||||
|
"@rollup/rollup-win32-x64-msvc": "4.50.0",
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tinyglobby": {
|
||||||
|
"version": "0.2.14",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fdir": "^6.4.4",
|
||||||
|
"picomatch": "^4.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vite": {
|
||||||
|
"version": "7.1.4",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
|
"fdir": "^6.5.0",
|
||||||
|
"picomatch": "^4.0.3",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"rollup": "^4.43.0",
|
||||||
|
"tinyglobby": "^0.2.14"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"vite": "bin/vite.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/node": "^20.19.0 || >=22.12.0",
|
||||||
|
"jiti": ">=1.21.0",
|
||||||
|
"less": "^4.0.0",
|
||||||
|
"lightningcss": "^1.21.0",
|
||||||
|
"sass": "^1.70.0",
|
||||||
|
"sass-embedded": "^1.70.0",
|
||||||
|
"stylus": ">=0.54.8",
|
||||||
|
"sugarss": "^5.0.0",
|
||||||
|
"terser": "^5.16.0",
|
||||||
|
"tsx": "^4.8.1",
|
||||||
|
"yaml": "^2.4.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"jiti": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"less": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"lightningcss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass-embedded": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"stylus": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sugarss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"terser": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"tsx": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"yaml": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
626
bindings/javascript/examples/drizzle/package-lock.json
generated
Normal file
626
bindings/javascript/examples/drizzle/package-lock.json
generated
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
{
|
||||||
|
"name": "drizzle",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "drizzle",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@tursodatabase/database": "../../packages/native",
|
||||||
|
"better-sqlite3": "^12.2.0",
|
||||||
|
"drizzle-orm": "^0.44.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../..": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"workspaces": [
|
||||||
|
"packages/common",
|
||||||
|
"packages/native",
|
||||||
|
"packages/browser",
|
||||||
|
"packages/browser-common",
|
||||||
|
"sync/packages/common",
|
||||||
|
"sync/packages/native",
|
||||||
|
"sync/packages/browser"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"../../packages/browser": {
|
||||||
|
"name": "@tursodatabase/database-browser",
|
||||||
|
"version": "0.1.5",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@napi-rs/wasm-runtime": "^1.0.3",
|
||||||
|
"@tursodatabase/database-browser-common": "^0.1.5",
|
||||||
|
"@tursodatabase/database-common": "^0.1.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@napi-rs/cli": "^3.1.5",
|
||||||
|
"@vitest/browser": "^3.2.4",
|
||||||
|
"playwright": "^1.55.0",
|
||||||
|
"typescript": "^5.9.2",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../../packages/browser-common": {
|
||||||
|
"name": "@tursodatabase/database-browser-common",
|
||||||
|
"version": "0.1.5",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../../packages/common": {
|
||||||
|
"name": "@tursodatabase/database-common",
|
||||||
|
"version": "0.1.5",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../../packages/native": {
|
||||||
|
"name": "@tursodatabase/database",
|
||||||
|
"version": "0.1.5",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tursodatabase/database-common": "^0.1.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@napi-rs/cli": "^3.1.5",
|
||||||
|
"@types/node": "^24.3.1",
|
||||||
|
"typescript": "^5.9.2",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../../sync/packages/browser": {
|
||||||
|
"name": "@tursodatabase/sync-browser",
|
||||||
|
"version": "0.1.5",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@napi-rs/wasm-runtime": "^1.0.3",
|
||||||
|
"@tursodatabase/database-browser-common": "^0.1.5",
|
||||||
|
"@tursodatabase/database-common": "^0.1.5",
|
||||||
|
"@tursodatabase/sync-common": "^0.1.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@napi-rs/cli": "^3.1.5",
|
||||||
|
"@vitest/browser": "^3.2.4",
|
||||||
|
"playwright": "^1.55.0",
|
||||||
|
"typescript": "^5.9.2",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../../sync/packages/common": {
|
||||||
|
"name": "@tursodatabase/sync-common",
|
||||||
|
"version": "0.1.5",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../../sync/packages/native": {
|
||||||
|
"name": "@tursodatabase/sync",
|
||||||
|
"version": "0.1.5",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tursodatabase/database-common": "^0.1.5",
|
||||||
|
"@tursodatabase/sync-common": "^0.1.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@napi-rs/cli": "^3.1.5",
|
||||||
|
"@types/node": "^24.3.1",
|
||||||
|
"typescript": "^5.9.2",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tursodatabase/database": {
|
||||||
|
"resolved": "../../packages/native",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/base64-js": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/better-sqlite3": {
|
||||||
|
"version": "12.2.0",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"prebuild-install": "^7.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20.x || 22.x || 23.x || 24.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bindings": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"file-uri-to-path": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bl": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer": "^5.5.0",
|
||||||
|
"inherits": "^2.0.4",
|
||||||
|
"readable-stream": "^3.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chownr": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/decompress-response": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-response": "^3.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/deep-extend": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/detect-libc": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/drizzle-orm": {
|
||||||
|
"version": "0.44.4",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@aws-sdk/client-rds-data": ">=3",
|
||||||
|
"@cloudflare/workers-types": ">=4",
|
||||||
|
"@electric-sql/pglite": ">=0.2.0",
|
||||||
|
"@libsql/client": ">=0.10.0",
|
||||||
|
"@libsql/client-wasm": ">=0.10.0",
|
||||||
|
"@neondatabase/serverless": ">=0.10.0",
|
||||||
|
"@op-engineering/op-sqlite": ">=2",
|
||||||
|
"@opentelemetry/api": "^1.4.1",
|
||||||
|
"@planetscale/database": ">=1.13",
|
||||||
|
"@prisma/client": "*",
|
||||||
|
"@tidbcloud/serverless": "*",
|
||||||
|
"@types/better-sqlite3": "*",
|
||||||
|
"@types/pg": "*",
|
||||||
|
"@types/sql.js": "*",
|
||||||
|
"@upstash/redis": ">=1.34.7",
|
||||||
|
"@vercel/postgres": ">=0.8.0",
|
||||||
|
"@xata.io/client": "*",
|
||||||
|
"better-sqlite3": ">=7",
|
||||||
|
"bun-types": "*",
|
||||||
|
"expo-sqlite": ">=14.0.0",
|
||||||
|
"gel": ">=2",
|
||||||
|
"knex": "*",
|
||||||
|
"kysely": "*",
|
||||||
|
"mysql2": ">=2",
|
||||||
|
"pg": ">=8",
|
||||||
|
"postgres": ">=3",
|
||||||
|
"sql.js": ">=1",
|
||||||
|
"sqlite3": ">=5"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@aws-sdk/client-rds-data": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@cloudflare/workers-types": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@electric-sql/pglite": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@libsql/client": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@libsql/client-wasm": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@neondatabase/serverless": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@op-engineering/op-sqlite": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@opentelemetry/api": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@planetscale/database": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@prisma/client": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@tidbcloud/serverless": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/better-sqlite3": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/pg": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/sql.js": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@upstash/redis": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@vercel/postgres": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@xata.io/client": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"better-sqlite3": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"bun-types": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"expo-sqlite": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"gel": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"knex": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"kysely": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"mysql2": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"pg": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"postgres": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prisma": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sql.js": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sqlite3": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/end-of-stream": {
|
||||||
|
"version": "1.4.5",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"once": "^1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/expand-template": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"license": "(MIT OR WTFPL)",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/file-uri-to-path": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/fs-constants": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/github-from-package": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/inherits": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/ini": {
|
||||||
|
"version": "1.3.8",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/mimic-response": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minimist": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mkdirp-classic": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/napi-build-utils": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/node-abi": {
|
||||||
|
"version": "3.75.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^7.3.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/once": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prebuild-install": {
|
||||||
|
"version": "7.1.3",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"detect-libc": "^2.0.0",
|
||||||
|
"expand-template": "^2.0.3",
|
||||||
|
"github-from-package": "0.0.0",
|
||||||
|
"minimist": "^1.2.3",
|
||||||
|
"mkdirp-classic": "^0.5.3",
|
||||||
|
"napi-build-utils": "^2.0.0",
|
||||||
|
"node-abi": "^3.3.0",
|
||||||
|
"pump": "^3.0.0",
|
||||||
|
"rc": "^1.2.7",
|
||||||
|
"simple-get": "^4.0.0",
|
||||||
|
"tar-fs": "^2.0.0",
|
||||||
|
"tunnel-agent": "^0.6.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"prebuild-install": "bin.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pump": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"end-of-stream": "^1.1.0",
|
||||||
|
"once": "^1.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rc": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
|
||||||
|
"dependencies": {
|
||||||
|
"deep-extend": "^0.6.0",
|
||||||
|
"ini": "~1.3.0",
|
||||||
|
"minimist": "^1.2.0",
|
||||||
|
"strip-json-comments": "~2.0.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rc": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/readable-stream": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/semver": {
|
||||||
|
"version": "7.7.2",
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/simple-concat": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/simple-get": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"decompress-response": "^6.0.0",
|
||||||
|
"once": "^1.3.1",
|
||||||
|
"simple-concat": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strip-json-comments": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar-fs": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"chownr": "^1.1.1",
|
||||||
|
"mkdirp-classic": "^0.5.2",
|
||||||
|
"pump": "^3.0.0",
|
||||||
|
"tar-stream": "^2.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar-stream": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bl": "^4.0.3",
|
||||||
|
"end-of-stream": "^1.4.1",
|
||||||
|
"fs-constants": "^1.0.0",
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"readable-stream": "^3.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tunnel-agent": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1934
bindings/javascript/package-lock.json
generated
1934
bindings/javascript/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -52,6 +52,7 @@ test('on-disk db', async () => {
|
|||||||
db2.close();
|
db2.close();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// attach is not supported in browser for now
|
||||||
// test('attach', async () => {
|
// test('attach', async () => {
|
||||||
// const path1 = `test-${(Math.random() * 10000) | 0}.db`;
|
// const path1 = `test-${(Math.random() * 10000) | 0}.db`;
|
||||||
// const path2 = `test-${(Math.random() * 10000) | 0}.db`;
|
// const path2 = `test-${(Math.random() * 10000) | 0}.db`;
|
||||||
|
|||||||
29
bindings/javascript/packages/common/async-lock.ts
Normal file
29
bindings/javascript/packages/common/async-lock.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
export class AsyncLock {
|
||||||
|
locked: boolean;
|
||||||
|
queue: any[];
|
||||||
|
constructor() {
|
||||||
|
this.locked = false;
|
||||||
|
this.queue = []
|
||||||
|
}
|
||||||
|
async acquire() {
|
||||||
|
if (!this.locked) {
|
||||||
|
this.locked = true;
|
||||||
|
return Promise.resolve();
|
||||||
|
} else {
|
||||||
|
const block = new Promise(resolve => { this.queue.push(resolve) });
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release() {
|
||||||
|
if (this.locked == false) {
|
||||||
|
throw new Error("invalid state: lock was already unlocked");
|
||||||
|
}
|
||||||
|
const item = this.queue.shift();
|
||||||
|
if (item != null) {
|
||||||
|
this.locked = true;
|
||||||
|
item();
|
||||||
|
} else {
|
||||||
|
this.locked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,5 +2,6 @@ import { NativeDatabase, NativeStatement, DatabaseOpts } from "./types.js";
|
|||||||
import { Database as DatabaseCompat, Statement as StatementCompat } from "./compat.js";
|
import { Database as DatabaseCompat, Statement as StatementCompat } from "./compat.js";
|
||||||
import { Database as DatabasePromise, Statement as StatementPromise } from "./promise.js";
|
import { Database as DatabasePromise, Statement as StatementPromise } from "./promise.js";
|
||||||
import { SqliteError } from "./sqlite-error.js";
|
import { SqliteError } from "./sqlite-error.js";
|
||||||
|
import { AsyncLock } from "./async-lock.js";
|
||||||
|
|
||||||
export { DatabaseCompat, StatementCompat, DatabasePromise, StatementPromise, NativeDatabase, NativeStatement, SqliteError, DatabaseOpts }
|
export { DatabaseCompat, StatementCompat, DatabasePromise, StatementPromise, NativeDatabase, NativeStatement, SqliteError, DatabaseOpts, AsyncLock }
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { AsyncLock } from "./async-lock.js";
|
||||||
import { bindParams } from "./bind.js";
|
import { bindParams } from "./bind.js";
|
||||||
import { SqliteError } from "./sqlite-error.js";
|
import { SqliteError } from "./sqlite-error.js";
|
||||||
import { NativeDatabase, NativeStatement, STEP_IO, STEP_ROW, STEP_DONE, DatabaseOpts } from "./types.js";
|
import { NativeDatabase, NativeStatement, STEP_IO, STEP_ROW, STEP_DONE, DatabaseOpts } from "./types.js";
|
||||||
@@ -32,6 +33,7 @@ class Database {
|
|||||||
db: NativeDatabase;
|
db: NativeDatabase;
|
||||||
memory: boolean;
|
memory: boolean;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
execLock: AsyncLock;
|
||||||
private _inTransaction: boolean = false;
|
private _inTransaction: boolean = false;
|
||||||
/**
|
/**
|
||||||
* Creates a new database connection. If the database file pointed to by `path` does not exists, it will be created.
|
* Creates a new database connection. If the database file pointed to by `path` does not exists, it will be created.
|
||||||
@@ -57,6 +59,7 @@ class Database {
|
|||||||
initialize(db: NativeDatabase, name, readonly) {
|
initialize(db: NativeDatabase, name, readonly) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.memory = db.memory;
|
this.memory = db.memory;
|
||||||
|
this.execLock = new AsyncLock();
|
||||||
Object.defineProperties(this, {
|
Object.defineProperties(this, {
|
||||||
inTransaction: {
|
inTransaction: {
|
||||||
get: () => this._inTransaction,
|
get: () => this._inTransaction,
|
||||||
@@ -112,17 +115,22 @@ class Database {
|
|||||||
const db = this;
|
const db = this;
|
||||||
const wrapTxn = (mode) => {
|
const wrapTxn = (mode) => {
|
||||||
return async (...bindParameters) => {
|
return async (...bindParameters) => {
|
||||||
await db.exec("BEGIN " + mode);
|
await this.execLock.acquire();
|
||||||
db._inTransaction = true;
|
|
||||||
try {
|
try {
|
||||||
const result = await fn(...bindParameters);
|
await db.exec("BEGIN " + mode);
|
||||||
await db.exec("COMMIT");
|
db._inTransaction = true;
|
||||||
db._inTransaction = false;
|
try {
|
||||||
return result;
|
const result = await fn(...bindParameters);
|
||||||
} catch (err) {
|
await db.exec("COMMIT");
|
||||||
await db.exec("ROLLBACK");
|
db._inTransaction = false;
|
||||||
db._inTransaction = false;
|
return result;
|
||||||
throw err;
|
} catch (err) {
|
||||||
|
await db.exec("ROLLBACK");
|
||||||
|
db._inTransaction = false;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.execLock.release();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -195,6 +203,7 @@ class Database {
|
|||||||
throw new TypeError("The database connection is not open");
|
throw new TypeError("The database connection is not open");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.execLock.acquire();
|
||||||
try {
|
try {
|
||||||
const stmt = this.prepare(sql);
|
const stmt = this.prepare(sql);
|
||||||
try {
|
try {
|
||||||
@@ -204,6 +213,8 @@ class Database {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw convertError(err);
|
throw convertError(err);
|
||||||
|
} finally {
|
||||||
|
this.execLock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,25 +313,30 @@ class Statement {
|
|||||||
this.stmt.reset();
|
this.stmt.reset();
|
||||||
bindParams(this.stmt, bindParameters);
|
bindParams(this.stmt, bindParameters);
|
||||||
|
|
||||||
while (true) {
|
await this.db.execLock.acquire();
|
||||||
const stepResult = this.stmt.stepSync();
|
try {
|
||||||
if (stepResult === STEP_IO) {
|
while (true) {
|
||||||
await this.db.db.ioLoopAsync();
|
const stepResult = await this.stmt.stepSync();
|
||||||
continue;
|
if (stepResult === STEP_IO) {
|
||||||
}
|
await this.db.db.ioLoopAsync();
|
||||||
if (stepResult === STEP_DONE) {
|
continue;
|
||||||
break;
|
}
|
||||||
}
|
if (stepResult === STEP_DONE) {
|
||||||
if (stepResult === STEP_ROW) {
|
break;
|
||||||
// For run(), we don't need the row data, just continue
|
}
|
||||||
continue;
|
if (stepResult === STEP_ROW) {
|
||||||
|
// For run(), we don't need the row data, just continue
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lastInsertRowid = this.db.db.lastInsertRowid();
|
||||||
|
const changes = this.db.db.totalChanges() === totalChangesBefore ? 0 : this.db.db.changes();
|
||||||
|
|
||||||
|
return { changes, lastInsertRowid };
|
||||||
|
} finally {
|
||||||
|
this.db.execLock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
const lastInsertRowid = this.db.db.lastInsertRowid();
|
|
||||||
const changes = this.db.db.totalChanges() === totalChangesBefore ? 0 : this.db.db.changes();
|
|
||||||
|
|
||||||
return { changes, lastInsertRowid };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -332,18 +348,23 @@ class Statement {
|
|||||||
this.stmt.reset();
|
this.stmt.reset();
|
||||||
bindParams(this.stmt, bindParameters);
|
bindParams(this.stmt, bindParameters);
|
||||||
|
|
||||||
while (true) {
|
await this.db.execLock.acquire();
|
||||||
const stepResult = this.stmt.stepSync();
|
try {
|
||||||
if (stepResult === STEP_IO) {
|
while (true) {
|
||||||
await this.db.db.ioLoopAsync();
|
const stepResult = await this.stmt.stepSync();
|
||||||
continue;
|
if (stepResult === STEP_IO) {
|
||||||
}
|
await this.db.db.ioLoopAsync();
|
||||||
if (stepResult === STEP_DONE) {
|
continue;
|
||||||
return undefined;
|
}
|
||||||
}
|
if (stepResult === STEP_DONE) {
|
||||||
if (stepResult === STEP_ROW) {
|
return undefined;
|
||||||
return this.stmt.row();
|
}
|
||||||
|
if (stepResult === STEP_ROW) {
|
||||||
|
return this.stmt.row();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,18 +377,23 @@ class Statement {
|
|||||||
this.stmt.reset();
|
this.stmt.reset();
|
||||||
bindParams(this.stmt, bindParameters);
|
bindParams(this.stmt, bindParameters);
|
||||||
|
|
||||||
while (true) {
|
await this.db.execLock.acquire();
|
||||||
const stepResult = this.stmt.stepSync();
|
try {
|
||||||
if (stepResult === STEP_IO) {
|
while (true) {
|
||||||
await this.db.db.ioLoopAsync();
|
const stepResult = await this.stmt.stepSync();
|
||||||
continue;
|
if (stepResult === STEP_IO) {
|
||||||
}
|
await this.db.db.ioLoopAsync();
|
||||||
if (stepResult === STEP_DONE) {
|
continue;
|
||||||
break;
|
}
|
||||||
}
|
if (stepResult === STEP_DONE) {
|
||||||
if (stepResult === STEP_ROW) {
|
break;
|
||||||
yield this.stmt.row();
|
}
|
||||||
|
if (stepResult === STEP_ROW) {
|
||||||
|
yield this.stmt.row();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
this.db.execLock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,20 +407,26 @@ class Statement {
|
|||||||
bindParams(this.stmt, bindParameters);
|
bindParams(this.stmt, bindParameters);
|
||||||
const rows: any[] = [];
|
const rows: any[] = [];
|
||||||
|
|
||||||
while (true) {
|
await this.db.execLock.acquire();
|
||||||
const stepResult = this.stmt.stepSync();
|
try {
|
||||||
if (stepResult === STEP_IO) {
|
while (true) {
|
||||||
await this.db.db.ioLoopAsync();
|
const stepResult = await this.stmt.stepSync();
|
||||||
continue;
|
if (stepResult === STEP_IO) {
|
||||||
}
|
await this.db.db.ioLoopAsync();
|
||||||
if (stepResult === STEP_DONE) {
|
continue;
|
||||||
break;
|
}
|
||||||
}
|
if (stepResult === STEP_DONE) {
|
||||||
if (stepResult === STEP_ROW) {
|
break;
|
||||||
rows.push(this.stmt.row());
|
}
|
||||||
|
if (stepResult === STEP_ROW) {
|
||||||
|
rows.push(this.stmt.row());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
this.db.execLock.release();
|
||||||
}
|
}
|
||||||
return rows;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -22,6 +22,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@napi-rs/cli": "^3.1.5",
|
"@napi-rs/cli": "^3.1.5",
|
||||||
"@types/node": "^24.3.1",
|
"@types/node": "^24.3.1",
|
||||||
|
"better-sqlite3": "^12.2.0",
|
||||||
|
"drizzle-kit": "^0.31.4",
|
||||||
|
"drizzle-orm": "^0.44.5",
|
||||||
"typescript": "^5.9.2",
|
"typescript": "^5.9.2",
|
||||||
"vitest": "^3.2.4"
|
"vitest": "^3.2.4"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,26 @@
|
|||||||
import { unlinkSync } from "node:fs";
|
import { unlinkSync } from "node:fs";
|
||||||
import { expect, test } from 'vitest'
|
import { expect, test } from 'vitest'
|
||||||
import { connect } from './promise.js'
|
import { connect } from './promise.js'
|
||||||
|
import { sql } from 'drizzle-orm';
|
||||||
|
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
||||||
|
|
||||||
|
test('drizzle-orm', async () => {
|
||||||
|
const path = `test-${(Math.random() * 10000) | 0}.db`;
|
||||||
|
try {
|
||||||
|
const conn = await connect(path);
|
||||||
|
const db = drizzle(conn);
|
||||||
|
await db.run('CREATE TABLE t(x, y)');
|
||||||
|
let tasks = [];
|
||||||
|
for (let i = 0; i < 1234; i++) {
|
||||||
|
tasks.push(db.run(sql`INSERT INTO t VALUES (${i}, randomblob(${i} * 5))`))
|
||||||
|
}
|
||||||
|
await Promise.all(tasks);
|
||||||
|
expect(await db.all("SELECT COUNT(*) as cnt FROM t")).toEqual([{ cnt: 1234 }])
|
||||||
|
} finally {
|
||||||
|
unlinkSync(path);
|
||||||
|
unlinkSync(`${path}-wal`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('in-memory db', async () => {
|
test('in-memory db', async () => {
|
||||||
const db = await connect(":memory:");
|
const db = await connect(":memory:");
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ turso_core = { workspace = true }
|
|||||||
turso_node = { workspace = true }
|
turso_node = { workspace = true }
|
||||||
genawaiter = { version = "0.99.1", default-features = false }
|
genawaiter = { version = "0.99.1", default-features = false }
|
||||||
tracing-subscriber = { workspace = true }
|
tracing-subscriber = { workspace = true }
|
||||||
|
tracing.workspace = true
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
napi-build = "2.2.3"
|
napi-build = "2.2.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
browser = ["turso_node/browser"]
|
browser = ["turso_node/browser"]
|
||||||
|
|||||||
BIN
bindings/javascript/sync/packages/browser/a
Executable file
BIN
bindings/javascript/sync/packages/browser/a
Executable file
Binary file not shown.
BIN
bindings/javascript/sync/packages/browser/a-shm
Executable file
BIN
bindings/javascript/sync/packages/browser/a-shm
Executable file
Binary file not shown.
@@ -42,7 +42,7 @@
|
|||||||
"tsc-build": "npm exec tsc && cp sync.wasm32-wasi.wasm ./dist/sync.wasm32-wasi.wasm && WASM_FILE=sync.wasm32-wasi.wasm JS_FILE=./dist/wasm-inline.js node ../../../scripts/inline-wasm-base64.js && npm run bundle",
|
"tsc-build": "npm exec tsc && cp sync.wasm32-wasi.wasm ./dist/sync.wasm32-wasi.wasm && WASM_FILE=sync.wasm32-wasi.wasm JS_FILE=./dist/wasm-inline.js node ../../../scripts/inline-wasm-base64.js && npm run bundle",
|
||||||
"bundle": "vite build",
|
"bundle": "vite build",
|
||||||
"build": "npm run napi-build && npm run tsc-build",
|
"build": "npm run napi-build && npm run tsc-build",
|
||||||
"test": "VITE_TURSO_DB_URL=http://b--a--a.localhost:10000 CI=1 vitest --browser=chromium --run && VITE_TURSO_DB_URL=http://b--a--a.localhost:10000 CI=1 vitest --browser=firefox --run"
|
"test": "VITE_TURSO_DB_URL=http://c--a--a.localhost:10000 CI=1 vitest --testTimeout 30000 --browser=chromium --run && VITE_TURSO_DB_URL=http://c--a--a.localhost:10000 CI=1 vitest --testTimeout 30000 --browser=firefox --run"
|
||||||
},
|
},
|
||||||
"napi": {
|
"napi": {
|
||||||
"binaryName": "sync",
|
"binaryName": "sync",
|
||||||
|
|||||||
@@ -260,6 +260,105 @@ test('persistence-pull-push', async () => {
|
|||||||
expect(rows2.sort(localeCompare)).toEqual(expected.sort(localeCompare))
|
expect(rows2.sort(localeCompare)).toEqual(expected.sort(localeCompare))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('pull-push-concurrent', async () => {
|
||||||
|
{
|
||||||
|
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 5000 });
|
||||||
|
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
||||||
|
await db.exec("DELETE FROM q");
|
||||||
|
await db.push();
|
||||||
|
await db.close();
|
||||||
|
}
|
||||||
|
let pullResolve = null;
|
||||||
|
const pullFinish = new Promise(resolve => pullResolve = resolve);
|
||||||
|
let pushResolve = null;
|
||||||
|
const pushFinish = new Promise(resolve => pushResolve = resolve);
|
||||||
|
let stopPull = false;
|
||||||
|
let stopPush = false;
|
||||||
|
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
||||||
|
let pull = async () => {
|
||||||
|
try {
|
||||||
|
await db.pull();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('pull', e);
|
||||||
|
} finally {
|
||||||
|
if (!stopPull) {
|
||||||
|
setTimeout(pull, 0);
|
||||||
|
} else {
|
||||||
|
pullResolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let push = async () => {
|
||||||
|
try {
|
||||||
|
if ((await db.stats()).operations > 0) {
|
||||||
|
await db.push();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('push', e);
|
||||||
|
} finally {
|
||||||
|
if (!stopPush) {
|
||||||
|
setTimeout(push, 0);
|
||||||
|
} else {
|
||||||
|
pushResolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(pull, 0);
|
||||||
|
setTimeout(push, 0);
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
await db.exec(`INSERT INTO q VALUES ('k${i}', 'v${i}')`);
|
||||||
|
}
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
stopPush = true;
|
||||||
|
await pushFinish;
|
||||||
|
stopPull = true;
|
||||||
|
await pullFinish;
|
||||||
|
console.info(await db.stats());
|
||||||
|
})
|
||||||
|
|
||||||
|
test('concurrent-updates', async () => {
|
||||||
|
{
|
||||||
|
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 5000 });
|
||||||
|
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
||||||
|
await db.exec("DELETE FROM q");
|
||||||
|
await db.push();
|
||||||
|
await db.close();
|
||||||
|
}
|
||||||
|
const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
||||||
|
const db2 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
||||||
|
async function pull(db) {
|
||||||
|
try {
|
||||||
|
await db.pull();
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
setTimeout(async () => await pull(db), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function push(db) {
|
||||||
|
try {
|
||||||
|
await db.push();
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
setTimeout(async () => await push(db), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(async () => await pull(db1), 0)
|
||||||
|
setTimeout(async () => await pull(db2), 0)
|
||||||
|
setTimeout(async () => await push(db1), 0)
|
||||||
|
setTimeout(async () => await push(db2), 0)
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
try {
|
||||||
|
await db1.exec(`INSERT INTO q VALUES ('1', 0) ON CONFLICT DO UPDATE SET y = randomblob(128)`);
|
||||||
|
await db2.exec(`INSERT INTO q VALUES ('2', 0) ON CONFLICT DO UPDATE SET y = randomblob(128)`);
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('transform', async () => {
|
test('transform', async () => {
|
||||||
{
|
{
|
||||||
const db = await connect({
|
const db = await connect({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { registerFileAtWorker, unregisterFileAtWorker } from "@tursodatabase/database-browser-common"
|
import { registerFileAtWorker, unregisterFileAtWorker } from "@tursodatabase/database-browser-common"
|
||||||
import { DatabasePromise, DatabaseOpts, NativeDatabase } from "@tursodatabase/database-common"
|
import { DatabasePromise, DatabaseOpts, NativeDatabase } from "@tursodatabase/database-common"
|
||||||
import { ProtocolIo, run, SyncOpts, RunOpts, memoryIO, SyncEngineStats } from "@tursodatabase/sync-common";
|
import { ProtocolIo, run, SyncOpts, RunOpts, memoryIO, SyncEngineStats, SyncEngineGuards } from "@tursodatabase/sync-common";
|
||||||
|
|
||||||
let BrowserIo: ProtocolIo = {
|
let BrowserIo: ProtocolIo = {
|
||||||
async read(path: string): Promise<Buffer | Uint8Array | null> {
|
async read(path: string): Promise<Buffer | Uint8Array | null> {
|
||||||
@@ -24,6 +24,7 @@ class Database extends DatabasePromise {
|
|||||||
io: ProtocolIo;
|
io: ProtocolIo;
|
||||||
worker: Worker | null;
|
worker: Worker | null;
|
||||||
fsPath: string | null;
|
fsPath: string | null;
|
||||||
|
guards: SyncEngineGuards;
|
||||||
constructor(db: NativeDatabase, io: ProtocolIo, worker: Worker | null, runOpts: RunOpts, engine: any, fsPath: string | null, opts: DatabaseOpts = {}) {
|
constructor(db: NativeDatabase, io: ProtocolIo, worker: Worker | null, runOpts: RunOpts, engine: any, fsPath: string | null, opts: DatabaseOpts = {}) {
|
||||||
super(db, opts)
|
super(db, opts)
|
||||||
this.io = io;
|
this.io = io;
|
||||||
@@ -31,18 +32,21 @@ class Database extends DatabasePromise {
|
|||||||
this.runOpts = runOpts;
|
this.runOpts = runOpts;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.fsPath = fsPath;
|
this.fsPath = fsPath;
|
||||||
|
this.guards = new SyncEngineGuards();
|
||||||
}
|
}
|
||||||
async sync() {
|
async sync() {
|
||||||
await run(this.runOpts, this.io, this.engine, this.engine.sync());
|
await this.push();
|
||||||
|
await this.pull();
|
||||||
}
|
}
|
||||||
async pull() {
|
async pull() {
|
||||||
await run(this.runOpts, this.io, this.engine, this.engine.pull());
|
const changes = await this.guards.wait(async () => await run(this.runOpts, this.io, this.engine, this.engine.wait()));
|
||||||
|
await this.guards.apply(async () => await run(this.runOpts, this.io, this.engine, this.engine.apply(changes)));
|
||||||
}
|
}
|
||||||
async push() {
|
async push() {
|
||||||
await run(this.runOpts, this.io, this.engine, this.engine.push());
|
await this.guards.push(async () => await run(this.runOpts, this.io, this.engine, this.engine.push()));
|
||||||
}
|
}
|
||||||
async checkpoint() {
|
async checkpoint() {
|
||||||
await run(this.runOpts, this.io, this.engine, this.engine.checkpoint());
|
await this.guards.checkpoint(async () => await run(this.runOpts, this.io, this.engine, this.engine.checkpoint()));
|
||||||
}
|
}
|
||||||
async stats(): Promise<SyncEngineStats> {
|
async stats(): Promise<SyncEngineStats> {
|
||||||
return (await run(this.runOpts, this.io, this.engine, this.engine.stats()));
|
return (await run(this.runOpts, this.io, this.engine, this.engine.stats()));
|
||||||
@@ -76,7 +80,8 @@ async function connect(opts: SyncOpts, connect: (any) => any, init: () => Promis
|
|||||||
tablesIgnore: opts.tablesIgnore,
|
tablesIgnore: opts.tablesIgnore,
|
||||||
useTransform: opts.transform != null,
|
useTransform: opts.transform != null,
|
||||||
tracing: opts.tracing,
|
tracing: opts.tracing,
|
||||||
protocolVersion: 1
|
protocolVersion: 1,
|
||||||
|
longPollTimeoutMs: opts.longPollTimeoutMs
|
||||||
});
|
});
|
||||||
const runOpts: RunOpts = {
|
const runOpts: RunOpts = {
|
||||||
url: opts.url,
|
url: opts.url,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { run, memoryIO } from "./run.js"
|
import { run, memoryIO, SyncEngineGuards } from "./run.js"
|
||||||
import { SyncOpts, ProtocolIo, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats } from "./types.js"
|
import { SyncOpts, ProtocolIo, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats } from "./types.js"
|
||||||
|
|
||||||
export { run, memoryIO, }
|
export { run, memoryIO, SyncEngineGuards }
|
||||||
export type { SyncOpts, ProtocolIo, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats }
|
export type { SyncOpts, ProtocolIo, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats }
|
||||||
@@ -21,5 +21,8 @@
|
|||||||
"tsc-build": "npm exec tsc",
|
"tsc-build": "npm exec tsc",
|
||||||
"build": "npm run tsc-build",
|
"build": "npm run tsc-build",
|
||||||
"test": "echo 'no tests'"
|
"test": "echo 'no tests'"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tursodatabase/database-common": "^0.2.0-pre.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { GeneratorResponse, ProtocolIo, RunOpts } from "./types.js";
|
import { GeneratorResponse, ProtocolIo, RunOpts } from "./types.js";
|
||||||
|
import { AsyncLock } from "@tursodatabase/database-common";
|
||||||
|
|
||||||
const GENERATOR_RESUME_IO = 0;
|
const GENERATOR_RESUME_IO = 0;
|
||||||
const GENERATOR_RESUME_DONE = 1;
|
const GENERATOR_RESUME_DONE = 1;
|
||||||
@@ -114,6 +115,10 @@ export async function run(opts: RunOpts, io: ProtocolIo, engine: any, generator:
|
|||||||
if (type == 'SyncEngineStats') {
|
if (type == 'SyncEngineStats') {
|
||||||
return rest;
|
return rest;
|
||||||
}
|
}
|
||||||
|
if (type == 'SyncEngineChanges') {
|
||||||
|
//@ts-ignore
|
||||||
|
return rest.changes;
|
||||||
|
}
|
||||||
for (let request = engine.protocolIo(); request != null; request = engine.protocolIo()) {
|
for (let request = engine.protocolIo(); request != null; request = engine.protocolIo()) {
|
||||||
tasks.push(trackPromise(process(opts, io, request)));
|
tasks.push(trackPromise(process(opts, io, request)));
|
||||||
}
|
}
|
||||||
@@ -124,4 +129,67 @@ export async function run(opts: RunOpts, io: ProtocolIo, engine: any, generator:
|
|||||||
tasks = tasks.filter(t => !t.finished);
|
tasks = tasks.filter(t => !t.finished);
|
||||||
}
|
}
|
||||||
return generator.take();
|
return generator.take();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export class SyncEngineGuards {
|
||||||
|
waitLock: AsyncLock;
|
||||||
|
pushLock: AsyncLock;
|
||||||
|
pullLock: AsyncLock;
|
||||||
|
checkpointLock: AsyncLock;
|
||||||
|
constructor() {
|
||||||
|
this.waitLock = new AsyncLock();
|
||||||
|
this.pushLock = new AsyncLock();
|
||||||
|
this.pullLock = new AsyncLock();
|
||||||
|
this.checkpointLock = new AsyncLock();
|
||||||
|
}
|
||||||
|
async wait(f: () => Promise<any>): Promise<any> {
|
||||||
|
try {
|
||||||
|
await this.waitLock.acquire();
|
||||||
|
return await f();
|
||||||
|
} finally {
|
||||||
|
this.waitLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async push(f: () => Promise<void>) {
|
||||||
|
try {
|
||||||
|
await this.pushLock.acquire();
|
||||||
|
await this.pullLock.acquire();
|
||||||
|
await this.checkpointLock.acquire();
|
||||||
|
return await f();
|
||||||
|
} finally {
|
||||||
|
this.pushLock.release();
|
||||||
|
this.pullLock.release();
|
||||||
|
this.checkpointLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async apply(f: () => Promise<void>) {
|
||||||
|
try {
|
||||||
|
await this.waitLock.acquire();
|
||||||
|
await this.pushLock.acquire();
|
||||||
|
await this.pullLock.acquire();
|
||||||
|
await this.checkpointLock.acquire();
|
||||||
|
return await f();
|
||||||
|
} finally {
|
||||||
|
this.waitLock.release();
|
||||||
|
this.pushLock.release();
|
||||||
|
this.pullLock.release();
|
||||||
|
this.checkpointLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async checkpoint(f: () => Promise<void>) {
|
||||||
|
try {
|
||||||
|
await this.waitLock.acquire();
|
||||||
|
await this.pushLock.acquire();
|
||||||
|
await this.pullLock.acquire();
|
||||||
|
await this.checkpointLock.acquire();
|
||||||
|
return await f();
|
||||||
|
} finally {
|
||||||
|
this.waitLock.release();
|
||||||
|
this.pushLock.release();
|
||||||
|
this.pullLock.release();
|
||||||
|
this.checkpointLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,9 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"module": "esnext",
|
"module": "nodenext",
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
"outDir": "dist/",
|
"outDir": "dist/",
|
||||||
"lib": [
|
"lib": [
|
||||||
"es2020",
|
"es2020",
|
||||||
|
|||||||
@@ -54,4 +54,4 @@ export interface SyncEngineStats {
|
|||||||
revision: string | null;
|
revision: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GeneratorResponse = { type: 'IO' } | { type: 'Done' } | ({ type: 'SyncEngineStats' } & SyncEngineStats)
|
export type GeneratorResponse = { type: 'IO' } | { type: 'Done' } | ({ type: 'SyncEngineStats' } & SyncEngineStats) | { type: 'SyncEngineChanges', changes: any }
|
||||||
@@ -174,15 +174,19 @@ export declare class SyncEngine {
|
|||||||
/** Runs the I/O loop asynchronously, returning a Promise. */
|
/** Runs the I/O loop asynchronously, returning a Promise. */
|
||||||
ioLoopAsync(): Promise<void>
|
ioLoopAsync(): Promise<void>
|
||||||
protocolIo(): JsProtocolRequestBytes | null
|
protocolIo(): JsProtocolRequestBytes | null
|
||||||
sync(): GeneratorHolder
|
|
||||||
push(): GeneratorHolder
|
push(): GeneratorHolder
|
||||||
stats(): GeneratorHolder
|
stats(): GeneratorHolder
|
||||||
pull(): GeneratorHolder
|
wait(): GeneratorHolder
|
||||||
|
apply(changes: SyncEngineChanges): GeneratorHolder
|
||||||
checkpoint(): GeneratorHolder
|
checkpoint(): GeneratorHolder
|
||||||
open(): Database
|
open(): Database
|
||||||
close(): void
|
close(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export declare class SyncEngineChanges {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export declare const enum DatabaseChangeTypeJs {
|
export declare const enum DatabaseChangeTypeJs {
|
||||||
Insert = 0,
|
Insert = 0,
|
||||||
Update = 1,
|
Update = 1,
|
||||||
@@ -217,6 +221,7 @@ export type GeneratorResponse =
|
|||||||
| { type: 'IO' }
|
| { type: 'IO' }
|
||||||
| { type: 'Done' }
|
| { type: 'Done' }
|
||||||
| { type: 'SyncEngineStats', operations: number, mainWal: number, revertWal: number, lastPullUnixTime: number, lastPushUnixTime?: number, revision?: string }
|
| { type: 'SyncEngineStats', operations: number, mainWal: number, revertWal: number, lastPullUnixTime: number, lastPushUnixTime?: number, revision?: string }
|
||||||
|
| { type: 'SyncEngineChanges', changes: SyncEngineChanges }
|
||||||
|
|
||||||
export type JsProtocolRequest =
|
export type JsProtocolRequest =
|
||||||
| { type: 'Http', method: string, path: string, body?: Array<number>, headers: Array<[string, string]> }
|
| { type: 'Http', method: string, path: string, body?: Array<number>, headers: Array<[string, string]> }
|
||||||
|
|||||||
@@ -508,7 +508,7 @@ if (!nativeBinding) {
|
|||||||
throw new Error(`Failed to load native binding`)
|
throw new Error(`Failed to load native binding`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { Database, Opfs, OpfsFile, Statement, initThreadPool, GeneratorHolder, JsDataCompletion, JsProtocolIo, JsProtocolRequestBytes, SyncEngine, DatabaseChangeTypeJs, SyncEngineProtocolVersion } = nativeBinding
|
const { Database, Statement, GeneratorHolder, JsDataCompletion, JsProtocolIo, JsProtocolRequestBytes, SyncEngine, SyncEngineChanges, DatabaseChangeTypeJs, SyncEngineProtocolVersion } = nativeBinding
|
||||||
export { Database }
|
export { Database }
|
||||||
export { Opfs }
|
export { Opfs }
|
||||||
export { OpfsFile }
|
export { OpfsFile }
|
||||||
@@ -519,5 +519,6 @@ export { JsDataCompletion }
|
|||||||
export { JsProtocolIo }
|
export { JsProtocolIo }
|
||||||
export { JsProtocolRequestBytes }
|
export { JsProtocolRequestBytes }
|
||||||
export { SyncEngine }
|
export { SyncEngine }
|
||||||
|
export { SyncEngineChanges }
|
||||||
export { DatabaseChangeTypeJs }
|
export { DatabaseChangeTypeJs }
|
||||||
export { SyncEngineProtocolVersion }
|
export { SyncEngineProtocolVersion }
|
||||||
|
|||||||
14
bindings/javascript/sync/packages/native/log
Normal file
14
bindings/javascript/sync/packages/native/log
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
> @tursodatabase/sync@0.2.0-pre.3 test
|
||||||
|
> VITE_TURSO_DB_URL=http://c--a--a.localhost:10000 vitest --run -t update
|
||||||
|
|
||||||
|
|
||||||
|
RUN v3.2.4 /home/sivukhin/turso/limbo/bindings/javascript/sync/packages/native
|
||||||
|
|
||||||
|
✓ promise.test.ts (14 tests | 13 skipped) 109ms
|
||||||
|
|
||||||
|
Test Files 1 passed (1)
|
||||||
|
Tests 1 passed | 13 skipped (14)
|
||||||
|
Start at 16:40:50
|
||||||
|
Duration 436ms (transform 99ms, setup 0ms, collect 118ms, tests 109ms, environment 0ms, prepare 57ms)
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"napi-artifacts": "napi artifacts --output-dir .",
|
"napi-artifacts": "napi artifacts --output-dir .",
|
||||||
"tsc-build": "npm exec tsc",
|
"tsc-build": "npm exec tsc",
|
||||||
"build": "npm run napi-build && npm run tsc-build",
|
"build": "npm run napi-build && npm run tsc-build",
|
||||||
"test": "VITE_TURSO_DB_URL=http://b--a--a.localhost:10000 vitest --run",
|
"test": "VITE_TURSO_DB_URL=http://c--a--a.localhost:10000 vitest --run",
|
||||||
"prepublishOnly": "npm run napi-dirs && npm run napi-artifacts && napi prepublish -t npm"
|
"prepublishOnly": "npm run napi-dirs && npm run napi-artifacts && napi prepublish -t npm"
|
||||||
},
|
},
|
||||||
"napi": {
|
"napi": {
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ test('checkpoint', async () => {
|
|||||||
await db1.checkpoint();
|
await db1.checkpoint();
|
||||||
expect((await db1.stats()).mainWal).toBe(0);
|
expect((await db1.stats()).mainWal).toBe(0);
|
||||||
let revertWal = (await db1.stats()).revertWal;
|
let revertWal = (await db1.stats()).revertWal;
|
||||||
expect(revertWal).toBeLessThan(4096 * 1000 / 100);
|
expect(revertWal).toBeLessThan(4096 * 1000 / 50);
|
||||||
|
|
||||||
for (let i = 0; i < 1000; i++) {
|
for (let i = 0; i < 1000; i++) {
|
||||||
await db1.exec(`UPDATE q SET y = 'u${i}' WHERE x = 'k${i}'`);
|
await db1.exec(`UPDATE q SET y = 'u${i}' WHERE x = 'k${i}'`);
|
||||||
@@ -284,6 +284,119 @@ test('persistence-pull-push', async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('update', async () => {
|
||||||
|
{
|
||||||
|
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 5000 });
|
||||||
|
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
||||||
|
await db.exec("DELETE FROM q");
|
||||||
|
await db.push();
|
||||||
|
await db.close();
|
||||||
|
}
|
||||||
|
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
||||||
|
await db.exec("INSERT INTO q VALUES ('1', '2')")
|
||||||
|
await db.push();
|
||||||
|
await db.exec("INSERT INTO q VALUES ('1', '2') ON CONFLICT DO UPDATE SET y = '3'")
|
||||||
|
await db.push();
|
||||||
|
})
|
||||||
|
|
||||||
|
test('concurrent-updates', async () => {
|
||||||
|
{
|
||||||
|
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 5000 });
|
||||||
|
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
||||||
|
await db.exec("DELETE FROM q");
|
||||||
|
await db.push();
|
||||||
|
await db.close();
|
||||||
|
}
|
||||||
|
const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
||||||
|
async function pull(db) {
|
||||||
|
try {
|
||||||
|
await db.pull();
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
setTimeout(async () => await pull(db), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function push(db) {
|
||||||
|
try {
|
||||||
|
await db.push();
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
setTimeout(async () => await push(db), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(async () => await pull(db1), 0)
|
||||||
|
setTimeout(async () => await push(db1), 0)
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
try {
|
||||||
|
await Promise.all([
|
||||||
|
db1.exec(`INSERT INTO q VALUES ('1', 0) ON CONFLICT DO UPDATE SET y = ${i + 1}`),
|
||||||
|
db1.exec(`INSERT INTO q VALUES ('2', 0) ON CONFLICT DO UPDATE SET y = ${i + 1}`)
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('pull-push-concurrent', async () => {
|
||||||
|
{
|
||||||
|
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 5000 });
|
||||||
|
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
||||||
|
await db.exec("DELETE FROM q");
|
||||||
|
await db.push();
|
||||||
|
await db.close();
|
||||||
|
}
|
||||||
|
let pullResolve = null;
|
||||||
|
const pullFinish = new Promise(resolve => pullResolve = resolve);
|
||||||
|
let pushResolve = null;
|
||||||
|
const pushFinish = new Promise(resolve => pushResolve = resolve);
|
||||||
|
let stopPull = false;
|
||||||
|
let stopPush = false;
|
||||||
|
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
||||||
|
let pull = async () => {
|
||||||
|
try {
|
||||||
|
await db.pull();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('pull', e);
|
||||||
|
} finally {
|
||||||
|
if (!stopPull) {
|
||||||
|
setTimeout(pull, 0);
|
||||||
|
} else {
|
||||||
|
pullResolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let push = async () => {
|
||||||
|
try {
|
||||||
|
if ((await db.stats()).operations > 0) {
|
||||||
|
await db.push();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('push', e);
|
||||||
|
} finally {
|
||||||
|
if (!stopPush) {
|
||||||
|
setTimeout(push, 0);
|
||||||
|
} else {
|
||||||
|
pushResolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(pull, 0);
|
||||||
|
setTimeout(push, 0);
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
await db.exec(`INSERT INTO q VALUES ('k${i}', 'v${i}')`);
|
||||||
|
}
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
stopPush = true;
|
||||||
|
await pushFinish;
|
||||||
|
stopPull = true;
|
||||||
|
await pullFinish;
|
||||||
|
console.info(await db.stats());
|
||||||
|
})
|
||||||
|
|
||||||
test('transform', async () => {
|
test('transform', async () => {
|
||||||
{
|
{
|
||||||
const db = await connect({
|
const db = await connect({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DatabasePromise, DatabaseOpts, NativeDatabase } from "@tursodatabase/database-common"
|
import { DatabasePromise, DatabaseOpts, NativeDatabase } from "@tursodatabase/database-common"
|
||||||
import { ProtocolIo, run, SyncOpts, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats } from "@tursodatabase/sync-common";
|
import { ProtocolIo, run, SyncOpts, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats, SyncEngineGuards } from "@tursodatabase/sync-common";
|
||||||
import { Database as NativeDB, SyncEngine } from "#index";
|
import { Database as NativeDB, SyncEngine } from "#index";
|
||||||
import { promises } from "node:fs";
|
import { promises } from "node:fs";
|
||||||
|
|
||||||
@@ -43,23 +43,27 @@ class Database extends DatabasePromise {
|
|||||||
runOpts: RunOpts;
|
runOpts: RunOpts;
|
||||||
engine: any;
|
engine: any;
|
||||||
io: ProtocolIo;
|
io: ProtocolIo;
|
||||||
|
guards: SyncEngineGuards
|
||||||
constructor(db: NativeDatabase, io: ProtocolIo, runOpts: RunOpts, engine: any, opts: DatabaseOpts = {}) {
|
constructor(db: NativeDatabase, io: ProtocolIo, runOpts: RunOpts, engine: any, opts: DatabaseOpts = {}) {
|
||||||
super(db, opts)
|
super(db, opts)
|
||||||
this.runOpts = runOpts;
|
this.runOpts = runOpts;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.io = io;
|
this.io = io;
|
||||||
|
this.guards = new SyncEngineGuards();
|
||||||
}
|
}
|
||||||
async sync() {
|
async sync() {
|
||||||
await run(this.runOpts, this.io, this.engine, this.engine.sync());
|
await this.push();
|
||||||
|
await this.pull();
|
||||||
}
|
}
|
||||||
async pull() {
|
async pull() {
|
||||||
await run(this.runOpts, this.io, this.engine, this.engine.pull());
|
const changes = await this.guards.wait(async () => await run(this.runOpts, this.io, this.engine, this.engine.wait()));
|
||||||
|
await this.guards.apply(async () => await run(this.runOpts, this.io, this.engine, this.engine.apply(changes)));
|
||||||
}
|
}
|
||||||
async push() {
|
async push() {
|
||||||
await run(this.runOpts, this.io, this.engine, this.engine.push());
|
await this.guards.push(async () => await run(this.runOpts, this.io, this.engine, this.engine.push()));
|
||||||
}
|
}
|
||||||
async checkpoint() {
|
async checkpoint() {
|
||||||
await run(this.runOpts, this.io, this.engine, this.engine.checkpoint());
|
await this.guards.checkpoint(async () => await run(this.runOpts, this.io, this.engine, this.engine.checkpoint()));
|
||||||
}
|
}
|
||||||
async stats(): Promise<SyncEngineStats> {
|
async stats(): Promise<SyncEngineStats> {
|
||||||
return (await run(this.runOpts, this.io, this.engine, this.engine.stats()));
|
return (await run(this.runOpts, this.io, this.engine, this.engine.stats()));
|
||||||
@@ -83,8 +87,8 @@ async function connect(opts: SyncOpts): Promise<Database> {
|
|||||||
tablesIgnore: opts.tablesIgnore,
|
tablesIgnore: opts.tablesIgnore,
|
||||||
useTransform: opts.transform != null,
|
useTransform: opts.transform != null,
|
||||||
tracing: opts.tracing,
|
tracing: opts.tracing,
|
||||||
longPollTimeoutMs: opts.longPollTimeoutMs,
|
|
||||||
protocolVersion: 1,
|
protocolVersion: 1,
|
||||||
|
longPollTimeoutMs: opts.longPollTimeoutMs,
|
||||||
});
|
});
|
||||||
const runOpts: RunOpts = {
|
const runOpts: RunOpts = {
|
||||||
url: opts.url,
|
url: opts.url,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use turso_sync_engine::types::ProtocolCommand;
|
use turso_sync_engine::types::{DbChangesStatus, ProtocolCommand};
|
||||||
|
|
||||||
pub const GENERATOR_RESUME_IO: u32 = 0;
|
pub const GENERATOR_RESUME_IO: u32 = 0;
|
||||||
pub const GENERATOR_RESUME_DONE: u32 = 1;
|
pub const GENERATOR_RESUME_DONE: u32 = 1;
|
||||||
@@ -35,7 +35,12 @@ impl<F: Future<Output = turso_sync_engine::Result<()>>> Generator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi(discriminant = "type")]
|
#[napi]
|
||||||
|
pub struct SyncEngineChanges {
|
||||||
|
pub(crate) status: Box<Option<DbChangesStatus>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(discriminant = "type", object_from_js = false)]
|
||||||
pub enum GeneratorResponse {
|
pub enum GeneratorResponse {
|
||||||
IO,
|
IO,
|
||||||
Done,
|
Done,
|
||||||
@@ -47,6 +52,9 @@ pub enum GeneratorResponse {
|
|||||||
last_push_unix_time: Option<i64>,
|
last_push_unix_time: Option<i64>,
|
||||||
revision: Option<String>,
|
revision: Option<String>,
|
||||||
},
|
},
|
||||||
|
SyncEngineChanges {
|
||||||
|
changes: SyncEngineChanges,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use turso_sync_engine::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
generator::{GeneratorHolder, GeneratorResponse},
|
generator::{GeneratorHolder, GeneratorResponse, SyncEngineChanges},
|
||||||
js_protocol_io::{JsProtocolIo, JsProtocolRequestBytes},
|
js_protocol_io::{JsProtocolIo, JsProtocolRequestBytes},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,38 +28,6 @@ pub struct DatabaseOpts {
|
|||||||
pub path: String,
|
pub path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SyncEngineGuard {
|
|
||||||
inner: Arc<RwLock<Option<DatabaseSyncEngine<JsProtocolIo>>>>,
|
|
||||||
wait_lock: Mutex<()>,
|
|
||||||
push_lock: Mutex<()>,
|
|
||||||
pull_lock: Mutex<()>,
|
|
||||||
checkpoint_lock: Mutex<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyncEngineGuard {
|
|
||||||
fn checkpoint_lock(&self) -> (MutexGuard<'_, ()>, MutexGuard<'_, ()>, MutexGuard<'_, ()>) {
|
|
||||||
let push = self.push_lock.lock().unwrap();
|
|
||||||
let pull = self.pull_lock.lock().unwrap();
|
|
||||||
let checkpoint = self.checkpoint_lock.lock().unwrap();
|
|
||||||
(push, pull, checkpoint)
|
|
||||||
}
|
|
||||||
fn pull_lock(&self) -> (MutexGuard<'_, ()>, MutexGuard<'_, ()>, MutexGuard<'_, ()>) {
|
|
||||||
let wait = self.wait_lock.lock().unwrap();
|
|
||||||
let push = self.push_lock.lock().unwrap();
|
|
||||||
let pull = self.pull_lock.lock().unwrap();
|
|
||||||
(wait, push, pull)
|
|
||||||
}
|
|
||||||
fn push_lock(&self) -> MutexGuard<'_, ()> {
|
|
||||||
let push = self.push_lock.lock().unwrap();
|
|
||||||
push
|
|
||||||
}
|
|
||||||
fn wait_lock(&self) -> (MutexGuard<'_, ()>, MutexGuard<'_, ()>) {
|
|
||||||
let wait = self.wait_lock.lock().unwrap();
|
|
||||||
let pull = self.pull_lock.lock().unwrap();
|
|
||||||
(wait, pull)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub struct SyncEngine {
|
pub struct SyncEngine {
|
||||||
path: String,
|
path: String,
|
||||||
@@ -71,7 +39,7 @@ pub struct SyncEngine {
|
|||||||
use_transform: bool,
|
use_transform: bool,
|
||||||
io: Option<Arc<dyn turso_core::IO>>,
|
io: Option<Arc<dyn turso_core::IO>>,
|
||||||
protocol: Option<Arc<JsProtocolIo>>,
|
protocol: Option<Arc<JsProtocolIo>>,
|
||||||
sync_engine: Arc<SyncEngineGuard>,
|
sync_engine: Arc<RwLock<Option<DatabaseSyncEngine<JsProtocolIo>>>>,
|
||||||
opened: Arc<Mutex<Option<turso_node::Database>>>,
|
opened: Arc<Mutex<Option<turso_node::Database>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,13 +182,7 @@ impl SyncEngine {
|
|||||||
tables_ignore: opts.tables_ignore.unwrap_or_default(),
|
tables_ignore: opts.tables_ignore.unwrap_or_default(),
|
||||||
use_transform: opts.use_transform,
|
use_transform: opts.use_transform,
|
||||||
#[allow(clippy::arc_with_non_send_sync)]
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
sync_engine: Arc::new(SyncEngineGuard {
|
sync_engine: Arc::new(RwLock::new(None)),
|
||||||
inner: Arc::new(RwLock::new(None)),
|
|
||||||
wait_lock: Mutex::new(()),
|
|
||||||
push_lock: Mutex::new(()),
|
|
||||||
pull_lock: Mutex::new(()),
|
|
||||||
checkpoint_lock: Mutex::new(()),
|
|
||||||
}),
|
|
||||||
io: Some(io),
|
io: Some(io),
|
||||||
protocol: Some(Arc::new(JsProtocolIo::default())),
|
protocol: Some(Arc::new(JsProtocolIo::default())),
|
||||||
#[allow(clippy::arc_with_non_send_sync)]
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
@@ -257,7 +219,7 @@ impl SyncEngine {
|
|||||||
let connection = initialized.connect_rw(&coro).await?;
|
let connection = initialized.connect_rw(&coro).await?;
|
||||||
let db = turso_node::Database::create(None, io.clone(), connection, path);
|
let db = turso_node::Database::create(None, io.clone(), connection, path);
|
||||||
|
|
||||||
*sync_engine.inner.write().unwrap() = Some(initialized);
|
*sync_engine.write().unwrap() = Some(initialized);
|
||||||
*opened.lock().unwrap() = Some(db);
|
*opened.lock().unwrap() = Some(db);
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
@@ -288,22 +250,10 @@ impl SyncEngine {
|
|||||||
Ok(self.protocol()?.take_request())
|
Ok(self.protocol()?.take_request())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn sync(&self) -> GeneratorHolder {
|
|
||||||
self.run(async move |coro, guard| {
|
|
||||||
let _lock = guard.pull_lock();
|
|
||||||
let sync_engine = try_read(&guard.inner)?;
|
|
||||||
let sync_engine = try_unwrap(&sync_engine)?;
|
|
||||||
sync_engine.sync(coro).await?;
|
|
||||||
Ok(None)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn push(&self) -> GeneratorHolder {
|
pub fn push(&self) -> GeneratorHolder {
|
||||||
self.run(async move |coro, guard| {
|
self.run(async move |coro, guard| {
|
||||||
let _lock = guard.push_lock();
|
let sync_engine = try_read(&guard)?;
|
||||||
let sync_engine = try_read(&guard.inner)?;
|
|
||||||
let sync_engine = try_unwrap(&sync_engine)?;
|
let sync_engine = try_unwrap(&sync_engine)?;
|
||||||
sync_engine.push_changes_to_remote(coro).await?;
|
sync_engine.push_changes_to_remote(coro).await?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -313,7 +263,7 @@ impl SyncEngine {
|
|||||||
#[napi]
|
#[napi]
|
||||||
pub fn stats(&self) -> GeneratorHolder {
|
pub fn stats(&self) -> GeneratorHolder {
|
||||||
self.run(async move |coro, guard| {
|
self.run(async move |coro, guard| {
|
||||||
let sync_engine = try_read(&guard.inner)?;
|
let sync_engine = try_read(&guard)?;
|
||||||
let sync_engine = try_unwrap(&sync_engine)?;
|
let sync_engine = try_unwrap(&sync_engine)?;
|
||||||
let stats = sync_engine.stats(coro).await?;
|
let stats = sync_engine.stats(coro).await?;
|
||||||
Ok(Some(GeneratorResponse::SyncEngineStats {
|
Ok(Some(GeneratorResponse::SyncEngineStats {
|
||||||
@@ -328,16 +278,25 @@ impl SyncEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn pull(&self) -> GeneratorHolder {
|
pub fn wait(&self) -> GeneratorHolder {
|
||||||
self.run(async move |coro, guard| {
|
self.run(async move |coro, guard| {
|
||||||
let sync_engine = try_read(&guard.inner)?;
|
let sync_engine = try_read(&guard)?;
|
||||||
let sync_engine = try_unwrap(&sync_engine)?;
|
let sync_engine = try_unwrap(&sync_engine)?;
|
||||||
let changes = {
|
Ok(Some(GeneratorResponse::SyncEngineChanges {
|
||||||
let _lock = guard.wait_lock();
|
changes: SyncEngineChanges {
|
||||||
sync_engine.wait_changes_from_remote(coro).await?
|
status: Box::new(Some(sync_engine.wait_changes_from_remote(coro).await?)),
|
||||||
};
|
},
|
||||||
let _lock = guard.pull_lock();
|
}))
|
||||||
sync_engine.apply_changes_from_remote(coro, changes).await?;
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn apply(&self, changes: &mut SyncEngineChanges) -> GeneratorHolder {
|
||||||
|
let status = changes.status.take().unwrap();
|
||||||
|
self.run(async move |coro, guard| {
|
||||||
|
let sync_engine = try_read(&guard)?;
|
||||||
|
let sync_engine = try_unwrap(&sync_engine)?;
|
||||||
|
sync_engine.apply_changes_from_remote(coro, status).await?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -345,8 +304,7 @@ impl SyncEngine {
|
|||||||
#[napi]
|
#[napi]
|
||||||
pub fn checkpoint(&self) -> GeneratorHolder {
|
pub fn checkpoint(&self) -> GeneratorHolder {
|
||||||
self.run(async move |coro, guard| {
|
self.run(async move |coro, guard| {
|
||||||
let _lock = guard.checkpoint_lock();
|
let sync_engine = try_read(&guard)?;
|
||||||
let sync_engine = try_read(&guard.inner)?;
|
|
||||||
let sync_engine = try_unwrap(&sync_engine)?;
|
let sync_engine = try_unwrap(&sync_engine)?;
|
||||||
sync_engine.checkpoint(coro).await?;
|
sync_engine.checkpoint(coro).await?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -367,7 +325,7 @@ impl SyncEngine {
|
|||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn close(&mut self) {
|
pub fn close(&mut self) {
|
||||||
let _ = self.sync_engine.inner.write().unwrap().take();
|
let _ = self.sync_engine.write().unwrap().take();
|
||||||
let _ = self.opened.lock().unwrap().take().unwrap();
|
let _ = self.opened.lock().unwrap().take().unwrap();
|
||||||
let _ = self.io.take();
|
let _ = self.io.take();
|
||||||
let _ = self.protocol.take();
|
let _ = self.protocol.take();
|
||||||
@@ -396,7 +354,7 @@ impl SyncEngine {
|
|||||||
&self,
|
&self,
|
||||||
f: impl AsyncFnOnce(
|
f: impl AsyncFnOnce(
|
||||||
&Coro<()>,
|
&Coro<()>,
|
||||||
&Arc<SyncEngineGuard>,
|
&Arc<RwLock<Option<DatabaseSyncEngine<JsProtocolIo>>>>,
|
||||||
) -> turso_sync_engine::Result<Option<GeneratorResponse>>
|
) -> turso_sync_engine::Result<Option<GeneratorResponse>>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
) -> GeneratorHolder {
|
) -> GeneratorHolder {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user