Migrating 0.x → 1.0.0 alpha
This guide helps you upgrade your UnrealORM codebase to 1.0.0 alpha. The 1.0.0 release includes major improvements including transaction support, SurrealDB JS SDK 2.0 alpha integration, and enhanced update APIs.
Breaking Changes
Section titled “Breaking Changes”1. $dynamic Property Removed
Section titled “1. $dynamic Property Removed”Extra fields (fields not defined in your schema) are now assigned directly to model instances instead of being stored in the $dynamic property.
Before (pre-1.0):
const user = await User.select(db, { only: true, limit: 1 });// Extra fields were in $dynamicconsole.log(user.$dynamic.someExtraField);After (1.0.0 alpha):
const user = await User.select(db, { only: true, limit: 1 });// Extra fields are now directly on the instanceconsole.log(user.someExtraField);2. Update Method Signature
Section titled “2. Update Method Signature”Before (pre-1.0):
// Instance methodsawait user.update(db, { name: "Jane" });await user.merge(db, { name: "Jane" });
// Static methodsawait User.update(db, "user:123", { name: "Jane" });await User.merge(db, "user:123", { name: "Jane" });After (1.0.0 alpha):
// Instance methods - now requires explicit modeawait user.update(db, { data: { name: "Jane" }, mode: "merge" });await user.update(db, { data: { name: "Jane" }, mode: "content" });
// Static methods - now requires explicit modeawait User.update(db, "user:123", { data: { name: "Jane" }, mode: "merge",});3. Removed merge Method
Section titled “3. Removed merge Method”The merge method has been removed. Use update with mode: 'merge' instead.
Before:
await user.merge(db, { name: "Jane" });After:
await user.update(db, { data: { name: "Jane" }, mode: "merge" });4. from Method Enhanced
Section titled “4. from Method Enhanced”The from method now supports surql template literals and raw queries in addition to record IDs.
Before (pre-1.0):
// Only record IDs were supportedconst user = await User.from(db, "user:123");After (1.0.0 alpha):
import { surql } from "surrealdb";
// Record ID (still works)const user = await User.from(db, "user:123");
// SurrealQL queryconst users = await User.from(db, surql`SELECT * FROM user WHERE age > 18`);
// Raw query stringconst users = await User.from(db, { raw: "SELECT * FROM user WHERE active = true" });5. SurrealDB 2.0 Alpha Dependency
Section titled “5. SurrealDB 2.0 Alpha Dependency”UnrealORM 1.0.0 alpha requires SurrealDB 2.0 alpha. Update your dependencies:
package.json:
{ "dependencies": { "surrealdb": "^2.0.0-alpha.14", "@surrealdb/node": "2.3.4" // if you run embedded, such as for internal testing }}6. Field Options Type Changes
Section titled “6. Field Options Type Changes”Field options now use BoundQuery and Expr types instead of strings for better type safety.
Before:
Field.string({ assert: "$value CONTAINS '@'", default: "'unknown@example.com'",});After:
import { surql } from "surrealdb";
Field.string({ assert: surql`$value CONTAINS "@"`, default: surql`"unknown@example.com"`,});New: CLI Tools
Section titled “New: CLI Tools”UnrealORM 1.0.0 alpha introduces a new CLI package for schema management:
# Initialize a new project (recommended starting point)bunx @unreal-orm/cli init
# Or with other package managersnpx @unreal-orm/cli initpnpm dlx @unreal-orm/cli inityarn dlx @unreal-orm/cli initThe init command will:
- Configure your database connection
- Set up the project structure (
unreal/folder) - Install dependencies (
unreal-orm,surrealdb,@unreal-orm/cli) - Optionally generate sample tables or import from existing database
Available Commands
Section titled “Available Commands”| Command | Description |
|---|---|
init | Initialize UnrealORM in your project |
pull | Introspect database and generate TypeScript schema |
push | Apply TypeScript schema to database |
diff | Compare code schema with database schema |
mermaid | Generate ERD diagrams from your schema |
view | Interactive TUI for browsing and editing records |
Quick Start
Section titled “Quick Start”# Initialize a new projectbunx @unreal-orm/cli init
# After init, use the CLI directlyunreal pull # Generate TypeScript from databaseunreal push # Apply schema to databaseunreal diff # Compare code vs databaseSmart Merge
Section titled “Smart Merge”The pull command now features intelligent merging that preserves your customizations:
- Adds new fields/indexes with
// Added from databasecomments - Comments out removed fields/indexes for review (never deletes your code)
- Preserves your custom methods, comments, and formatting
See the CLI README for full documentation.
New: Implicit Database Support
Section titled “New: Implicit Database Support”UnrealORM 1.0.0 alpha introduces optional implicit database connections. Configure your database once, then call CRUD methods without passing db explicitly.
Configuration
Section titled “Configuration”Run unreal init to set up your project:
bunx @unreal-orm/cli initThis creates:
unreal/surreal.ts- Database connection withUnreal.configure()callunreal.config.json- Project configuration
The generated surreal.ts automatically configures the ORM when imported. Just add this import to your app’s entry point:
// In your main.ts, index.ts, or app entry pointimport "./unreal/surreal";All CRUD methods now support two calling patterns:
// Pattern 1: Explicit db (always works)const users = await User.select(db, { limit: 10 });const user = await User.create(db, { name: "John" });await user.update(db, { data: { name: "Jane" }, mode: "merge" });await user.delete(db);
// Pattern 2: Implicit db (uses configured default)const users = await User.select({ limit: 10 });const user = await User.create({ name: "John" });await user.update({ data: { name: "Jane" }, mode: "merge" });await user.delete();Supported Methods
Section titled “Supported Methods”| Method | Explicit | Implicit |
|---|---|---|
Model.select(db, options) | ✓ | Model.select(options) |
Model.create(db, data) | ✓ | Model.create(data) |
Model.update(db, id, options) | ✓ | Model.update(id, options) |
Model.delete(db, id) | ✓ | Model.delete(id) |
instance.update(db, options) | ✓ | instance.update(options) |
instance.delete(db) | ✓ | instance.delete() |
Step-by-Step Migration
Section titled “Step-by-Step Migration”1. Update Dependencies
Section titled “1. Update Dependencies”The easiest way is to run the init command which handles everything:
bunx @unreal-orm/cli initOr manually update:
# Update SurrealDB to 2.0 alphabun add surrealdb@alphabun add @surrealdb/node@alpha # if using embedded mode
# Update UnrealORM and install CLIbun add unreal-orm@latestbun add -D @unreal-orm/cli@latest2. Update Update Method Calls
Section titled “2. Update Update Method Calls”Find all instances of .update() and .merge() calls and update them:
# Search for update calls (manual review required)grep -r "\.update(" src/grep -r "\.merge(" src/Migration patterns:
// Pattern 1: Simple updates// Beforeawait user.update(db, { name: "Jane" });// Afterawait user.update(db, { data: { name: "Jane" }, mode: "merge" });
// Pattern 2: Merge calls// Beforeawait user.merge(db, { name: "Jane" });// Afterawait user.update(db, { data: { name: "Jane" }, mode: "merge" });
// Pattern 3: Static updates// Beforeawait User.update(db, "user:123", { name: "Jane" });// Afterawait User.update(db, "user:123", { data: { name: "Jane" }, mode: "content",});3. Update Field Definitions
Section titled “3. Update Field Definitions”Update field options to use surql templates:
import { surql } from "surrealdb";
// Beforeclass User extends Table.normal({ name: "user", fields: { email: Field.string({ assert: "$value CONTAINS '@'", default: "'unknown@example.com'", }), active: Field.bool({ default: "true" }), },}) {}
// Afterclass User extends Table.normal({ name: "user", fields: { email: Field.string({ assert: surql`$value CONTAINS "@"`, default: surql`"unknown@example.com"`, }), active: Field.bool({ default: surql`true` }), },}) {}Transaction Migration
Section titled “Transaction Migration”Basic Transaction Usage
Section titled “Basic Transaction Usage”import { Surreal } from "surrealdb";
const db = new Surreal();await db.connect("memory");
// Start a transactionconst tx = await db.beginTransaction();
try { // All operations now use the transaction instead of db const user = await User.create(tx, { name: "Alice" }); const post = await Post.create(tx, { title: "Hello", author: user.id });
await user.update(tx, { data: { name: "Alice Smith" }, mode: "merge" });
// Commit the transaction await tx.commit();} catch (error) { // Rollback on error await tx.cancel(); throw error;}Feature Flag Checking
Section titled “Feature Flag Checking”Check if transactions are supported in your SurrealDB version:
import { Features } from "surrealdb";
if (db.isFeatureSupported(Features.Transactions)) { // Transactional operations const tx = await db.beginTransaction(); // ... use transaction} else { // Fallback to non-transactional operations console.warn("Transactions not supported, using regular operations");}Update API Migration
Section titled “Update API Migration”Update Modes Explained
Section titled “Update Modes Explained”| Mode | Description | Use Case |
|---|---|---|
content | Full document replacement | Complete record updates |
merge | Partial field updates | Incremental changes |
replace | Full document replacement (alias) | Same as content |
patch | JSON Patch operations | Complex field-level changes |
Migration Examples
Section titled “Migration Examples”// 1. Simple field updates (most common)// Beforeawait user.update(db, { name: "Jane" });await user.merge(db, { email: "jane@example.com" });
// Afterawait user.update(db, { data: { name: "Jane" }, mode: "merge" });await user.update(db, { data: { email: "jane@example.com" }, mode: "merge" });
// 2. Complete record replacement// Before (update with all required fields)await user.update(db, { name: "Jane", email: "jane@example.com", age: 30 });
// Afterawait user.update(db, { data: { name: "Jane", email: "jane@example.com", age: 30 }, mode: "content",});
// 3. JSON Patch operations (new in 1.0.0)const user = await User.update(db, "user:123", { data: [ { op: "replace", path: "/name", value: "Jane" }, { op: "add", path: "/age", value: 30 }, ], mode: "patch",});SurrealDB 2.0 Integration
Section titled “SurrealDB 2.0 Integration”New Imports
Section titled “New Imports”import { surql, BoundQuery, Expr } from "surrealdb";Query Building Changes
Section titled “Query Building Changes”// Before (string-based queries)const users = await User.select(db, { where: "age > 18 AND status = 'active'",});
// After (syntax highlighted and automatic variable binding)const users = await User.select(db, { // using surql template where: surql`age > 18 AND status = 'active'`, // or using Expr api where: and(eq("active", true), gte("age", age)), // or both! where: surql`${eq("active", true)} AND age >= ${age}`,});Field Option Updates
Section titled “Field Option Updates”// BeforeField.string({ permissions: { select: "WHERE $auth.id = owner", },});
// AfterField.string({ permissions: { select: surql`WHERE $auth.id = owner`, },});Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”1. TypeScript errors with update methods
Section titled “1. TypeScript errors with update methods”Error: Argument of type '{ name: string }' is not assignable to parameter of type 'UpdateOptions<...>'
Solution: Wrap data in data property and specify mode:
// Wrongawait user.update(db, { name: "Jane" });
// Correctawait user.update(db, { data: { name: "Jane" }, mode: "merge" });2. Field option type errors
Section titled “2. Field option type errors”Error: Type 'string' is not assignable to type 'BoundQuery | Expr'
Solution: Use surql template literals:
import { surql } from "surrealdb";
// WrongField.string({ default: "default_value" });
// CorrectField.string({ default: surql`default_value` });3. Transaction not supported
Section titled “3. Transaction not supported”Error: beginTransaction is not a function
Solution: Check SurrealDB version and feature support:
import { Features } from "surrealdb";
if (!db.isFeatureSupported(Features.Transactions)) { console.log("Transactions require SurrealDB v3 (alpha)"); // Use regular db operations instead}Getting Help
Section titled “Getting Help”- GitHub Issues: Report bugs
- GitHub Discussions: Ask questions
- Documentation: Full docs
Migration Checklist
Section titled “Migration Checklist”- Update SurrealDB to 2.0 alpha
- Update UnrealORM to 1.0.0 alpha
- Run
bunx @unreal-orm/cli initor install CLI manually - Replace
.$dynamic.fieldwith.field(direct property access) - Replace all
.merge()calls with.update({ mode: 'merge' }) - Update all
.update()calls to use new signature - Update
.from()calls if using raw queries (now supportssurqland{ raw: ... }) - Convert field options to use
surqltemplates - Add transaction support where needed
- Test all CRUD operations
- Verify type safety with TypeScript compiler
- Use
unreal diffto verify schema sync - (Optional) Run
unreal initto enable implicit database support