The JavaScript SDK provides a set of utility functions for common tasks like deep value comparison, JSON conversion, SurrealQL string serialization, identifier escaping, and expression building. These complement the SDK’s core query methods and value types.
| Utility | Description |
|---|---|
equals(a, b) | Deep equality comparison for all value types |
expr() | Composes type-safe expressions for WHERE clauses and conditions |
surql | Tagged template for composing parameterized queries |
BoundQuery | Parameterized query class with manual control |
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 |
JavaScript’s === operator compares objects by reference, which means two RecordId instances with the same table and ID are not considered equal. The equals() function performs deep structural comparison across all value types, including SurrealDB’s custom classes, nested objects, arrays, Date, RegExp, and bigint/number normalization.
import { equals, RecordId } from 'surrealdb'; 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)
This is particularly useful for detecting changes in query results.
const user1 = await db.select(userId); const user2 = await db.select(userId); if (!equals(user1, user2)) { console.log('Record was modified'); }
NoteIndividual value classes also expose an
.equals()instance method for single-type comparisons (e.g.recordId.equals(other)). Use the standaloneequals()function for generic or cross-type comparisons.
The jsonify() function converts SurrealDB value types in a result to their JSON representations, in the same manner that SurrealDB would serialize them. It only transforms SurrealDB-specific classes, leaving all other values untouched, and is fully type-safe.
import { jsonify, RecordId, Decimal, Duration } from 'surrealdb'; 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 jsonify query results directly using the .json() chain on query methods.
The expr() function and its companion operators allow you to compose dynamic, type-safe conditions for use in query builder methods like .where() and in surql templates. See Bound queries for the full guide.
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);
Available operators include comparison (eq, ne, gt, gte, lt, lte), logical (and, or, not), string/array (contains, containsAny, containsAll), geometry (inside, outside, intersects), and search (matches, knn).
The surql tagged template and BoundQuery class provide safe parameterization for dynamic queries. See Bound queries for the full guide.
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);
When you need to construct SurrealQL strings manually, the escape functions ensure that identifiers and values are properly quoted. In most cases, you should prefer bound queries or the value type classes instead of manual escaping.
import { escapeIdent, escapeKey, escapeRid, escapeValue } from 'surrealdb'; 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'
WarningEscape functions are not a complete defense against injection. Always prefer parameterized queries using
surqlorBoundQuery.
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) { ... }