Skip to main content

Raw SQL and Parameters

Raw()

Raw wraps a literal string that is emitted into the generated SQL verbatim — no escaping, no quoting, no validation. Use it for expressions the builder doesn't model (function calls, dialect-specific syntax, computed columns) anywhere an SQL element is accepted: columns, from(), where()/on() operands, orderBy(), table names, and more.

import { Raw, Select } from '@sqb/builder';

Select(Raw("'John''s Bike' f1")).from('table1');
// select 'John''s Bike' f1 from table1

Select().from('table1', Raw('func1()'));
// select * from table1,func1()

Select().from('table1').orderBy(Raw('LOWER(field1) desc'));
// select * from table1 order by LOWER(field1) desc

That last one needs Raw specifically because .orderBy()'s plain-string form only parses a bare [schema.][table.]field [asc|desc] shape — .orderBy('LOWER(field1)') throws a TypeError ("does not match order column format"). A plain column name doesn't need Raw at all: .orderBy('field1 desc') already works on its own.

Because Raw content is never escaped, never interpolate untrusted input into it directly — build the value with Param instead and let the target driver bind it safely.

Param()

Param represents an external bind parameter. It serializes to :name by default (dialect packages can override the placeholder syntax — ?, $1, @name, etc. — through a SerializerExtension).

import { Param, Select, Eq } from '@sqb/builder';

Select().from('customers').where(Eq('id', Param('id')));

Param is dual-callable and accepts either positional arguments or a single options object; both forms accept an optional dataType (a DataType member) and isArray flag:

Param('id');
Param('id', DataType.INTEGER);
Param('id', DataType.INTEGER, false);
Param({ name: 'id', dataType: DataType.INTEGER, isArray: false });

Supplying values

Bind values are resolved from generate({ params }), or from .values(obj) set directly on the query — both end up in result.params:

const query = Select().from('customers').where(Eq('id', Param('id')));

query.generate({ params: { id: 1 } });
// { sql: 'select * from customers where id = :id', params: { id: 1 }, ... }
Insert('customers', { id: Param('id'), name: Param('name') })
.values({ id: 1, name: 'Abc' })
.generate();
// sql: insert into customers (id, name) values (:id, :name)
// params: { id: 1, name: 'Abc' }

result.paramOptions mirrors each parameter's dataType/isArray, which database adapters use to bind values with the correct native type.

strictParams

Passing strictParams: true to .generate() converts every literal value used as the right-hand side of a comparison into an auto-generated Param (named P$_1, P$_2, ...), so the resulting SQL never contains inline literals:

Select().from('table1').where({ id: 1 }).generate({ strictParams: true });
// sql: select * from table1 where id = :P$_1
// params: { P$_1: 1 }

This is useful for drivers or caches that key on the SQL text and want literal values kept out of it entirely. See Generating SQL per dialect for the rest of the .generate() options.