UNPKG

chanfana

Version:

OpenAPI 3 and 3.1 schema generator and validator for Hono, itty-router and more!

63 lines (52 loc) 2.15 kB
import { ReadEndpoint } from "../read"; import type { ListFilters, Logger, O } from "../types"; import { buildPrimaryKeyFilters, buildWhereClause, getD1Binding, validateTableName } from "./base"; /** * D1-specific ReadEndpoint implementation. * Provides automatic SELECT operations with SQL injection prevention. */ export class D1ReadEndpoint<HandleArgs extends Array<object> = Array<object>> extends ReadEndpoint<HandleArgs> { /** Name of the D1 database binding in the worker environment. Defaults to "DB" */ dbName = "DB"; /** Optional logger for debugging and error tracking */ logger?: Logger; /** * Gets the D1 database binding from the worker environment. * @returns D1Database instance * @throws ApiException if binding is not defined or is not a D1 binding */ getDBBinding(): D1Database { return getD1Binding((args) => this.params.router.getBindings(args), this.args, this.dbName); } /** * Gets the list of valid column names from the model schema. * @returns Array of valid column names */ protected getValidColumns(): string[] { return Object.keys(this.meta.model.schema.shape); } /** * Fetches a single record from the database. * @param filters - Filter conditions for the query * @returns The found record or null if not found */ async fetch(filters: ListFilters): Promise<O<typeof this._meta> | null> { const tableName = validateTableName(this.meta.model.tableName); const validColumns = this.getValidColumns(); // Build safe filters restricted to primary key columns const safeFilters = buildPrimaryKeyFilters(filters, this._meta.model.primaryKeys, validColumns); const whereClause = buildWhereClause(safeFilters.conditions); const sql = `SELECT * FROM ${tableName} ${whereClause} LIMIT 1`; if (this.logger) { this.logger.debug?.(`[D1ReadEndpoint] SQL: ${sql}`); } const obj = await this.getDBBinding() .prepare(sql) .bind(...safeFilters.conditionsParams) .all(); if (!obj.results || obj.results.length === 0) { return null; } return obj.results[0] as O<typeof this._meta>; } }