Design Principles
Core Philosophy
Section titled “Core Philosophy”UnrealORM is designed to provide a type-safe interface to SurrealDB while staying as close as possible to SurrealDB’s native capabilities. Our goal is to enhance the developer experience through TypeScript types and builder patterns without abstracting away from SurrealDB’s powerful features.
Key Principles
Section titled “Key Principles”1. Native First
Section titled “1. Native First”- DO expose SurrealDB’s native features directly
- DO use SurrealQL expressions for computations and mutations
- DON’T create abstractions that hide or replace SurrealDB’s native capabilities
- DON’T add computed fields or transformations at the ORM level
Example:
// GOOD: Using SurrealQL's native time::now() functionconst User = Table.define({ createdAt: Field.datetime({ default: 'time::now()' })});
// BAD: Adding ORM-level computationconst User = Table.define({ createdAt: Field.datetime({ defaultNow: true }) // Don't add this kind of abstraction});
2. Type Safety Without Overhead
Section titled “2. Type Safety Without Overhead”- DO provide TypeScript types for all SurrealDB features
- DO use type inference to improve developer experience
- DON’T add runtime type checking or validation
- DON’T create complex type hierarchies that don’t map to SurrealDB concepts
Example:
// GOOD: Types that directly map to SurrealDB conceptsinterface RecordLinkOptions { table: typeof Table; reference?: boolean; onDelete?: 'cascade' | 'restrict' | 'no action';}
// BAD: Complex abstractions that don't map to SurrealDBinterface ComputedFieldOptions { compute: (record: any) => any; // Don't add client-side computation}
3. Query Building
Section titled “3. Query Building”- DO allow direct use of SurrealQL in queries
- DO provide type-safe parameters for queries
- DON’T create a query builder that abstracts away SurrealQL
- DON’T add ORM-specific query operations
Example:
// GOOD: Direct use of SurrealQL with type-safe parametersconst adults = await User.find(db, { where: "age >= $minAge", orderBy: [{ field: "age", order: "DESC" }]}, { minAge: 18 });
// BAD: ORM-specific query abstractionsconst adults = await User.where() .ageGreaterThan(18) .orderByAgeDesc() .find();
4. Schema Definition
Section titled “4. Schema Definition”- DO provide a direct mapping to SurrealDB’s schema capabilities
- DO expose all SurrealQL field types and options
- DON’T add ORM-specific field types
- DON’T create schema features that can’t be represented in SurrealDB
Example:
// GOOD: Direct mapping to SurrealDB field types and optionsconst Product = Table.define({ name: Field.string({ assert: 'string::len($value) > 0', value: 'string::trim($value)' }), price: Field.number({ assert: '$value >= 0' })});
// BAD: ORM-specific validations or transformationsconst Product = Table.define({ name: Field.string({ transform: (value) => value.trim(), // Don't add client-side transforms validate: (value) => value.length > 0 // Don't add client-side validation })});
5. Record Links and References
Section titled “5. Record Links and References”- DO use SurrealDB’s native record linking capabilities
- DO support SurrealDB’s reference tracking feature