Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(schema-engine-wasm): proof of concept #5096

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ members = [
"prisma-fmt",
"prisma-schema-wasm",
"psl/*",
"quaint",
"quaint", "schema-engine/schema-engine-wasm",
]

[workspace.dependencies]
Expand Down
2 changes: 1 addition & 1 deletion query-engine/connector-test-kit-rs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ To run tests through a driver adapters, you should also configure the following
Example:

```shell
export EXTERNAL_TEST_EXECUTOR="$WORKSPACE_ROOT/query-engine/driver-adapters/executor/script/testd.sh"
export EXTERNAL_TEST_EXECUTOR="$WORKSPACE_ROOT/query-engine/driver-adapters/executor/script/testd-qe.sh"
export DRIVER_ADAPTER=neon
export ENGINE=wasm
export DRIVER_ADAPTER_CONFIG ='{ "proxyUrl": "127.0.0.1:5488/v1" }'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ impl TestConfig {
}

pub fn external_test_executor_path(&self) -> Option<String> {
const DEFAULT_TEST_EXECUTOR: &str = "query-engine/driver-adapters/executor/script/testd.sh";
const DEFAULT_TEST_EXECUTOR: &str = "query-engine/driver-adapters/executor/script/testd-qe.sh";
self.with_driver_adapter()
.and_then(|_| {
Self::workspace_root().or_else(|| {
Expand Down
10 changes: 7 additions & 3 deletions query-engine/driver-adapters/executor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@
"description": "",
"private": true,
"scripts": {
"build": "tsup ./src/testd.ts ./src/bench.ts --format esm --dts",
"test": "node --import tsx ./src/testd.ts",
"build": "tsup ./src/testd-qe.ts ./src/testd-se.ts ./src/bench.ts --format esm --dts",
"test:qe": "node --import tsx ./src/testd-qe.ts",
"test:se": "node --import tsx ./src/testd-se.ts",
"clean:d1": "rm -rf ../../connector-test-kit-rs/query-engine-tests/.wrangler"
},
"tsup": {
"external": [
"../../../query-engine-wasm/pkg/postgresql/query_engine_bg.js",
"../../../query-engine-wasm/pkg/mysql/query_engine_bg.js",
"../../../query-engine-wasm/pkg/sqlite/query_engine_bg.js"
"../../../query-engine-wasm/pkg/sqlite/query_engine_bg.js",
"../../../schema-engine-wasm/pkg/postgresql/schema_engine_bg.js",
"../../../schema-engine-wasm/pkg/mysql/schema_engine_bg.js",
"../../../schema-engine-wasm/pkg/sqlite/schema_engine_bg.js"
]
},
"keywords": [],
Expand Down
2 changes: 2 additions & 0 deletions query-engine/driver-adapters/executor/script/testd-qe.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
node "$(dirname "${BASH_SOURCE[0]}")/../dist/testd-qe.mjs"
2 changes: 2 additions & 0 deletions query-engine/driver-adapters/executor/script/testd-se.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
node "$(dirname "${BASH_SOURCE[0]}")/../dist/testd-qe.mjs"
2 changes: 0 additions & 2 deletions query-engine/driver-adapters/executor/script/testd.sh

This file was deleted.

2 changes: 1 addition & 1 deletion query-engine/driver-adapters/executor/src/bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as fs from "node:fs/promises";
import path from "node:path";
import { __dirname } from './utils'

import * as qe from "./qe";
import * as qe from "./query-engine";

import { pg } from "@prisma/bundled-js-drivers";
import * as prismaPg from "@prisma/adapter-pg";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as wasmMysql from '../../../query-engine-wasm/pkg/mysql/query_engine_bg
import * as wasmSqlite from '../../../query-engine-wasm/pkg/sqlite/query_engine_bg.js'
import fs from 'node:fs/promises'
import path from 'node:path'
import { __dirname } from './utils'
import { __dirname } from './utils.js'

const wasm = {
postgres: wasmPostgres,
Expand All @@ -15,7 +15,7 @@ type EngineName = keyof typeof wasm

const initializedModules = new Set<EngineName>()

export async function getEngineForProvider(provider: EngineName) {
export async function getQueryEngineForProvider(provider: EngineName) {
const engine = wasm[provider]
if (!initializedModules.has(provider)) {
const subDir = provider === 'postgres' ? 'postgresql' : provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export async function initQueryEngine(
const options = queryEngineOptions(datamodel);

if (engineType === "Wasm") {
const { getEngineForProvider } = await import("./wasm");
const { getQueryEngineForProvider: getEngineForProvider } = await import("./query-engine-wasm");
const WasmQueryEngine = await getEngineForProvider(adapter.provider)
return new WasmQueryEngine(options, logCallback, adapter);
} else {
Expand Down
30 changes: 30 additions & 0 deletions query-engine/driver-adapters/executor/src/schema-engine-wasm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as wasmPostgres from '../../../../schema-engine/schema-engine-wasm/pkg/postgresql/schema_engine_bg.js'
import * as wasmMysql from "../../../../schema-engine/schema-engine-wasm/pkg/mysql/schema_engine_bg.js";
import * as wasmSqlite from "../../../../schema-engine/schema-engine-wasm/pkg/sqlite/schema_engine_bg.js";
import fs from 'node:fs/promises'
import path from 'node:path'
import { __dirname } from './utils.js'

const wasm = {
postgres: wasmPostgres,
mysql: wasmMysql,
sqlite: wasmSqlite
}

type EngineName = keyof typeof wasm

const initializedModules = new Set<EngineName>()

export async function getSchemaEngineForProvider(provider: EngineName) {
const engine = wasm[provider]
if (!initializedModules.has(provider)) {
const subDir = provider === 'postgres' ? 'postgresql' : provider
const bytes = await fs.readFile(path.resolve(__dirname, '..', '..', '..', 'schema-engine-wasm', 'pkg', subDir, 'schema_engine_bg.wasm'))
const module = new WebAssembly.Module(bytes)
const instance = new WebAssembly.Instance(module, { './schema_engine_bg.js': engine })
engine.__wbg_set_wasm(instance.exports);
initializedModules.add(provider)
}

return engine.SchemaEngine
}
23 changes: 23 additions & 0 deletions query-engine/driver-adapters/executor/src/schema-engine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { DriverAdapter } from "@prisma/driver-adapter-utils";
import { __dirname } from './utils'

export interface SchemaEngine {
connect(trace: string, requestId: string): Promise<void>;
disconnect(trace: string, requestId: string): Promise<void>;
query(body: string, trace: string, tx_id: string | undefined, requestId: string): Promise<string>;
startTransaction(input: string, trace: string, requestId: string): Promise<string>;
commitTransaction(tx_id: string, trace: string, requestId: string): Promise<string>;
rollbackTransaction(tx_id: string, trace: string, requestId: string): Promise<string>;
}

export type QueryLogCallback = (log: string) => void;

export async function initSchemaEngine(
adapter: DriverAdapter,
datamodel: string,
debug: (...args: any[]) => void
): Promise<SchemaEngine> {
const { getSchemaEngineForProvider: getEngineForProvider } = await import("./schema-engine-wasm");
const WasmQueryEngine = await getEngineForProvider(adapter.provider)
return new WasmQueryEngine(adapter);
}
33 changes: 33 additions & 0 deletions query-engine/driver-adapters/executor/src/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { match } from 'ts-pattern';
import { type DriverAdaptersManager } from './driver-adapters-manager';
import type { Env } from './types';
import { PgManager } from "./driver-adapters-manager/pg";
import { NeonWsManager } from "./driver-adapters-manager/neon.ws";
import { LibSQLManager } from "./driver-adapters-manager/libsql";
import { PlanetScaleManager } from "./driver-adapters-manager/planetscale";
import { D1Manager } from "./driver-adapters-manager/d1";

export async function setupDriverAdaptersManager(
env: Env,
migrationScript?: string
): Promise<DriverAdaptersManager> {
return match(env)
.with({ DRIVER_ADAPTER: "pg" }, async (env) => await PgManager.setup(env))
.with(
{ DRIVER_ADAPTER: "neon:ws" },
async (env) => await NeonWsManager.setup(env)
)
.with(
{ DRIVER_ADAPTER: "libsql" },
async (env) => await LibSQLManager.setup(env)
)
.with(
{ DRIVER_ADAPTER: "planetscale" },
async (env) => await PlanetScaleManager.setup(env)
)
.with(
{ DRIVER_ADAPTER: "d1" },
async (env) => await D1Manager.setup(env, migrationScript)
)
.exhaustive();
}
Original file line number Diff line number Diff line change
@@ -1,65 +1,17 @@
import * as readline from "node:readline";
import { match } from "ts-pattern";
import * as S from "@effect/schema/Schema";
import {
bindAdapter,
ErrorCapturingDriverAdapter,
} from "@prisma/driver-adapter-utils";
import { webcrypto } from "node:crypto";

import type { DriverAdaptersManager } from "./driver-adapters-manager";
import { jsonRpc, Env } from "./types";
import * as qe from "./qe";
import { PgManager } from "./driver-adapters-manager/pg";
import { NeonWsManager } from "./driver-adapters-manager/neon.ws";
import { LibSQLManager } from "./driver-adapters-manager/libsql";
import { PlanetScaleManager } from "./driver-adapters-manager/planetscale";
import { D1Manager } from "./driver-adapters-manager/d1";
import * as qe from "./query-engine";
import { nextRequestId } from "./requestId";
import { createRNEngineConnector } from "./rn";

if (!global.crypto) {
global.crypto = webcrypto as Crypto;
}

async function initialiseDriverAdapterManager(
env: Env,
migrationScript?: string
): Promise<DriverAdaptersManager> {
return match(env)
.with({ DRIVER_ADAPTER: "pg" }, async (env) => await PgManager.setup(env))
.with(
{ DRIVER_ADAPTER: "neon:ws" },
async (env) => await NeonWsManager.setup(env)
)
.with(
{ DRIVER_ADAPTER: "libsql" },
async (env) => await LibSQLManager.setup(env)
)
.with(
{ DRIVER_ADAPTER: "planetscale" },
async (env) => await PlanetScaleManager.setup(env)
)
.with(
{ DRIVER_ADAPTER: "d1" },
async (env) => await D1Manager.setup(env, migrationScript)
)
.exhaustive();
}

// conditional debug logging based on LOG_LEVEL env var
const debug = (() => {
if ((process.env.LOG_LEVEL ?? "").toLowerCase() != "debug") {
return (...args: any[]) => {};
}

return (...args: any[]) => {
console.error("[nodejs] DEBUG:", ...args);
};
})();

// error logger
const err = (...args: any[]) => console.error("[nodejs] ERROR:", ...args);
import { debug, err } from "./utils";
import { setupDriverAdaptersManager } from "./setup";

async function main(): Promise<void> {
const env = S.decodeUnknownSync(Env)(process.env);
Expand Down Expand Up @@ -116,7 +68,7 @@ async function handleRequest(
logs.push(log);
};

const driverAdapterManager = await initialiseDriverAdapterManager(
const driverAdapterManager = await setupDriverAdaptersManager(
env,
migrationScript
);
Expand Down
Loading
Loading