Skip to content

sqlite: getRow(), parameterized query types/docs, fix interface method_call alloc#96

Merged
cs01 merged 2 commits intomainfrom
sqlite-improvements
Mar 6, 2026
Merged

sqlite: getRow(), parameterized query types/docs, fix interface method_call alloc#96
cs01 merged 2 commits intomainfrom
sqlite-improvements

Conversation

@cs01
Copy link
Owner

@cs01 cs01 commented Mar 5, 2026

sqlite: getRow(), parameterized query types/docs, fix interface method_call alloc

What changed

New API: sqlite.getRow<T>(db, sql, params?)

Returns the first matching row as a typed struct, or null if no row found. Fills the gap between sqlite.get() (string, single-row) and sqlite.query() (array, multi-row):

interface User { id: string; name: string; age: string; }

const alice: User = sqlite.getRow<User>(db,
  "SELECT id, name, age FROM users WHERE name = ?", ["Alice"]);
if (alice === null) { /* not found */ }
console.log(alice.name); // "Alice"

Parameterized queries now visible in type definitions

chadscript.d.ts was missing the optional params? arg on exec, get, and all, and sqlite.query<T>() wasn't declared at all — even though both had been implemented. Fixed:

declare namespace sqlite {
  function exec(db: any, sql: string, params?: any[]): void;
  function get(db: any, sql: string, params?: any[]): string;
  function getRow<T = any>(db: any, sql: string, params?: any[]): T;
  function all(db: any, sql: string, params?: any[]): string[];
  function query<T = any>(db: any, sql: string, params?: any[]): T[];
  function close(db: any): void;
}

Bug fix: getDeclaredInterfaceType rejects method_call RHS

interface-allocator.ts had a guard that only allowed variable or object as RHS types when resolving const x: SomeInterface = <expr>. This blocked method_call expressions (like sqlite.getRow(), or any user function returning an interface) from being tracked as typed interface variables. Field access on the result (alice.name) would fall back to treating the pointer as a raw string.

Fix: also allow method_call in the guard. The subsequent getInterface(declaredType) check ensures only known interfaces are matched.

This is a general fix — any pattern const x: MyInterface = someMethod() now correctly tracks x as MyInterface and generates proper GEP field accesses.

Docs: docs/stdlib/sqlite.md rewritten

  • Documents all 6 functions (open, exec, get, getRow, all, query, close)
  • Shows parameterized query examples for each
  • Adds SQL injection safety section
  • Replaces the "use .split('|')" tip with sqlite.query() / sqlite.getRow() guidance

examples/query.ts updated

Uses sqlite.query<User>() and sqlite.getRow<User>() instead of sqlite.all() with pipe-delimited output.

Test coverage

  • tests/fixtures/builtins/sqlite-get-row.ts — new fixture covering:

    • getRow with params (found row, typed field access)
    • getRow returning null (no match)
    • getRow without params
  • Existing sqlite-test.ts and sqlite-query.ts continue to pass

Notes

  • sqlite.get() and sqlite.all() pipe-delimited behavior is unchanged (backwards compatible)
  • getRow requires explicit type annotation (const x: MyInterface = sqlite.getRow(...)) for field access to work — the generic type param alone isn't enough since ChadScript uses type erasure

@cs01 cs01 changed the title sqlite: add getRow(), parameterized query types/docs, fix interface m… sqlite: getRow(), parameterized query types/docs, fix interface method_call alloc Mar 5, 2026
@cs01 cs01 merged commit bee4adc into main Mar 6, 2026
12 checks passed
@cs01 cs01 deleted the sqlite-improvements branch March 6, 2026 01:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant