first commit
This commit is contained in:
68
docs/persistence/database/db-sqlite/src/unsafe/unsafe.md
Normal file
68
docs/persistence/database/db-sqlite/src/unsafe/unsafe.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# unsafe
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `unsafe` subpath exports `rawQuery` — a direct SQL execution function that bypasses the Drizzle ORM layer entirely. It is intentionally segregated behind the `@suaveplan/db-sqlite/unsafe` subpath import to make its use explicit and auditable: any import of this path stands out in code review as a deliberate bypass of the normal query builder.
|
||||
|
||||
**Security warning:** `rawQuery` provides no SQL injection protection. Never pass user-supplied or externally-sourced strings as the `sql` argument. Use only for migration scripts, low-level tooling, or read-only administrative queries where the SQL is fully under developer control.
|
||||
|
||||
## Features
|
||||
|
||||
- `rawQuery<T>(db, sql, params?)` — executes a prepared statement on any `bun:sqlite`-compatible Database instance
|
||||
- Returns rows typed as `T[]` (caller asserts the row shape)
|
||||
- Maps execution errors to `SqliteError(SQLITE.QUERY_FAILED)`
|
||||
- Supports parameterised queries via the `params` array — always use `?` placeholders and pass values in `params` rather than string-interpolating them
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { rawQuery } from "@suaveplan/db-sqlite/unsafe";
|
||||
|
||||
const rows = await rawQuery<{ count: number }>(
|
||||
sqlite,
|
||||
"SELECT count(*) AS count FROM sqlite_master WHERE type = ?",
|
||||
["table"]
|
||||
);
|
||||
console.log(rows[0]?.count);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { rawQuery } from "@suaveplan/db-sqlite/unsafe";
|
||||
|
||||
// Used in a migration helper to read schema state before Drizzle is set up
|
||||
async function tableExists(sqlite: unknown, name: string): Promise<boolean> {
|
||||
const rows = await rawQuery<{ found: number }>(
|
||||
sqlite,
|
||||
"SELECT 1 AS found FROM sqlite_master WHERE type = 'table' AND name = ?",
|
||||
[name]
|
||||
);
|
||||
return rows.length > 0;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `rawQuery<T>(db, sql, params?): Promise<T[]>`
|
||||
|
||||
Executes `sql` as a prepared statement on `db`. Throws `SqliteError(SQLITE.QUERY_FAILED)` on error.
|
||||
|
||||
**Parameters**
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `db` | `any` | A `bun:sqlite` Database instance |
|
||||
| `sql` | `string` | The SQL to execute — must not contain user input |
|
||||
| `params` | `unknown[]` | Bind parameters for `?` placeholders |
|
||||
|
||||
**Returns** `Promise<T[]>` — rows shaped as `T`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`rawQuery` uses `db.prepare(sql).all(params)` rather than `db.query(sql).all(params)` to be consistent with the caching strategy used by `SqliteAdapter`. The `params` spread form (`stmt.all(...params)`) passes each parameter as a positional argument, matching `bun:sqlite`'s expected calling convention.
|
||||
|
||||
The `db` parameter is typed as `any` to accept both `bun:sqlite Database` instances and test doubles without requiring a concrete import of `bun:sqlite` types from this module.
|
||||
Reference in New Issue
Block a user