Skip to main content

Executing Queries

Both SqbClient and SqbConnection expose an execute() method with the same signature:

execute(query: string | Query, options?: QueryExecuteOptions): Promise<QueryResult>;

query is either a raw SQL string or a Query object built with @sqb/builder (Select(), Insert(), Update(), Delete(), ...).

client.execute() vs connection.execute()

// SqbClient.execute(): acquires a connection, runs the query, releases the connection.
const result = await client.execute('select * from customers where id = $1', {
params: [1],
});
// SqbConnection.execute(): runs on a connection you already hold.
await client.acquire(async connection => {
const result = await connection.execute('select * from customers where id = $1', {
params: [1],
});
});

client.execute() is a convenience wrapper: it calls client.acquire() internally, runs your query on the freshly acquired connection, and releases that connection in a finally block — unless the result carries an open Cursor, in which case the connection is instead retain()-ed and only released once the cursor is closed. Use connection.execute() directly when you need multiple statements to share one connection (e.g. inside a transaction).

Queries on a given connection are also serialized through an internal task queue, so calling execute() multiple times concurrently on the same SqbConnection runs them one after another rather than interleaved.

QueryExecuteOptions

interface QueryExecuteOptions {
params?: Record<string, any> | any[];
autoCommit?: boolean;
cursor?: boolean;
transform?: ValueTransformFunction;
fetchRows?: number;
ignoreNulls?: boolean;
namingStrategy?: FieldNaming;
objectRows?: boolean;
showSql?: boolean;
prettyPrint?: boolean;
action?: string;
fetchAsString?: DataType[];
}

Any option you don't pass falls back to the matching field on ClientDefaults (config.defaults from SqbClient's constructor), and if that's also unset, to a hard-coded runtime default. The table below documents the actual runtime defaults, verified directly against the _prepareQueryRequest() method in sqb-connection.ts — several of these differ from what the inline // Default = ... comments in the source say, so trust this table over the JSDoc:

OptionResolved viaRuntime defaultNotes
autoCommitoptions.autoCommit → connection's ConnectionOptions.autoCommitdefaults.autoCommittruetrueOnly applies when the connection isn't already inside a transaction — if connection.inTransaction is true, autoCommit is forced to false regardless of what you pass. The JSDoc on ConnectionOptions.autoCommit / QueryExecuteOptions.autoCommit says "Default = false" — that is incorrect; outside a transaction, a query auto-commits unless you explicitly pass autoCommit: false.
cursoroptions.cursordefaults.cursorfalsefalseSee Cursors & Streaming.
objectRowsoptions.objectRowsdefaults.objectRowstruetrueRows are returned as plain objects (keyed by field name) unless you opt into array rows. The JSDoc says "Default = driver default" — in the actual code it's hard-coded to true, independent of the adapter.
ignoreNullsoptions.ignoreNullsdefaults.ignoreNullsfalsefalseAlso forced back to false whenever the effective objectRows is falseignoreNulls only ever applies to object rows.
fetchRowsoptions.fetchRowsdefaults.fetchRows100100In regular (non-cursor) mode, the maximum number of rows fetched. In cursor mode, the prefetch batch size (see Cursors & Streaming). Both ClientDefaults.fetchRows and QueryExecuteOptions.fetchRows carry a stale // Default = 10 comment in the source — the actual fallback coded in _prepareQueryRequest() is 100.
namingStrategyoptions.namingStrategydefaults.fieldNamingundefinednone (original names)See FieldNaming.
transformoptions.transformdefaults.transformundefinednoneSee below.
showSqloptions.showSqldefaults.showSqlfalsefalseWhen true, QueryResult.query is populated with the executed QueryRequest (SQL + params).
prettyPrintoptions.prettyPrintdefaults.prettyPrintfalsefalsePassed through to the SQL generator when the query is a Query builder object.
paramsnonePositional array or named-parameter object, forwarded to the query generator (for Query objects) or the driver (for raw SQL).
action''Free-form label attached to the request, mainly useful for logging/hooks.
fetchAsStringnoneList of DataTypes the adapter should coerce to string instead of native type.

objectRows and row shape

With the default objectRows: true, rows come back as Record<string, any> keyed by field name (after namingStrategy is applied). With objectRows: false, rows come back as arrays, positioned by QueryResult.fields' index.

Field naming

namingStrategy accepts a FieldNaming value — 'original' | 'lowercase' | 'uppercase' | 'camelcase' | 'pascalcase', or a (fieldName: string) => string | undefined function. It renames both the keys on object rows and the name field on each FieldInfo in QueryResult.fields. Returning undefined from a custom function drops that field from object rows entirely.

transform

type ValueTransformFunction = (value: any, fieldInfo?: FieldInfo) => any;

Runs over every field value as rows are normalized, letting you convert/mask driver values before they reach your code (e.g. converting a driver-specific date type to a plain Date).

Reading the result: QueryResult

interface QueryResult {
executeTime: number;
fields?: FieldInfoMap;
rows?: any;
rowType?: 'array' | 'object';
query?: QueryRequest; // only populated when showSql: true
returns?: any;
rowsAffected?: number;
cursor?: Cursor; // only populated when cursor: true
}
  • executeTime — milliseconds the query took, measured around the adapter call.
  • fields / rowType / rows — populated for statements that return rows (accessing result.fields.get('columnName') gives you a FieldInfo).
  • rowsAffected — populated for statements that report an affected-row count (e.g. UPDATE, DELETE).
  • cursor — populated instead of rows when cursor: true was requested — see Cursors & Streaming.

Example: raw SQL with parameters

const result = await client.execute(
'select id, name from customers where active = $1',
{ params: [true], fetchRows: 500 },
);
console.log(result.rows);

Next steps