Initial Commit
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# query-helpers
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`query-helpers` holds the small, stateless utility functions shared by every public method on `SurrealAdapter` and its sibling CRUD/transaction modules: positional-parameter conversion, error normalisation, and result-shape flattening.
|
||||
|
||||
Centralising these helpers keeps `adapter.ts` focused on the `DatabaseAdapter` lifecycle (connect/disconnect/state) and lets the CRUD and transaction modules each consume the same battle-tested implementations without duplication.
|
||||
|
||||
## Features
|
||||
|
||||
- `paramsToRecord(params?)` — turn `readonly unknown[]` into `{ p0, p1, ... }` (or `undefined` for empty input)
|
||||
- `wrapQueryError(err, sql)` — coerce arbitrary thrown values into structured `SurrealError(QUERY_FAILED)` with cause preservation
|
||||
- `flattenRows<T>(results)` — flatten the surrealdb.js `[[row, ...]]` nested shape into `T[]`
|
||||
- All helpers are pure, allocation-free on the empty-input fast paths, and free of any client/IO coupling
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
paramsToRecord,
|
||||
wrapQueryError,
|
||||
flattenRows,
|
||||
} from "@suaveplan/surrealdb/adapter/query-helpers";
|
||||
|
||||
const vars = paramsToRecord(["alice", 42]);
|
||||
// vars === { p0: "alice", p1: 42 }
|
||||
|
||||
try {
|
||||
// ...driver call...
|
||||
} catch (err) {
|
||||
throw wrapQueryError(err, "SELECT * FROM user");
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
flattenRows,
|
||||
wrapQueryError,
|
||||
} from "@suaveplan/surrealdb/adapter/query-helpers";
|
||||
|
||||
async function safeQuery<T>(
|
||||
client: { query<U>(sql: string): Promise<U[]> },
|
||||
sql: string
|
||||
): Promise<T[]> {
|
||||
try {
|
||||
const results = await client.query<T>(sql);
|
||||
return flattenRows<T>(results);
|
||||
} catch (err) {
|
||||
throw wrapQueryError(err, sql);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `paramsToRecord(params?: readonly unknown[]): Record<string, unknown> | undefined`
|
||||
|
||||
Returns `undefined` when `params` is missing or empty. Otherwise returns a fresh record keyed `p0`, `p1`, ... in order.
|
||||
|
||||
### `wrapQueryError(err: unknown, sql: string): SurrealError`
|
||||
|
||||
Returns `err` unchanged when it is already a `SurrealError`. Otherwise wraps it as `SurrealError(SURREAL.QUERY_FAILED, "Query failed [<sql>]: <message>", { cause })` where `cause` is preserved only for `Error` instances.
|
||||
|
||||
### `flattenRows<T>(results: unknown): T[]`
|
||||
|
||||
If `results` is `[[...]]` returns the inner array. If `results` is `[T, ...]` returns it as-is. For empty or non-array inputs returns `[]`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- `paramsToRecord` allocates a fresh object on every call to keep callers safe from accidental mutation; the empty-input branch avoids the allocation entirely.
|
||||
- `wrapQueryError` mirrors the original behaviour from `SurrealAdapter._wrapQueryError` — it must NOT swallow `SurrealError` subclasses, since callers rely on the code discriminator surviving the `await` boundary.
|
||||
- `flattenRows` accepts `unknown` so call-sites can pass the raw driver return value without an upfront cast; the structural test exhausts both observed shapes (single-statement and multi-statement query responses).
|
||||
- These functions are deliberately leaf utilities: they import only `../../errors/index.js`, never the driver or adapter. That keeps the dependency graph acyclic when the CRUD and transaction modules depend on them.
|
||||
Reference in New Issue
Block a user