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-build",
|
||||
"napi-derive",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"turso_core",
|
||||
"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();
|
||||
})
|
||||
|
||||
// attach is not supported in browser for now
|
||||
// test('attach', async () => {
|
||||
// const path1 = `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 DatabasePromise, Statement as StatementPromise } from "./promise.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 { SqliteError } from "./sqlite-error.js";
|
||||
import { NativeDatabase, NativeStatement, STEP_IO, STEP_ROW, STEP_DONE, DatabaseOpts } from "./types.js";
|
||||
@@ -32,6 +33,7 @@ class Database {
|
||||
db: NativeDatabase;
|
||||
memory: boolean;
|
||||
open: boolean;
|
||||
execLock: AsyncLock;
|
||||
private _inTransaction: boolean = false;
|
||||
/**
|
||||
* 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) {
|
||||
this.db = db;
|
||||
this.memory = db.memory;
|
||||
this.execLock = new AsyncLock();
|
||||
Object.defineProperties(this, {
|
||||
inTransaction: {
|
||||
get: () => this._inTransaction,
|
||||
@@ -112,6 +115,8 @@ class Database {
|
||||
const db = this;
|
||||
const wrapTxn = (mode) => {
|
||||
return async (...bindParameters) => {
|
||||
await this.execLock.acquire();
|
||||
try {
|
||||
await db.exec("BEGIN " + mode);
|
||||
db._inTransaction = true;
|
||||
try {
|
||||
@@ -124,6 +129,9 @@ class Database {
|
||||
db._inTransaction = false;
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
this.execLock.release();
|
||||
}
|
||||
};
|
||||
};
|
||||
const properties = {
|
||||
@@ -195,6 +203,7 @@ class Database {
|
||||
throw new TypeError("The database connection is not open");
|
||||
}
|
||||
|
||||
await this.execLock.acquire();
|
||||
try {
|
||||
const stmt = this.prepare(sql);
|
||||
try {
|
||||
@@ -204,6 +213,8 @@ class Database {
|
||||
}
|
||||
} catch (err) {
|
||||
throw convertError(err);
|
||||
} finally {
|
||||
this.execLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,8 +313,10 @@ class Statement {
|
||||
this.stmt.reset();
|
||||
bindParams(this.stmt, bindParameters);
|
||||
|
||||
await this.db.execLock.acquire();
|
||||
try {
|
||||
while (true) {
|
||||
const stepResult = this.stmt.stepSync();
|
||||
const stepResult = await this.stmt.stepSync();
|
||||
if (stepResult === STEP_IO) {
|
||||
await this.db.db.ioLoopAsync();
|
||||
continue;
|
||||
@@ -321,6 +334,9 @@ class Statement {
|
||||
const changes = this.db.db.totalChanges() === totalChangesBefore ? 0 : this.db.db.changes();
|
||||
|
||||
return { changes, lastInsertRowid };
|
||||
} finally {
|
||||
this.db.execLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,8 +348,10 @@ class Statement {
|
||||
this.stmt.reset();
|
||||
bindParams(this.stmt, bindParameters);
|
||||
|
||||
await this.db.execLock.acquire();
|
||||
try {
|
||||
while (true) {
|
||||
const stepResult = this.stmt.stepSync();
|
||||
const stepResult = await this.stmt.stepSync();
|
||||
if (stepResult === STEP_IO) {
|
||||
await this.db.db.ioLoopAsync();
|
||||
continue;
|
||||
@@ -345,6 +363,9 @@ class Statement {
|
||||
return this.stmt.row();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,8 +377,10 @@ class Statement {
|
||||
this.stmt.reset();
|
||||
bindParams(this.stmt, bindParameters);
|
||||
|
||||
await this.db.execLock.acquire();
|
||||
try {
|
||||
while (true) {
|
||||
const stepResult = this.stmt.stepSync();
|
||||
const stepResult = await this.stmt.stepSync();
|
||||
if (stepResult === STEP_IO) {
|
||||
await this.db.db.ioLoopAsync();
|
||||
continue;
|
||||
@@ -369,6 +392,9 @@ class Statement {
|
||||
yield this.stmt.row();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.db.execLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,8 +407,10 @@ class Statement {
|
||||
bindParams(this.stmt, bindParameters);
|
||||
const rows: any[] = [];
|
||||
|
||||
await this.db.execLock.acquire();
|
||||
try {
|
||||
while (true) {
|
||||
const stepResult = this.stmt.stepSync();
|
||||
const stepResult = await this.stmt.stepSync();
|
||||
if (stepResult === STEP_IO) {
|
||||
await this.db.db.ioLoopAsync();
|
||||
continue;
|
||||
@@ -396,6 +424,10 @@ class Statement {
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
finally {
|
||||
this.db.execLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupts the statement.
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
"devDependencies": {
|
||||
"@napi-rs/cli": "^3.1.5",
|
||||
"@types/node": "^24.3.1",
|
||||
"better-sqlite3": "^12.2.0",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"typescript": "^5.9.2",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
import { unlinkSync } from "node:fs";
|
||||
import { expect, test } from 'vitest'
|
||||
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 () => {
|
||||
const db = await connect(":memory:");
|
||||
|
||||
@@ -18,6 +18,7 @@ turso_core = { workspace = true }
|
||||
turso_node = { workspace = true }
|
||||
genawaiter = { version = "0.99.1", default-features = false }
|
||||
tracing-subscriber = { workspace = true }
|
||||
tracing.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
napi-build = "2.2.3"
|
||||
|
||||
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",
|
||||
"bundle": "vite 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": {
|
||||
"binaryName": "sync",
|
||||
|
||||
@@ -260,6 +260,105 @@ test('persistence-pull-push', async () => {
|
||||
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 () => {
|
||||
{
|
||||
const db = await connect({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { registerFileAtWorker, unregisterFileAtWorker } from "@tursodatabase/database-browser-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 = {
|
||||
async read(path: string): Promise<Buffer | Uint8Array | null> {
|
||||
@@ -24,6 +24,7 @@ class Database extends DatabasePromise {
|
||||
io: ProtocolIo;
|
||||
worker: Worker | null;
|
||||
fsPath: string | null;
|
||||
guards: SyncEngineGuards;
|
||||
constructor(db: NativeDatabase, io: ProtocolIo, worker: Worker | null, runOpts: RunOpts, engine: any, fsPath: string | null, opts: DatabaseOpts = {}) {
|
||||
super(db, opts)
|
||||
this.io = io;
|
||||
@@ -31,18 +32,21 @@ class Database extends DatabasePromise {
|
||||
this.runOpts = runOpts;
|
||||
this.engine = engine;
|
||||
this.fsPath = fsPath;
|
||||
this.guards = new SyncEngineGuards();
|
||||
}
|
||||
async sync() {
|
||||
await run(this.runOpts, this.io, this.engine, this.engine.sync());
|
||||
await this.push();
|
||||
await this.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() {
|
||||
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() {
|
||||
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> {
|
||||
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,
|
||||
useTransform: opts.transform != null,
|
||||
tracing: opts.tracing,
|
||||
protocolVersion: 1
|
||||
protocolVersion: 1,
|
||||
longPollTimeoutMs: opts.longPollTimeoutMs
|
||||
});
|
||||
const runOpts: RunOpts = {
|
||||
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"
|
||||
|
||||
export { run, memoryIO, }
|
||||
export { run, memoryIO, SyncEngineGuards }
|
||||
export type { SyncOpts, ProtocolIo, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats }
|
||||
@@ -21,5 +21,8 @@
|
||||
"tsc-build": "npm exec tsc",
|
||||
"build": "npm run tsc-build",
|
||||
"test": "echo 'no tests'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tursodatabase/database-common": "^0.2.0-pre.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import { GeneratorResponse, ProtocolIo, RunOpts } from "./types.js";
|
||||
import { AsyncLock } from "@tursodatabase/database-common";
|
||||
|
||||
const GENERATOR_RESUME_IO = 0;
|
||||
const GENERATOR_RESUME_DONE = 1;
|
||||
@@ -114,6 +115,10 @@ export async function run(opts: RunOpts, io: ProtocolIo, engine: any, generator:
|
||||
if (type == 'SyncEngineStats') {
|
||||
return rest;
|
||||
}
|
||||
if (type == 'SyncEngineChanges') {
|
||||
//@ts-ignore
|
||||
return rest.changes;
|
||||
}
|
||||
for (let request = engine.protocolIo(); request != null; request = engine.protocolIo()) {
|
||||
tasks.push(trackPromise(process(opts, io, request)));
|
||||
}
|
||||
@@ -125,3 +130,66 @@ export async function run(opts: RunOpts, io: ProtocolIo, engine: any, generator:
|
||||
}
|
||||
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,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"module": "esnext",
|
||||
"module": "nodenext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "nodenext",
|
||||
"outDir": "dist/",
|
||||
"lib": [
|
||||
"es2020",
|
||||
|
||||
@@ -54,4 +54,4 @@ export interface SyncEngineStats {
|
||||
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. */
|
||||
ioLoopAsync(): Promise<void>
|
||||
protocolIo(): JsProtocolRequestBytes | null
|
||||
sync(): GeneratorHolder
|
||||
push(): GeneratorHolder
|
||||
stats(): GeneratorHolder
|
||||
pull(): GeneratorHolder
|
||||
wait(): GeneratorHolder
|
||||
apply(changes: SyncEngineChanges): GeneratorHolder
|
||||
checkpoint(): GeneratorHolder
|
||||
open(): Database
|
||||
close(): void
|
||||
}
|
||||
|
||||
export declare class SyncEngineChanges {
|
||||
|
||||
}
|
||||
|
||||
export declare const enum DatabaseChangeTypeJs {
|
||||
Insert = 0,
|
||||
Update = 1,
|
||||
@@ -217,6 +221,7 @@ export type GeneratorResponse =
|
||||
| { type: 'IO' }
|
||||
| { type: 'Done' }
|
||||
| { type: 'SyncEngineStats', operations: number, mainWal: number, revertWal: number, lastPullUnixTime: number, lastPushUnixTime?: number, revision?: string }
|
||||
| { type: 'SyncEngineChanges', changes: SyncEngineChanges }
|
||||
|
||||
export type JsProtocolRequest =
|
||||
| { 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`)
|
||||
}
|
||||
|
||||
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 { Opfs }
|
||||
export { OpfsFile }
|
||||
@@ -519,5 +519,6 @@ export { JsDataCompletion }
|
||||
export { JsProtocolIo }
|
||||
export { JsProtocolRequestBytes }
|
||||
export { SyncEngine }
|
||||
export { SyncEngineChanges }
|
||||
export { DatabaseChangeTypeJs }
|
||||
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 .",
|
||||
"tsc-build": "npm exec tsc",
|
||||
"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"
|
||||
},
|
||||
"napi": {
|
||||
|
||||
@@ -160,7 +160,7 @@ test('checkpoint', async () => {
|
||||
await db1.checkpoint();
|
||||
expect((await db1.stats()).mainWal).toBe(0);
|
||||
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++) {
|
||||
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 () => {
|
||||
{
|
||||
const db = await connect({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 { promises } from "node:fs";
|
||||
|
||||
@@ -43,23 +43,27 @@ class Database extends DatabasePromise {
|
||||
runOpts: RunOpts;
|
||||
engine: any;
|
||||
io: ProtocolIo;
|
||||
guards: SyncEngineGuards
|
||||
constructor(db: NativeDatabase, io: ProtocolIo, runOpts: RunOpts, engine: any, opts: DatabaseOpts = {}) {
|
||||
super(db, opts)
|
||||
this.runOpts = runOpts;
|
||||
this.engine = engine;
|
||||
this.io = io;
|
||||
this.guards = new SyncEngineGuards();
|
||||
}
|
||||
async sync() {
|
||||
await run(this.runOpts, this.io, this.engine, this.engine.sync());
|
||||
await this.push();
|
||||
await this.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() {
|
||||
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() {
|
||||
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> {
|
||||
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,
|
||||
useTransform: opts.transform != null,
|
||||
tracing: opts.tracing,
|
||||
longPollTimeoutMs: opts.longPollTimeoutMs,
|
||||
protocolVersion: 1,
|
||||
longPollTimeoutMs: opts.longPollTimeoutMs,
|
||||
});
|
||||
const runOpts: RunOpts = {
|
||||
url: opts.url,
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{
|
||||
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_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 {
|
||||
IO,
|
||||
Done,
|
||||
@@ -47,6 +52,9 @@ pub enum GeneratorResponse {
|
||||
last_push_unix_time: Option<i64>,
|
||||
revision: Option<String>,
|
||||
},
|
||||
SyncEngineChanges {
|
||||
changes: SyncEngineChanges,
|
||||
},
|
||||
}
|
||||
|
||||
#[napi]
|
||||
|
||||
@@ -19,7 +19,7 @@ use turso_sync_engine::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
generator::{GeneratorHolder, GeneratorResponse},
|
||||
generator::{GeneratorHolder, GeneratorResponse, SyncEngineChanges},
|
||||
js_protocol_io::{JsProtocolIo, JsProtocolRequestBytes},
|
||||
};
|
||||
|
||||
@@ -28,38 +28,6 @@ pub struct DatabaseOpts {
|
||||
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]
|
||||
pub struct SyncEngine {
|
||||
path: String,
|
||||
@@ -71,7 +39,7 @@ pub struct SyncEngine {
|
||||
use_transform: bool,
|
||||
io: Option<Arc<dyn turso_core::IO>>,
|
||||
protocol: Option<Arc<JsProtocolIo>>,
|
||||
sync_engine: Arc<SyncEngineGuard>,
|
||||
sync_engine: Arc<RwLock<Option<DatabaseSyncEngine<JsProtocolIo>>>>,
|
||||
opened: Arc<Mutex<Option<turso_node::Database>>>,
|
||||
}
|
||||
|
||||
@@ -214,13 +182,7 @@ impl SyncEngine {
|
||||
tables_ignore: opts.tables_ignore.unwrap_or_default(),
|
||||
use_transform: opts.use_transform,
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
sync_engine: Arc::new(SyncEngineGuard {
|
||||
inner: Arc::new(RwLock::new(None)),
|
||||
wait_lock: Mutex::new(()),
|
||||
push_lock: Mutex::new(()),
|
||||
pull_lock: Mutex::new(()),
|
||||
checkpoint_lock: Mutex::new(()),
|
||||
}),
|
||||
sync_engine: Arc::new(RwLock::new(None)),
|
||||
io: Some(io),
|
||||
protocol: Some(Arc::new(JsProtocolIo::default())),
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
@@ -257,7 +219,7 @@ impl SyncEngine {
|
||||
let connection = initialized.connect_rw(&coro).await?;
|
||||
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);
|
||||
Ok(())
|
||||
});
|
||||
@@ -288,22 +250,10 @@ impl SyncEngine {
|
||||
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]
|
||||
pub fn push(&self) -> GeneratorHolder {
|
||||
self.run(async move |coro, guard| {
|
||||
let _lock = guard.push_lock();
|
||||
let sync_engine = try_read(&guard.inner)?;
|
||||
let sync_engine = try_read(&guard)?;
|
||||
let sync_engine = try_unwrap(&sync_engine)?;
|
||||
sync_engine.push_changes_to_remote(coro).await?;
|
||||
Ok(None)
|
||||
@@ -313,7 +263,7 @@ impl SyncEngine {
|
||||
#[napi]
|
||||
pub fn stats(&self) -> GeneratorHolder {
|
||||
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 stats = sync_engine.stats(coro).await?;
|
||||
Ok(Some(GeneratorResponse::SyncEngineStats {
|
||||
@@ -328,16 +278,25 @@ impl SyncEngine {
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn pull(&self) -> GeneratorHolder {
|
||||
pub fn wait(&self) -> GeneratorHolder {
|
||||
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 changes = {
|
||||
let _lock = guard.wait_lock();
|
||||
sync_engine.wait_changes_from_remote(coro).await?
|
||||
};
|
||||
let _lock = guard.pull_lock();
|
||||
sync_engine.apply_changes_from_remote(coro, changes).await?;
|
||||
Ok(Some(GeneratorResponse::SyncEngineChanges {
|
||||
changes: SyncEngineChanges {
|
||||
status: Box::new(Some(sync_engine.wait_changes_from_remote(coro).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)
|
||||
})
|
||||
}
|
||||
@@ -345,8 +304,7 @@ impl SyncEngine {
|
||||
#[napi]
|
||||
pub fn checkpoint(&self) -> GeneratorHolder {
|
||||
self.run(async move |coro, guard| {
|
||||
let _lock = guard.checkpoint_lock();
|
||||
let sync_engine = try_read(&guard.inner)?;
|
||||
let sync_engine = try_read(&guard)?;
|
||||
let sync_engine = try_unwrap(&sync_engine)?;
|
||||
sync_engine.checkpoint(coro).await?;
|
||||
Ok(None)
|
||||
@@ -367,7 +325,7 @@ impl SyncEngine {
|
||||
|
||||
#[napi]
|
||||
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.io.take();
|
||||
let _ = self.protocol.take();
|
||||
@@ -396,7 +354,7 @@ impl SyncEngine {
|
||||
&self,
|
||||
f: impl AsyncFnOnce(
|
||||
&Coro<()>,
|
||||
&Arc<SyncEngineGuard>,
|
||||
&Arc<RwLock<Option<DatabaseSyncEngine<JsProtocolIo>>>>,
|
||||
) -> turso_sync_engine::Result<Option<GeneratorResponse>>
|
||||
+ 'static,
|
||||
) -> GeneratorHolder {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user