equals()
The equals() function performs deep equality comparison for values, including SurrealDB-specific types that may not compare correctly with JavaScript’s === operator.
Import:
import { equals } from 'surrealdb';
Source: utils/equals.ts
Function Signature
function equals(a: unknown, b: unknown): boolean
Parameters
| Parameter | Type | Description |
|---|
a required | unknown | First value to compare. |
b required | unknown | Second value to compare. |
Returns
boolean - true if values are deeply equal, false otherwise
What It Compares
The equals() function correctly handles:
- Primitives - strings, numbers, booleans, null, undefined
- SurrealDB Types - RecordId, DateTime, Duration, Decimal, Uuid, etc.
- Dates - JavaScript Date objects
- Regular Expressions - RegExp patterns
- Objects - Deep object comparison
- Arrays - Deep array comparison
- Mixed types - Proper handling of bigint/number comparisons
Examples
Primitive Comparisons
import { equals } from 'surrealdb';
console.log(equals(42, 42));
console.log(equals('hello', 'hello'));
console.log(equals(true, false));
console.log(equals(null, null));
SurrealDB Type Comparisons
import { RecordId, DateTime, Uuid, Decimal, equals } from 'surrealdb';
const id1 = new RecordId('users', 'john');
const id2 = new RecordId('users', 'john');
const id3 = new RecordId('users', 'jane');
console.log(equals(id1, id2));
console.log(equals(id1, id3));
const dt1 = DateTime.parse('2024-01-15T12:00:00.123456789Z');
const dt2 = DateTime.parse('2024-01-15T12:00:00.123456789Z');
console.log(equals(dt1, dt2));
const uuid1 = Uuid.parse('550e8400-e29b-41d4-a716-446655440000');
const uuid2 = Uuid.parse('550e8400-e29b-41d4-a716-446655440000');
console.log(equals(uuid1, uuid2));
const dec1 = new Decimal('19.99');
const dec2 = new Decimal('19.99');
console.log(equals(dec1, dec2));
Object Comparisons
const obj1 = { name: 'John', age: 30 };
const obj2 = { name: 'John', age: 30 };
const obj3 = { name: 'John', age: 31 };
console.log(equals(obj1, obj2));
console.log(equals(obj1, obj3));
const deep1 = {
user: {
profile: {
name: 'John'
}
}
};
const deep2 = {
user: {
profile: {
name: 'John'
}
}
};
console.log(equals(deep1, deep2));
Array Comparisons
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
const arr3 = [1, 2, 4];
console.log(equals(arr1, arr2));
console.log(equals(arr1, arr3));
const ids1 = [
new RecordId('users', 'john'),
new RecordId('users', 'jane')
];
const ids2 = [
new RecordId('users', 'john'),
new RecordId('users', 'jane')
];
console.log(equals(ids1, ids2));
Mixed Type Comparisons
console.log(equals(42n, 42));
console.log(equals(42, 42n));
const date1 = new Date('2024-01-15');
const date2 = new Date('2024-01-15');
console.log(equals(date1, date2));
Use Cases
Checking Record Existence
async function hasRecord(recordId: RecordId): Promise<boolean> {
const records = await db.select(new Table(recordId.tb));
return records.some(record => equals(record.id, recordId));
}
const exists = await hasRecord(new RecordId('users', 'john'));
Deduplication
function deduplicate<T>(items: T[]): T[] {
const unique: T[] = [];
for (const item of items) {
if (!unique.some(u => equals(u, item))) {
unique.push(item);
}
}
return unique;
}
const recordIds = [
new RecordId('users', 'john'),
new RecordId('users', 'jane'),
new RecordId('users', 'john'),
];
const uniqueIds = deduplicate(recordIds);
console.log(uniqueIds.length);
Change Detection
function hasChanged<T>(before: T, after: T): boolean {
return !equals(before, after);
}
const originalUser = await db.select(userId);
const updatedUser = await db.select(userId);
if (hasChanged(originalUser, updatedUser)) {
console.log('User data was modified');
}
Array Difference
function findNewItems<T>(oldList: T[], newList: T[]): T[] {
return newList.filter(newItem =>
!oldList.some(oldItem => equals(oldItem, newItem))
);
}
const oldTags = ['javascript', 'typescript'];
const newTags = ['javascript', 'typescript', 'react'];
const added = findNewItems(oldTags, newTags);
console.log(added);
Caching / Memoization
class Cache<K, V> {
private cache = new Map<string, { key: K; value: V }>();
set(key: K, value: V): void {
const entry = { key, value };
this.cache.set(JSON.stringify(key), entry);
}
get(key: K): V | undefined {
for (const entry of this.cache.values()) {
if (equals(entry.key, key)) {
return entry.value;
}
}
return undefined;
}
}
// Use with complex keys
const cache = new Cache<RecordId, User>();
const userId = new RecordId('users', 'john');
cache.set(userId, userData);
const cached = cache.get(new RecordId('users', 'john'));
Record Comparison
interface User {
id: RecordId;
name: string;
email: string;
settings: {
theme: string;
notifications: boolean;
};
}
const user1: User = await db.select(new RecordId('users', 'john'));
const user2: User = await db.select(new RecordId('users', 'john'));
console.log(equals(user1, user2));
Why Not Use === or ==?
JavaScript’s equality operators don’t work correctly for:
const obj1 = { name: 'John' };
const obj2 = { name: 'John' };
console.log(obj1 === obj2);
console.log(equals(obj1, obj2));
const id1 = new RecordId('users', 'john');
const id2 = new RecordId('users', 'john');
console.log(id1 === id2);
console.log(equals(id1, id2));
const date1 = new Date('2024-01-15');
const date2 = new Date('2024-01-15');
console.log(date1 === date2);
console.log(equals(date1, date2));
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(arr1 === arr2);
console.log(equals(arr1, arr2));
Best Practices
1. Use for Value Comparisons
if (equals(recordId1, recordId2)) {
}
if (recordId1 === recordId2) {
}
2. Use for Complex Type Comparisons
const sameDateTime = equals(
DateTime.parse('2024-01-15T12:00:00.123456789Z'),
DateTime.parse('2024-01-15T12:00:00.123456789Z')
);
const wrong = dt1 === dt2;
3. Prefer Built-in .equals() for Single Types
const id1 = new RecordId('users', 'john');
const id2 = new RecordId('users', 'john');
console.log(equals(id1, id2));
console.log(id1.equals(id2));
See Also