Defining SQL Models
Models represent tables in your database. Define them by extending the Model
class and using decorators for columns and relations.
Decorators & Column Types
Hysteria ORM uses TypeScript decorators to define model fields and relationships. Decorators are special annotations that add metadata or behavior to class properties.
Column Decorators
Decorator | Description | Example Usage |
---|---|---|
@column() | Standard column. Accepts options like primaryKey , hidden , etc. | @column() name: string; |
@column.integer() | Ensures value is stored as integer. Useful for PKs and numeric fields. | @column.integer({ primaryKey: true }) id: number; |
@column.boolean() | Stores value as boolean, handles DB-specific formats. | @column.boolean() isActive: boolean; |
@column.json() | Serializes/deserializes JSON objects automatically. | @column.json() json: Record<string, any>; |
@column.date() | Handles date fields, with options for auto-creation and auto-update. | @column.date({ autoCreate: true }) createdAt: Date; |
@column.uuid() | Auto-generates a UUID if not provided. | @column.uuid({ primaryKey: true }) uuid: string; |
@column.ulid() | Auto-generates a ULID if not provided. | @column.ulid({ primaryKey: true }) ulid: string; |
@column.encryption.symmetric() | Encrypts/decrypts value using a symmetric key. | @column.encryption.symmetric({ key }) secret: string; |
@column.encryption.asymmetric() | Encrypts/decrypts value using asymmetric keys. | @column.encryption.asymmetric({ publicKey, privateKey }) secret: string; |
Column Options
You can pass options to @column()
and its variants to control column behavior:
Option | Type | Default | Description |
---|---|---|---|
primaryKey | boolean | false | Marks this column as the primary key. Only one primary key is allowed per model. |
serialize | function | undefined | Function to transform the value after reading from the database (e.g., parse, convert type). |
prepare | function | undefined | Function to transform the value before writing to the database (e.g., format, encrypt). |
hidden | boolean | false | If true, this column will not appear in serialized output (e.g., API responses). |
autoUpdate | boolean | false | If true, prepare will always be called on update, even if the value is not in the payload. |
databaseName | string | property name (case-converted) | Custom name for the column in the database. |
Example Usage
@column({ primaryKey: true, hidden: true, databaseName: 'user_id' })
declare id: number;
@column({
prepare: (value) => value.trim(),
serialize: (value) => value.toUpperCase(),
})
declare name: string;
Notes:
primaryKey
: Composite primary keys are not supported. Defining more than one will throw an error.hidden
: Useful for sensitive fields like passwords.prepare
/serialize
: Use for custom transformations, e.g., encryption, formatting, or type conversion.databaseName
: Use if your DB column name differs from your property name or case convention.
Examples
@column()
declare name: string;
@column.integer({ primaryKey: true })
declare id: number;
@column.boolean()
declare isActive: boolean;
@column.json()
declare json: Record<string, any> | null;
@column.date({ autoCreate: true })
declare createdAt: Date;
@column.uuid({ primaryKey: true })
declare uuid: string;
@column.ulid({ primaryKey: true })
declare ulid: string;
@column.encryption.symmetric({ key: 'my-secret-key' })
declare secret: string;
Relation Decorators
Decorator | Description | Example Usage |
---|---|---|
@hasOne | One-to-one relationship | @hasOne(() => Profile, 'userId') profile: Profile; |
@hasMany | One-to-many relationship | @hasMany(() => Post, 'userId') posts: Post[]; |
@belongsTo | Inverse of hasOne/hasMany | @belongsTo(() => User, 'userId') user: User; |
@manyToMany | Many-to-many via a join table | @manyToMany(() => Role, () => UserRole, { leftForeignKey: 'userId', rightForeignKey: 'roleId' }) roles: Role[]; |
Model Static Properties
You can customize model behavior by setting static properties on your model class:
Property | Description | Default | Example Usage |
---|---|---|---|
static _table | Custom table name for the model. | Pluralized snake_case | static _table = "users"; |
static modelCaseConvention | Case convention for model property names (e.g., camel, snake, pascal, none). | "camel" | static modelCaseConvention = "camel"; |
static databaseCaseConvention | Case convention for database column names. | "snake" | static databaseCaseConvention = "snake"; |
static softDeleteColumn | Column name used for soft deletes. | "deletedAt" | static softDeleteColumn = "deletedAt"; |
static softDeleteValue | Value set when soft deleting (usually a timestamp). | Current UTC datetime | YYYY-MM-DD HH:mm:ss |
Details
-
Custom Table Name (
_table
): By default, the table name is the pluralized, snake_case version of your model class. Override this by settingstatic _table
. -
Case Conventions:
modelCaseConvention
: Controls how property names are interpreted in your code (default: camelCase).databaseCaseConvention
: Controls how column names are mapped in the database (default: snake_case). This is useful for aligning with your database's naming style.
-
Soft Delete Support:
softDeleteColumn
: The column used to mark a record as deleted (default:deletedAt
).softDeleteValue
: The value written to the soft delete column (default: current UTC datetime in"YYYY-MM-DD HH:mm:ss"
format). When you soft delete a record, this value is set instead of actually removing the row.
Example: User Model
import { Model, column, hasMany, hasOne, manyToMany } from 'hysteria-orm';
import { Post } from './Post';
import { Address } from './Address';
export class User extends Model {
// Custom table name for this model
static _table = "users";
// Optional: override case conventions if needed
// static modelCaseConvention = "camel";
// static databaseCaseConvention = "snake";
// Optional: customize soft delete behavior
// static softDeleteColumn = "deletedAt";
// static softDeleteValue = new Date().toISOString();
@column.integer({ primaryKey: true })
declare id: number;
@column()
declare name: string;
@column()
declare email: string;
@column({ hidden: true })
declare password: string;
@column()
declare status: 'active' | 'inactive';
@column.boolean()
declare isActive: boolean;
@column.json()
declare json: Record<string, any> | null;
@column.date({ autoCreate: true })
declare createdAt: Date;
@column.date({ autoCreate: true, autoUpdate: true })
declare updatedAt: Date;
@hasOne(() => Post, 'userId')
declare post: Post;
@hasMany(() => Post, 'userId')
declare posts: Post[];
@manyToMany(() => Address, () => UserAddress, {
leftForeignKey: 'userId',
rightForeignKey: 'addressId',
})
declare addresses: Address[];
}
Decorators
@column()
for fields@column.integer()
,@column.boolean()
,@column.json()
,@column.date()
for typed fields@hasOne
,@hasMany
,@belongsTo
,@manyToMany
for relations
Next: Model Hooks