Capabilities
Quick Highlights
Section titled “Quick Highlights”| 💎 Feature | What it gives you |
|---|---|
| Schema-only mode | Generate SurrealQL with generateFullSchemaQl() without touching the database—perfect for migrations & CI. |
| Embedded testing | Run SurrealDB fully in-process via @surrealdb/node engines (mem://) for ultra-fast unit tests. |
Parameterized queries (vars) |
Prevent injection; supported in select, count, query, etc. |
Type-safe fetch projection |
Automatic hydration of related records (Field.record) with full TypeScript types. |
| Circular dependency thunk | Use Field.record(() => OtherTable) to avoid import cycles while keeping types. |
| Advanced data types | Full, type-safe support for bytes, duration, uuid, decimal, and specific geometry types. |
| Custom Surreal types | Define Field.custom<'left' | 'right'>('"left" | "right"') or any other database type for ultimate flexibility. |
DEFINE TABLE Features
Section titled “DEFINE TABLE Features”| Feature | SurrealDB Syntax Example | unreal-orm Support |
Notes |
|---|---|---|---|
| Basic Table Definition | DEFINE TABLE user; |
✅ Supported | class User extends Table.normal({ name: 'user', ... }) |
IF NOT EXISTS |
DEFINE TABLE user IF NOT EXISTS; |
✅ Supported | Table.normal({ ..., method: 'IF NOT EXISTS' }) |
OVERWRITE |
DEFINE TABLE user OVERWRITE; |
✅ Supported | Table.normal({ ..., method: 'OVERWRITE' }) |
SCHEMAFULL |
DEFINE TABLE user SCHEMAFULL; |
✅ Supported | Table.normal({ ..., schemafull: true }) is the standard. |
SCHEMALESS |
DEFINE TABLE user SCHEMALESS; |
✅ Supported | Table.normal({ ..., schemafull: false }) |
TYPE NORMAL |
DEFINE TABLE user TYPE NORMAL; |
✅ Supported | This is the default for Table.normal. |
TYPE ANY |
DEFINE TABLE user TYPE ANY; |
✅ Supported | Not directly supported, use schemafull: false. |
TYPE RELATION IN ... OUT ... |
DEFINE TABLE likes TYPE RELATION IN user OUT post; |
✅ Supported | Use Table.relation({ fields: { in: Field.record(...), out: Field.record(...) } }). ENFORCED not supported. |
ENFORCED (for TYPE RELATION) |
DEFINE TABLE likes TYPE RELATION ... ENFORCED; |
❌ Not Supported | Tied to full TYPE RELATION syntax. |
Table View (AS SELECT ...) |
DEFINE TABLE user_view AS SELECT ... FROM user; |
✅ Supported | class UserView extends Table.view({ name: 'user_view', as: surql'...' }). |
CHANGEFEED @duration [INCLUDE ORIGINAL] |
DEFINE TABLE user CHANGEFEED 1h; |
✅ Supported | Table.normal({ ..., changefeed: { duration: '1h' } }). |
PERMISSIONS (Table-level) |
DEFINE TABLE user PERMISSIONS FOR select WHERE ...; |
✅ Supported | Table.define({ ..., permissions: { select: '...' } }) |
COMMENT @string |
DEFINE TABLE user COMMENT 'User accounts'; |
✅ Supported | Table.define({ ..., comment: '...' }) |
DROP (within DEFINE TABLE) |
DEFINE TABLE user DROP; |
❌ Not Supported | REMOVE TABLE is a separate operation, not part of Table.define. |
DEFINE FIELD Features
Section titled “DEFINE FIELD Features”| Feature | SurrealDB Syntax Example | unreal-orm Support |
Notes |
|---|---|---|---|
| Basic Field Definition | DEFINE FIELD email ON user; |
✅ Supported | Via fields object in Table.define({ fields: { email: Field.string() } }). |
IF NOT EXISTS (Field-level) |
DEFINE FIELD email ON user IF NOT EXISTS; |
❌ Not Supported | ORM regenerates the whole schema. |
OVERWRITE (Field-level) |
DEFINE FIELD email ON user OVERWRITE; |
❌ Not Supported | ORM regenerates the whole schema. |
TYPE @type (various types) |
DEFINE FIELD age ON user TYPE number; |
⚠️ Partially | See “Data Type Support” section below for detailed coverage. |
FLEXIBLE TYPE @type |
DEFINE FIELD meta ON user FLEXIBLE TYPE object; |
✅ Supported | Use { flexible: true } with Field.object() or Field.custom(). Enables flexible schemas for object/custom fields. |
DEFAULT @expression |
DEFINE FIELD role ON user TYPE string DEFAULT 'guest'; |
✅ Supported | Field.string({ default: surql“guest” }). Handles primitives, time::now(), functions expressed as SurrealQL. |
DEFAULT ALWAYS @expression |
DEFINE FIELD updated_at ON user TYPE datetime DEFAULT ALWAYS time::now(); |
❌ Not Supported | Only standard DEFAULT is supported. |
VALUE @expression |
DEFINE FIELD created_at ON user VALUE time::now(); |
✅ Supported | Field.string({ value: surqltime::now() }) or e.g. Field.string({ value: surqlstring::lowercase($value) }) |
VALUE <future> { @expression } |
DEFINE FIELD last_accessed ON user VALUE <future> { time::now() }; |
❌ Not Supported | Only standard VALUE is supported, not VALUE |
ASSERT @expression |
DEFINE FIELD email ON user ASSERT string::is::email($value); |
✅ Supported | Field.string({ assert: surqlstring::is::email($value) }) |
READONLY |
DEFINE FIELD id ON user READONLY; |
✅ Supported | Field.string({ readonly: true }) |
PERMISSIONS (Field-level) |
DEFINE FIELD email ON user PERMISSIONS FOR select WHERE...; |
✅ Supported | Field.string({ permissions: { ... } }) |
COMMENT @string |
DEFINE FIELD email ON user COMMENT 'User email'; |
✅ Supported | Field.string({ comment: '...' }) |
REFERENCE (with ON DELETE actions) |
DEFINE FIELD author ON post TYPE record<user> REFERENCE ON DELETE CASCADE; |
✅ Supported | Field.record(() => User, { reference: { onDelete: 'CASCADE' } }). (SurrealDB v2.2+) |
Define type for id field |
DEFINE FIELD id ON user TYPE string; |
✅ Supported | Table.define({ fields: { id: Field.custom({ type: 'string' }) } }) |
| Define types for specific array indices | DEFINE FIELD data[0] ON mytable TYPE string; |
❌ Not Supported | Field.array(Field.string()) defines type for all items. |
DEFINE INDEX Features
Section titled “DEFINE INDEX Features”| Feature | SurrealDB Syntax Example | unreal-orm Support |
Notes |
|---|---|---|---|
| Basic Index Definition | DEFINE INDEX user_email ON user COLUMNS email; |
✅ Supported | Table.define({ indexes: { user_email: { fields: ['email'] } } }) |
IF NOT EXISTS (Index-level) |
DEFINE INDEX user_email ON user IF NOT EXISTS ...; |
❌ Not Supported | ORM regenerates the whole schema. |
OVERWRITE (Index-level) |
DEFINE INDEX user_email ON user OVERWRITE ...; |
❌ Not Supported | ORM regenerates the whole schema. |
UNIQUE Index |
DEFINE INDEX user_email ON user COLUMNS email UNIQUE; |
✅ Supported | Index.define(() => User, { fields: ['email'], unique: true }) |
SEARCH ANALYZER (Full-Text Search) |
DEFINE INDEX ... SEARCH ANALYZER ... BM25 HIGHLIGHTS; |
✅ Supported | Use the analyzer option in Index.define. Other keywords like BM25 are not exposed. |
Vector Index (MTREE, HNSW) |
DEFINE INDEX ... MTREE DIMENSION ...; |
❌ Not Supported | |
COMMENT @string |
DEFINE INDEX user_email ON user ... COMMENT '...'; |
✅ Supported | Use the comment option in Index.define. |
CONCURRENTLY |
DEFINE INDEX user_email ON user ... CONCURRENTLY; |
❌ Not Supported |
Other DEFINE Statements
Section titled “Other DEFINE Statements”unreal-orm primarily focuses on schema generation for tables, fields, and indexes. Other DEFINE statements are not yet supported by the ORM.
| Feature | SurrealDB Syntax Example | unreal-orm Support |
Notes |
|---|---|---|---|
DEFINE NAMESPACE |
DEFINE NAMESPACE test; |
❌ Not Supported | Operates within a given DB/NS connection. |
DEFINE DATABASE |
DEFINE DATABASE test; |
❌ Not Supported | |
DEFINE USER |
DEFINE USER ...; |
❌ Not Supported | |
DEFINE TOKEN |
DEFINE TOKEN ...; |
❌ Not Supported | |
DEFINE SCOPE |
DEFINE SCOPE ...; |
❌ Not Supported | |
DEFINE ANALYZER |
DEFINE ANALYZER ...; |
❌ Not Supported | |
DEFINE EVENT |
DEFINE EVENT ... ON TABLE ...; |
❌ Not Supported | |
DEFINE FUNCTION |
DEFINE FUNCTION fn::abc() ...; |
❌ Not Supported | |
DEFINE PARAM |
DEFINE PARAM $myparam ...; |
❌ Not Supported |
Data Type Support
Section titled “Data Type Support”Field Definition Examples
Section titled “Field Definition Examples”import { surql } from "surrealdb";import { Table, Field } from "unreal-orm";
class User extends Table.normal({ name: "user", schemafull: true, fields: { name: Field.string({ assert: surql`$value.length > 2` }), age: Field.number({ assert: surql`$value >= 0`, default: surql`0` }), isActive: Field.bool({ default: surql`true` }), createdAt: Field.datetime({ default: surql`time::now()` }), profile: Field.object({ bio: Field.string(), website: Field.option(Field.string()), }), tags: Field.array(Field.string(), { max: 10 }), posts: Field.array(Field.record(() => Post)), nickname: Field.option(Field.string()), // Advanced Types balance: Field.decimal(), apiKey: Field.uuid(), lastLogin: Field.duration(), avatar: Field.bytes(), location: Field.geometry("point"), side: Field.custom<"left" | "right">('"left" | "right"'), },}) {}
// Define indexes separatelyconst UserNameIndex = Index.define(() => User, { name: "user_name_idx", fields: ["name"], unique: true,});