• Start

Languages

/

JavaScript

/

Concepts

Utilities

SQON provides value comparison, conversion, and escaping utilities. The SDK adds query-building helpers on top.

Helpers are split across two packages. @surrealdb/sqon covers value comparison, conversion, and escaping. The surrealdb driver adds query-building tools for parameterised SurrealQL. Import from surrealdb when you use the driver and want both layers in one place.

// SQON (either package)
import { equals, jsonify, escapeIdent } from '@surrealdb/sqon';

// SDK only
import { surql, expr, BoundQuery, s, d, r, u } from 'surrealdb';

These live in @surrealdb/sqon alongside the value types. You do not need the database client to use them.

UtilityDescription
equals(a, b) Deep equality comparison for all value types
jsonify(value) Converts value types to JSON-safe string representations
escapeIdent(name) Escapes table and field names for use in SurrealQL
escapeKey(key) Escapes object keys for use in queries
escapeRid(value) Escapes record ID components
escapeValue(value) Escapes arbitrary values for embedding in queries
toSurqlString(value) Converts a value tree to a SurrealQL string representation

=== compares object references, so two RecordId instances with the same table and ID still fail an identity check. equals() walks the structure instead, including nested objects, arrays, SurrealDB value classes, Date, RegExp, and mixed bigint/number values.

import { equals, RecordId } from '@surrealdb/sqon';

const id1 = new RecordId('users', 'john');
const id2 = new RecordId('users', 'john');

console.log(id1 === id2); // false (different references)
console.log(equals(id1, id2)); // true (same value)

Handy when you want to know whether a fetched record changed between two reads:

const user1 = await db.select(userId);
const user2 = await db.select(userId);

if (!equals(user1, user2)) {
console.log('Record was modified');
}

jsonify() turns SurrealDB value classes in a result into the JSON string forms SurrealDB would use. Plain numbers, strings, and objects are left as they are. The return type reflects the conversion.

import { jsonify, RecordId, Decimal, Duration } from '@surrealdb/sqon';

const result = jsonify({
rid: new RecordId('person', 'tobie'),
dec: new Decimal('3.333333'),
dur: new Duration('1d2h'),
num: 123,
str: 'hello',
});
{
"rid": "person:tobie",
"dec": "3.333333",
"dur": "1d2h",
"num": 123,
"str": "hello"
}

You can also call .json() on query methods to jsonify the result in one step.

For JSON with explicit type wrappers (for example { "$recordId": ... }), use JsonCodec instead.

The escape helpers quote identifiers and values for hand-built SurrealQL. Prefer bound queries or value classes when you can.

import { escapeIdent, escapeKey, escapeRid, escapeValue } from '@surrealdb/sqon';

escapeIdent('users'); // 'users'
escapeIdent('user-table'); // '`user-table`'
escapeIdent('select'); // '`select`'

escapeKey('user-property'); // properly escaped for object notation

escapeRid('john'); // 'john'
escapeRid('user@email.com'); // '`user@email.com`'

escapeValue('hello'); // "'hello'"
escapeValue(42); // '42'
escapeValue(null); // 'null'
escapeValue(undefined); // 'none'

toSurqlString() walks a value tree (objects, arrays, SQON classes) and returns a SurrealQL literal string. Useful for logs, debugging, or SurrealQL snippets outside bound queries.

import { toSurqlString, RecordId, Decimal } from '@surrealdb/sqon';

toSurqlString(new RecordId('person', 'tobie')); // r"person:tobie"
toSurqlString(new Decimal('3.14')); // 3.14dec

These ship with the surrealdb driver and tie into its query engine. They are not exported from @surrealdb/sqon.

UtilityDescription
expr() Composes type-safe expressions for WHERE clauses and conditions
surql Tagged template for composing parameterized queries
BoundQuery Parameterized query class with manual control
s, d, r, u Tagged templates for SurrealQL string, datetime, record, and UUID prefixes

expr() and its operators build conditions for .where() and for surql templates. See Bound queries for the full list.

import { expr, surql, eq, gte, and, Table } from 'surrealdb';

const premiumAdults = expr(and(
eq('tier', 'premium'),
gte('age', 18),
));

const users = await db.select(new Table('users')).where(premiumAdults);

Operators cover comparisons (eq, ne, gt, gte, lt, lte), logic (and, or, not), strings and arrays (contains, containsAny, containsAll), geometry (inside, outside, intersects), and search (matches, knn).

surql and BoundQuery bind parameters so you do not splice user input into query strings. See Bound queries.

import { surql, BoundQuery } from 'surrealdb';

const minAge = 18;
const query = surql`SELECT * FROM users WHERE age >= ${minAge}`;
const [users] = await db.query(query);

const bound = new BoundQuery(
'SELECT * FROM users WHERE status = $status',
{ status: 'active' },
);
bound.bind('tier', 'premium');
const [results] = await db.query(bound);

The s, d, r, and u templates build typed literals with SurrealQL's string prefixes. See Value types.

const query = surql`SELECT * FROM users WHERE name = ${userName}`;

// Avoid string concatenation (injection risk)
const query = `SELECT * FROM users WHERE name = '${userName}'`;
const condition = expr(and(
eq('status', 'active'),
gte('age', 18),
));

await db.select(new Table('users')).where(condition);
if (equals(recordId1, recordId2)) {
// Same value
}

// Avoid reference comparison (only true if same instance)
if (recordId1 === recordId2) { ... }

Was this page helpful?