v1.0.0-alpha.11
This release introduces explicit database connections, a type-safe query builder, vector index support, file storage buckets, and a complete documentation redesign.
⚠️ Breaking Changes
Section titled “⚠️ Breaking Changes”Explicit db Argument Required
Section titled “Explicit db Argument Required”Global database configuration has been removed. All model CRUD methods (create, insert, select, count, update, updateMany, delete, deleteMany) and instance methods now require an explicit db argument as the first parameter.
Before:
import { configure } from "unreal-orm";
configure({ getDatabase: () => db });// db was resolved implicitly from global configconst users = await User.select({ where: surql`email = 'bob@bob.com'` });After:
// db must be passed explicitly as the first argumentconst users = await User.select(db, { where: surql`email = 'bob@bob.com'` });The configure() function (previously exported from unreal-orm) has been removed. A validateDb() utility is now used internally to provide clear error messages when db is missing.
✨ Features
Section titled “✨ Features”Type-Safe Query Builder
Section titled “Type-Safe Query Builder”A new field proxy query builder provides typed operators, SurrealDB built-in functions, and graph traversal syntax directly on field references. The proxy is passed as a callback parameter to where clauses on select, count, updateMany, and deleteMany:
const results = await Post.select(db, { where: (f) => f.title.contains("hello"), select: { title: true, commentCount: typed<number>(surql`count(<-comment)`), },});The proxy exposes typed namespaces for string::*, math::*, array::*, time::*, meta::*, record::*, type::*, is::*, and other SurrealDB function families, with full TypeScript autocompletion and return type inference. Graph traversal operators (->, <-, <->) are available directly on field refs. Standalone helper functions and(...), or(...), not(...), eq(), gt(), gte(), lt(), lte(), countIn(), countOut(), and more are also exported for composing complex conditions.
upsert Method
Section titled “upsert Method”A new UPSERT CRUD method creates or updates a record based on unique index lookup, avoiding table scans:
const user = await User.upsert(db, { data: { email: "bob@bob.com", name: "Bob Bobson" },});New CRUD Helpers: relate, count, updateMany, deleteMany
Section titled “New CRUD Helpers: relate, count, updateMany, deleteMany”New static methods added to model classes:
relate— Creates graph edges withRELATEsyntax, with optionalOR UPDATEand custom edge IDscount— Counts records with optionalwherefilter andbygroupingupdateMany— Bulk updates all records matching awhereclausedeleteMany— Bulk deletes all records matching awhereclause
// Create a graph edgeconst follow = await Follow.relate(db, { from: user.id, to: post.id, data: { since: new Date() },});
// Count active usersconst activeCount = await User.count(db, { where: (f) => f.is_active.eq(true),});
// Bulk updateawait User.updateMany(db, { where: (f) => f.is_active.eq(false), data: { is_active: true }, mode: 'merge',});
// Bulk deleteawait User.deleteMany(db, { where: (f) => f.is_active.eq(false),});Range APIs (RangeId and Range)
Section titled “Range APIs (RangeId and Range)”New builder APIs for SurrealDB record ID and value ranges, with support for NONE and UNBOUNDED sentinels:
import { RangeId, NONE, UNBOUNDED } from "unreal-orm";
const range = RangeId("player").from(["mage", NONE]).to(["mage", UNBOUNDED]);const results = await Player.select(db, { from: range });set Update Mode
Section titled “set Update Mode”A new set update mode supports computed field expressions via the query builder. Available on update (with data and mode: 'set') and updateMany (which accepts a callback for both where and data):
// Single record update with SET modeawait Post.update(db, postId, { mode: 'set', data: { views: surql`views + 1` },});
// Bulk update with field proxy callbackawait Post.updateMany(db, { mode: 'set', where: (f) => f.status.eq('published'), data: (f) => ({ views: f.views.add(1) }),});Callback-Based where Clauses
Section titled “Callback-Based where Clauses”select, count, updateMany, and deleteMany now accept callback-based where clauses for type-safe condition building. Use the standalone and(...), or(...), and not(...) functions to combine conditions:
import { and } from "unreal-orm";
const active = await User.select(db, { where: (f) => and(f.is_active.eq(true), f.age.gte(18)),});Index Enhancements
Section titled “Index Enhancements”New index options added:
COUNT— maintain a count of indexed entriesCONCURRENTLY— build index without blocking writesDEFER— defer index creation to next transactionFULLTEXT/BM25/HIGHLIGHTS— full-text search index configuration
Select Options
Section titled “Select Options”New select query options:
EXPLAIN— query execution planSPLIT— split results on a fieldWITH— index hintTEMPFILES— use temporary files for large result sets
Vector Index Support (MTREE, HNSW, DISKANN)
Section titled “Vector Index Support (MTREE, HNSW, DISKANN)”Full vector index support across the ORM and CLI, including parsing, generation, extraction, comparison, introspection, and codegen:
import { Index, Field } from "unreal-orm";
class Post extends Table.normal({ embedding: Field.array(Field.float()), // ...});
Index.define(() => Post, { name: "idx_embedding", fields: ["embedding"], vector: { type: "MTREE", dimension: 128, distance: "EUCLIDEAN", },});Supports all three vector index types with configurable dimension, distance metric, and element type. The CLI pull command now introspects vector indexes, and diff shows detailed change descriptions (e.g., “dimension 128 → 256”, “type MTREE → HNSW”).
File Storage Buckets
Section titled “File Storage Buckets”New Bucket.define() API for SurrealDB v3 file storage buckets (experimental):
import { Bucket } from "unreal-orm";
const AvatarBucket = Bucket.define({ name: "avatars", backend: "memory",});
const UploadBucket = Bucket.define({ name: "uploads", backend: "file:/var/data/uploads", permissions: surql`WHERE $auth.role = 'admin' OR $action = 'get'`, readonly: true,});
await Unreal.applySchema(db, [User, AvatarBucket, UploadBucket]);Supports memory and file backends, read-only mode, permission clauses with $action/$file/$target variables, and global buckets. Requires the files experimental capability in SurrealDB v3.
🔧 Improvements
Section titled “🔧 Improvements”Type Safety Overhaul
Section titled “Type Safety Overhaul”- Enforced
RecordIdtype forCreateData.idacrosscreate,upsert, andrelate - Removed all
db as unknown as Surrealcasts in favor ofSurrealLike.query()with typedsurql<R>calls - Removed
Record<string, unknown>destructuring casts in favor of direct typed destructuring - Removed
as TableDatacasts via propersurql<[TableData[]]>result typing - Fixed
id.table.nameusage instead of unsafe(id as { tb?: string }).tbcast - Fixed discriminated union narrowing for update modes
Field Assert Refactoring
Section titled “Field Assert Refactoring”resolveAssert now accepts an AssertCallback and uses createValueProxy for a typed $value proxy in field assertions. Removed redundant prop as string casts in field-proxy.
Documentation Redesign
Section titled “Documentation Redesign”- Complete restructure into getting-started, concepts, querying, advanced, and guides sections
- New hand-drawn design system with custom CSS, fonts, paper textures, and dark mode palette
- New pages: installation, quickstart, what-is-surrealdb, fields-and-types, indexes, models-and-tables, schema-application, surrealql-mapping, selecting, inserting, updating, deleting, where-builder, relations, permissions, migrations, sdk-interop, testing, cli-usage, full-text-search, geospatial, file-storage
- Fixed all SurrealDB SDK connection examples to use single
.connect()call pattern - Upgraded Astro, Starlight, and docs dependencies to latest
- Bumped TypeScript to 7.0.2 and Biome to 2.5.6
Dependency Updates
Section titled “Dependency Updates”- Bumped
surrealdbpeer and dev dependency to^2.0.8
🐛 Bug Fixes
Section titled “🐛 Bug Fixes”- Removed duplicate
generateMigrationSurqlandcompareSchemasfrom CLI — now re-exports fromunreal-orm - Removed dead code from
generateMigration(unused functions and variables) - Deleted empty introspection types file
- Removed redundant
db.use()call (handled bydb.connect()) - Fixed VIEW table generation: removed incorrect
TYPE NORMAL/TYPE ANYclauses - Hardened push transaction: ensured semicolons between statements in
BEGIN...COMMITblock - Fixed inconsistent
SchemaChangeimport (direct import fromunreal-orminstead of inline) - Fixed
idx_email.fieldsfallback forstring[] | undefinedtype mismatch - Enhanced
compareSchemaswith vector index type suffix and detailed vector parameter change descriptions