Handlers

Raw SQL safely

Use sdk.sql for parameterized queries — and understand why sdk.query is walled off.

Sometimes you need SQL the CRUD layer cannot express. There is a safe way to write it and an unsafe way, and the unsafe way will not save.

Use sdk.sql

sdk.sql is a tagged template that parameterizes every interpolated value automatically:

const rows = await sdk.sql`
  SELECT uid, subject, created_at
    FROM tickets
   WHERE status = ${status}
     AND created_at >= ${since}
   ORDER BY created_at DESC
   LIMIT ${limit}
`;

Everything in ${…} becomes a bound parameter. It is not possible to accidentally concatenate a value into the statement, because the template literal never produces one.

Raw SQL runs inside the database, on the rows as stored, so it may join and filter on id at full speed. What the handler returns is a different matter: a client names rows by uid, never by id, so select uid (and a referenced row's uid, through a join) for anything that leaves.

Why sdk.query is walled off

sdk.query(sql, params) exists for cases a template cannot express — a dynamically chosen table name, a generated IN list. It requires the sdk:query capability, and beyond that, a handler that interpolates a value into a sdk.query string will not save. The check happens at authoring time, not at runtime.

// Rejected at save — the string is built from a variable.
await sdk.query(`SELECT * FROM tickets WHERE status = '${status}'`);

// Fine — the value is a bound parameter.
await sdk.query("SELECT * FROM tickets WHERE status = ?", [status]);

Injection and scope are different problems

Parameterizing protects you from injection. It does not widen or narrow which rows you can see — that is decided by the caller's policies, before your SQL runs. A parameterized query is still a scoped query.

Schema changes

DDL — CREATE, ALTER, DROP — needs sdk:query_ddl, which is separate from and implies sdk:query. Changing shape at runtime is rarely the right answer; prefer the console's table editor, which handles foreign-key ordering atomically.

Next

On this page