@yydb/yydb 0.0.18 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,10 +17,15 @@ For a wire client only (renderer or an app that already runs `yydb serve`), use
17
17
  | Import | Runtime | Role |
18
18
  |--------|---------|------|
19
19
  | `@yydb/yydb` | Node | `Database.open`, micro helpers, VOS re-exports |
20
- | `@yydb/yydb/cli` | Node | CLI (`version`, `init`, `info`, `serve`) |
20
+ | `@yydb/yydb/cli` | Node | CLI (`version`, `init`, `info`, `verify`, `serve`) |
21
21
 
22
22
  Node.js 18+.
23
23
 
24
+ ```bash
25
+ npm install @yydb/yydb
26
+ npx yydb version
27
+ ```
28
+
24
29
  Schema truth lives in the `.yydb` file via `ensureSchema` and VOS documents.
25
30
 
26
31
  ## Example
@@ -65,6 +70,21 @@ await db.close();
65
70
  `OpenOptions`: `cli` (explicit CLI script path), `port` (preferred loopback port), `serveArgs` (extra `yydb serve`
66
71
  arguments). `binary` is a deprecated alias for `cli`.
67
72
 
73
+ ### Prepared statements
74
+
75
+ `db.prepare` parses and lowers a VOS query once; the plan stays in a native thread-local registry and re-executes
76
+ with different bindings.
77
+
78
+ ```ts
79
+ const stmt = await db.prepare('User.all().take($limit).collect()');
80
+ const rows = await stmt.execute({ limit: 100 });
81
+ const more = await stmt.execute({ limit: 50 });
82
+ stmt.close();
83
+ ```
84
+
85
+ `stmt.parameters` lists the expected bindings, and `stmt.info` exposes the read/write sets and source fingerprint.
86
+ Missing, extra, or mistyped parameters raise `YydbError` with code `yydb.query.bind`.
87
+
68
88
  The native binding exposes additive operations (`schemaVersion`, `schemaDocument`, `recordCount`, `journalMode`,
69
89
  `checkpoint`, `walFrameCount`, `get`, `put`); the CLI composes commands from them.
70
90
 
@@ -73,7 +93,7 @@ The native binding exposes additive operations (`schemaVersion`, `schemaDocument
73
93
  | Need | Package |
74
94
  |------|---------|
75
95
  | Node embedded engine and CLI (this package) | **`@yydb/yydb`** |
76
- | Browser, pure TypeScript | **`@yydb/light-db`** |
96
+ | Browser engine (pure TS and WASM sessions) | **`@yydb/light-db`** |
77
97
  | Wire client only | [`@yydb/yydb-client`](https://www.npmjs.com/package/@yydb/yydb-client) |
78
98
  | In-process Rust embed | [`yydb`](https://crates.io/crates/yydb) |
79
99
  | Agent skills (wire protocol) | [`@yydb/yydb-skills`](https://www.npmjs.com/package/@yydb/yydb-skills) |
@@ -83,4 +103,4 @@ endpoint.
83
103
 
84
104
  The managed engine listens on `127.0.0.1` with no authentication — keep the endpoint private.
85
105
 
86
- [YYDB overview](https://github.com/yy-database/yydb.rs) · [User guides](https://github.com/yy-database/yydb.rs/tree/dev/projects/packages/homepage/documentation/zh-hans)
106
+ [YYDB overview](https://github.com/yy-database/yydb) · [User guides](https://github.com/yy-database/yydb/tree/dev/projects/packages/homepage/documentation/zh-hans)
@@ -1,6 +1,6 @@
1
1
  import { type EmittableItem } from '@voml/vos';
2
2
  import { defineMicro as buildMicro, type DefinedMicro, type MicroHandle } from '../shared/micro.js';
3
- import { loadNative } from '../native/binding.js';
3
+ import { loadNative, type NativeStatement as NativeStatementHandle } from '../native/binding.js';
4
4
  import type { UdfScalarDescriptor } from '../shared/udf-types.js';
5
5
  /** Published schema metadata. */
6
6
  export interface SchemaVersion {
@@ -75,6 +75,75 @@ export interface CompactReport {
75
75
  checkpointed: boolean;
76
76
  orphans_reclaimed: number;
77
77
  }
78
+ /** Declared type for a prepared statement parameter slot. */
79
+ export type SlotType = 'any' | 'bool' | 'i64' | 'text' | 'null';
80
+ /** One named parameter descriptor on a {@link Statement}. */
81
+ export interface ParameterDescriptor {
82
+ /** Canonical parameter name (no leading `$`). */
83
+ name: string;
84
+ /** Positional slot index within the bound-value slice (0-based). */
85
+ index: number;
86
+ /** Declared slot type; narrowed from surrounding context when possible. */
87
+ slotTy: SlotType;
88
+ /** Number of times this parameter appears in the source. */
89
+ usageCount: number;
90
+ }
91
+ /** Whether a prepared statement is a read pipeline or a write program. */
92
+ export type QueryKind = 'Read' | 'Write';
93
+ /** Metadata about a prepared statement — useful for logging and cache keys. */
94
+ export interface StatementInfo {
95
+ statementId: string;
96
+ queryKind: QueryKind;
97
+ parameters: ParameterDescriptor[];
98
+ readSet: string[];
99
+ writeSet: string[];
100
+ sourceFingerprint: string;
101
+ source: string;
102
+ }
103
+ /**
104
+ * A pre-parsed, pre-lowered VOS query plan.
105
+ *
106
+ * Created by {@link Database.prepare}. The actual lowered op tree lives on
107
+ * the native side in a thread-local registry keyed by `statementId`; this
108
+ * class is a thin JS handle. Bind parameters and re-execute via
109
+ * {@link Statement.execute} without re-parsing or re-lowering the source.
110
+ *
111
+ * ```ts
112
+ * const stmt = await db.prepare('User.all().take($limit).collect()');
113
+ * const rows = await stmt.execute({ limit: 100 });
114
+ * // re-execute with different bind
115
+ * const rows2 = await stmt.execute({ limit: 50 });
116
+ * // release when done
117
+ * stmt.close();
118
+ * ```
119
+ */
120
+ export declare class Statement {
121
+ private readonly native;
122
+ private readonly db;
123
+ private closed;
124
+ constructor(native: NativeStatementHandle, db: unknown);
125
+ /** The fingerprint-prefixed unique id for this statement. */
126
+ get statementId(): string;
127
+ /** Parameter descriptors — empty array when the statement takes no parameters. */
128
+ get parameters(): ParameterDescriptor[];
129
+ /** Full statement metadata. */
130
+ get info(): StatementInfo;
131
+ /** Whether this statement has been closed and can no longer execute. */
132
+ get isClosed(): boolean;
133
+ /**
134
+ * Execute this prepared statement with optional named parameter bindings.
135
+ *
136
+ * Missing parameters, extraneous parameters or mistyped parameters raise
137
+ * `YydbError` with code `yydb.query.bind`.
138
+ *
139
+ * @param params Named parameter values — keys match the parameter names
140
+ * in the VOS source (`$name` → `{ name: value }`). Omit when the statement
141
+ * takes no parameters.
142
+ */
143
+ execute<T = Record<string, unknown>>(params?: Record<string, unknown>): Promise<T[]>;
144
+ /** Release this statement's plan from the native registry. */
145
+ close(): void;
146
+ }
78
147
  /**
79
148
  * Transaction-local handle passed to {@link Database.transaction} callbacks.
80
149
  * All CRUD methods forward to the underlying native handle while the
@@ -160,6 +229,25 @@ export declare class Database {
160
229
  * ```
161
230
  */
162
231
  transaction<T>(fn: (tx: TransactionHandle) => Promise<T>): Promise<T>;
232
+ /**
233
+ * Prepare a VOS read pipeline into a reusable query plan.
234
+ *
235
+ * Returns a {@link Statement} handle. The actual lowered op tree lives
236
+ * on the native side in a thread-local registry — you can call
237
+ * `statement.execute({ paramName: value })` cheaply multiple times
238
+ * without re-parsing or re-lowering the source.
239
+ *
240
+ * Prepare requires no schema binding; plan building is a pure parse +
241
+ * lower pass. Execute still needs `ensureSchema` first.
242
+ *
243
+ * ```ts
244
+ * const stmt = await db.prepare('User.all().take($limit).collect()');
245
+ * const rows = await stmt.execute({ limit: 100 });
246
+ * const rows2 = await stmt.execute({ limit: 50 });
247
+ * stmt.close();
248
+ * ```
249
+ */
250
+ prepare(source: string): Promise<Statement>;
163
251
  /** Execute a VOS read pipeline and return typed rows. */
164
252
  query<T = Record<string, unknown>>(source: string): Promise<T[]>;
165
253
  /** Execute a VOS write program. */
@@ -4,6 +4,69 @@ import { emitSource, } from '@voml/vos';
4
4
  import { defineMicro as buildMicro, microFingerprint, udfWireKind, MicroSessionRegistry, } from '../shared/micro.js';
5
5
  import { loadNative } from '../native/binding.js';
6
6
  import { YydbError } from '../shared/errors.js';
7
+ /**
8
+ * A pre-parsed, pre-lowered VOS query plan.
9
+ *
10
+ * Created by {@link Database.prepare}. The actual lowered op tree lives on
11
+ * the native side in a thread-local registry keyed by `statementId`; this
12
+ * class is a thin JS handle. Bind parameters and re-execute via
13
+ * {@link Statement.execute} without re-parsing or re-lowering the source.
14
+ *
15
+ * ```ts
16
+ * const stmt = await db.prepare('User.all().take($limit).collect()');
17
+ * const rows = await stmt.execute({ limit: 100 });
18
+ * // re-execute with different bind
19
+ * const rows2 = await stmt.execute({ limit: 50 });
20
+ * // release when done
21
+ * stmt.close();
22
+ * ```
23
+ */
24
+ export class Statement {
25
+ native;
26
+ db;
27
+ closed = false;
28
+ constructor(native, db) {
29
+ this.native = native;
30
+ this.db = db;
31
+ }
32
+ /** The fingerprint-prefixed unique id for this statement. */
33
+ get statementId() { return this.native.statementId(); }
34
+ /** Parameter descriptors — empty array when the statement takes no parameters. */
35
+ get parameters() {
36
+ return JSON.parse(this.native.parametersJson());
37
+ }
38
+ /** Full statement metadata. */
39
+ get info() {
40
+ return JSON.parse(this.native.info());
41
+ }
42
+ /** Whether this statement has been closed and can no longer execute. */
43
+ get isClosed() { return this.closed; }
44
+ /**
45
+ * Execute this prepared statement with optional named parameter bindings.
46
+ *
47
+ * Missing parameters, extraneous parameters or mistyped parameters raise
48
+ * `YydbError` with code `yydb.query.bind`.
49
+ *
50
+ * @param params Named parameter values — keys match the parameter names
51
+ * in the VOS source (`$name` → `{ name: value }`). Omit when the statement
52
+ * takes no parameters.
53
+ */
54
+ async execute(params) {
55
+ if (this.closed) {
56
+ throw new YydbError('yydb.statement.closed', 'statement has been closed');
57
+ }
58
+ const paramsJson = params !== undefined && params !== null ? JSON.stringify(params) : null;
59
+ const rowsJson = this.db.queryPrepared(this.native, paramsJson);
60
+ return JSON.parse(rowsJson);
61
+ }
62
+ /** Release this statement's plan from the native registry. */
63
+ close() {
64
+ if (!this.closed) {
65
+ this.native.close();
66
+ this.closed = true;
67
+ }
68
+ }
69
+ }
7
70
  /**
8
71
  * Transaction-local handle passed to {@link Database.transaction} callbacks.
9
72
  * All CRUD methods forward to the underlying native handle while the
@@ -195,6 +258,28 @@ export class Database {
195
258
  throw YydbError.fromDiagnosticJson(err instanceof Error ? err.message : String(err)) ?? err;
196
259
  }
197
260
  }
261
+ /**
262
+ * Prepare a VOS read pipeline into a reusable query plan.
263
+ *
264
+ * Returns a {@link Statement} handle. The actual lowered op tree lives
265
+ * on the native side in a thread-local registry — you can call
266
+ * `statement.execute({ paramName: value })` cheaply multiple times
267
+ * without re-parsing or re-lowering the source.
268
+ *
269
+ * Prepare requires no schema binding; plan building is a pure parse +
270
+ * lower pass. Execute still needs `ensureSchema` first.
271
+ *
272
+ * ```ts
273
+ * const stmt = await db.prepare('User.all().take($limit).collect()');
274
+ * const rows = await stmt.execute({ limit: 100 });
275
+ * const rows2 = await stmt.execute({ limit: 50 });
276
+ * stmt.close();
277
+ * ```
278
+ */
279
+ async prepare(source) {
280
+ const nativeStmt = this.native.prepare(source);
281
+ return new Statement(nativeStmt, this.native);
282
+ }
198
283
  /** Execute a VOS read pipeline and return typed rows. */
199
284
  async query(source) {
200
285
  const rowsJson = this.native.queryVos(source);
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Database, type OpenOptions, type SchemaVersion } from './api/database.js';
1
+ export { Database, Statement, type OpenOptions, type SchemaVersion, type ParameterDescriptor, type QueryKind, type SlotType, type StatementInfo } from './api/database.js';
2
2
  export { YydbError, YydbErrorCodes, YydbClientErrorCodes, isYydbError } from './shared/errors.js';
3
3
  export type { YydbErrorCode, YydbErrorOptions } from './shared/errors.js';
4
4
  export { defineMicro, type DefinedMicro, type MicroHandle, type TsMicroDefinitionInput, MicroSessionRegistry } from './shared/micro.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Database } from './api/database.js';
1
+ export { Database, Statement } from './api/database.js';
2
2
  export { YydbError, YydbErrorCodes, YydbClientErrorCodes, isYydbError } from './shared/errors.js';
3
3
  export { defineMicro, MicroSessionRegistry } from './shared/micro.js';
4
4
  export { nativeBindingName, platformKey, resolveYydbBinary, resolveYydbCli } from './native/resolve.js';
@@ -36,6 +36,10 @@ export interface NativeDatabase {
36
36
  queryVos(source: string): string;
37
37
  /** Execute a VOS write program. */
38
38
  executeVosWrite(source: string): void;
39
+ /** Prepare a VOS read pipeline into a reusable plan; returns a native Statement handle. */
40
+ prepare(source: string): NativeStatement;
41
+ /** Execute a previously prepared statement with optional JSON parameters. */
42
+ queryPrepared(statement: NativeStatement, paramsJson?: string | null): string;
39
43
  /** Publish a new schema version, optionally with rename map. */
40
44
  migrateSchema(document: string, renamesJson?: string | null): void;
41
45
  /** Checkpoint + copy self-contained `.yydb` main file (no WAL sidecars). */
@@ -49,6 +53,17 @@ export interface NativeDatabase {
49
53
  registerMicro(name: string, version: number, args: string[], returns: string, hostId: number, functionId: string, handleVersion: number, fingerprint: Uint8Array): void;
50
54
  callScalar(name: string, version: number, argsJson: string): string;
51
55
  }
56
+ /** A prepared VOS query plan handle exposed by the native binding. */
57
+ export interface NativeStatement {
58
+ /** Fingerprint-prefixed unique id for this prepared statement. */
59
+ statementId(): string;
60
+ /** Parameter descriptors JSON — the `parameters` field from a `PreparedStatement`. */
61
+ parametersJson(): string;
62
+ /** Full statement metadata as JSON (statementId, queryKind, parameters, readSet, writeSet, sourceFingerprint, source). */
63
+ info(): string;
64
+ /** Release this statement's plan from the registry; returns true when actually removed. */
65
+ close(): boolean;
66
+ }
52
67
  /** One remote `yydb serve` handle exposed by the native binding. */
53
68
  export interface NativeClient {
54
69
  endpoint(): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yydb/yydb",
3
- "version": "0.0.18",
3
+ "version": "0.1.0",
4
4
  "description": "YYDB Node embedded engine and CLI",
5
5
  "license": "MPL-2.0",
6
6
  "type": "module",
@@ -49,7 +49,7 @@
49
49
  "dependencies": {
50
50
  "@vmz/commander": "^0.3.5",
51
51
  "@vmz/diagnostic": "^0.3.5",
52
- "@voml/vos": "^0.0.1"
52
+ "@voml/vos": "^0.0.5"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/node": "^20.10.0",
@@ -59,9 +59,9 @@
59
59
  "node": ">=18"
60
60
  },
61
61
  "optionalDependencies": {
62
- "@yydb/yydb-darwin-arm64": "0.0.18",
63
- "@yydb/yydb-darwin-x64": "0.0.18",
64
- "@yydb/yydb-linux-x64": "0.0.18",
65
- "@yydb/yydb-win32-x64": "0.0.18"
62
+ "@yydb/yydb-darwin-arm64": "0.1.0",
63
+ "@yydb/yydb-darwin-x64": "0.1.0",
64
+ "@yydb/yydb-linux-x64": "0.1.0",
65
+ "@yydb/yydb-win32-x64": "0.1.0"
66
66
  }
67
67
  }