• 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.

Utility

Description

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');
}
Note

Individual value classes also expose an .equals() instance method for single-type comparisons (e.g. recordId.equals(other)). Use the standalone equals() function for generic or cross-type comparisons.

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'
Warning

Escaping alone does not stop injection. Use surql or BoundQuery for dynamic values.

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.

Utility

Description

expr()

Composes type-safe expressions for WHERE clauses and conditions

surql

Tagged template for composing parameterised queries

BoundQuery

Parameterised query class with manual control

s, d, r, u

Tagged templates for SurrealQL string, datetime, record, and UUID prefixes

isRetryableConflict(error)

Default predicate used by

.retry()

to detect retryable write conflicts

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?