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 equals(a: unknown, b: unknown): boolean
| Parameter | Type | Description |
|---|---|---|
a required | unknown | First value to compare. |
b required | unknown | Second value to compare. |
boolean - true if values are deeply equal, false otherwise
The equals() function correctly handles:
import { equals } from 'surrealdb'; console.log(equals(42, 42)); // true console.log(equals('hello', 'hello')); // true console.log(equals(true, false)); // false console.log(equals(null, null)); // true
import { RecordId, DateTime, Uuid, Decimal, equals } from 'surrealdb'; // RecordId comparison const id1 = new RecordId('users', 'john'); const id2 = new RecordId('users', 'john'); const id3 = new RecordId('users', 'jane'); console.log(equals(id1, id2)); // true console.log(equals(id1, id3)); // false // DateTime comparison (including nanoseconds) 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)); // true // Uuid comparison const uuid1 = Uuid.parse('550e8400-e29b-41d4-a716-446655440000'); const uuid2 = Uuid.parse('550e8400-e29b-41d4-a716-446655440000'); console.log(equals(uuid1, uuid2)); // true // Decimal comparison (arbitrary precision) const dec1 = new Decimal('19.99'); const dec2 = new Decimal('19.99'); console.log(equals(dec1, dec2)); // true
const obj1 = { name: 'John', age: 30 }; const obj2 = { name: 'John', age: 30 }; const obj3 = { name: 'John', age: 31 }; console.log(equals(obj1, obj2)); // true console.log(equals(obj1, obj3)); // false // Deep nested objects const deep1 = { user: { profile: { name: 'John' } } }; const deep2 = { user: { profile: { name: 'John' } } }; console.log(equals(deep1, deep2)); // true
const arr1 = [1, 2, 3]; const arr2 = [1, 2, 3]; const arr3 = [1, 2, 4]; console.log(equals(arr1, arr2)); // true console.log(equals(arr1, arr3)); // false // Arrays with SurrealDB types 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)); // true
// bigint and number comparison console.log(equals(42n, 42)); // true console.log(equals(42, 42n)); // true // Date comparison const date1 = new Date('2024-01-15'); const date2 = new Date('2024-01-15'); console.log(equals(date1, date2)); // true
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'));
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'), // Duplicate ]; const uniqueIds = deduplicate(recordIds); console.log(uniqueIds.length); // 2
function hasChanged<T>(before: T, after: T): boolean { return !equals(before, after); } const originalUser = await db.select(userId); // ... user makes changes ... const updatedUser = await db.select(userId); if (hasChanged(originalUser, updatedUser)) { console.log('User data was modified'); }
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); // ['react']
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')); // Found!
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')); // Deep comparison including nested objects and RecordId console.log(equals(user1, user2)); // true
=== or ==?JavaScript’s equality operators don’t work correctly for:
// Problem 1: Object references const obj1 = { name: 'John' }; const obj2 = { name: 'John' }; console.log(obj1 === obj2); // false (different references) console.log(equals(obj1, obj2)); // true (same content) // Problem 2: SurrealDB types const id1 = new RecordId('users', 'john'); const id2 = new RecordId('users', 'john'); console.log(id1 === id2); // false (different instances) console.log(equals(id1, id2)); // true (same value) // Problem 3: Date comparison const date1 = new Date('2024-01-15'); const date2 = new Date('2024-01-15'); console.log(date1 === date2); // false console.log(equals(date1, date2)); // true // Problem 4: Arrays const arr1 = [1, 2, 3]; const arr2 = [1, 2, 3]; console.log(arr1 === arr2); // false console.log(equals(arr1, arr2)); // true
// Good: Deep equality if (equals(recordId1, recordId2)) { // Same record } // Avoid: Reference equality (wrong for objects) if (recordId1 === recordId2) { // Only true if same instance }
// Good: Proper comparison const sameDateTime = equals( DateTime.parse('2024-01-15T12:00:00.123456789Z'), DateTime.parse('2024-01-15T12:00:00.123456789Z') ); // true // Avoid: Direct comparison const wrong = dt1 === dt2; // false (different instances)
.equals() for Single Typesconst id1 = new RecordId('users', 'john'); const id2 = new RecordId('users', 'john'); // Both are fine: console.log(equals(id1, id2)); // true console.log(id1.equals(id2)); // true // Use id1.equals(id2) when you know both are RecordId // Use equals(id1, id2) for generic comparisons