Types API Reference¶
This guide documents all TypeScript types exported by Dynamite ORM that enable creating models with complete type-safety.
Table of Contents¶
- Attribute Marker Types
- CreationOptional\<T>
- NonAttribute\<T>
- Inference Types
- InferAttributes\<T>
- FilterableAttributes\<T>
- Relationship Types
- HasMany\<T>
- HasOne\<T>
- BelongsTo\<T>
- Query Types
- QueryOperator
- QueryOptions\<T>
- WhereOptions\<T>
- IncludeRelationOptions
Attribute Marker Types¶
CreationOptional\<T>¶
Marks a field as optional during creation but present after saving. Use for fields with default values, auto-generated values, or auto-calculated values.
Syntax:
Characteristics: - Field is optional when calling Model.create() - Field is present in the instance after saving - Ideal for auto-generated IDs, timestamps, and default values
Examples:
import { Table, PrimaryKey, Default, CreatedAt, UpdatedAt, CreationOptional } from '@arcaelas/dynamite';
class User extends Table<User> {
// Auto-generated primary key
@PrimaryKey()
@Default(() => crypto.randomUUID())
declare id: CreationOptional<string>;
// Required field (no CreationOptional)
declare email: string;
// Field with default value
@Default(() => "customer")
declare role: CreationOptional<string>;
// Auto-set timestamps
@CreatedAt()
declare created_at: CreationOptional<string>;
@UpdatedAt()
declare updated_at: CreationOptional<string>;
}
// Only email is required during creation
const user = await User.create({
email: "john@example.com"
// id, role, created_at, updated_at are optional
});
// After creation, all fields are present
console.log(user.id); // "550e8400-e29b-..."
console.log(user.role); // "customer"
console.log(user.created_at); // "2025-01-15T10:30:00.000Z"
NonAttribute\<T>¶
Marks a field that is NOT stored in the database. Use for computed properties, relationships, and virtual getters.
Syntax:
Characteristics: - Field is excluded from database operations - Ideal for relationships and computed values - Does not appear in toJSON() unless explicitly added
Examples:
import { Table, HasMany, BelongsTo, NonAttribute } from '@arcaelas/dynamite';
class User extends Table<User> {
@PrimaryKey()
declare id: string;
declare name: string;
// Relationship - not stored in database
@HasMany(() => Order, "user_id")
declare orders: NonAttribute<Order[]>;
// Computed property
declare display_name: NonAttribute<string>;
}
class Order extends Table<Order> {
@PrimaryKey()
declare id: string;
declare user_id: string;
@BelongsTo(() => User, "user_id")
declare user: NonAttribute<User | null>;
}
Inference Types¶
InferAttributes\<T>¶
Extracts only the database attributes from a model, excluding methods, relationships, and non-attribute fields.
Usage:
import type { InferAttributes } from '@arcaelas/dynamite';
type UserAttributes = InferAttributes<User>;
// Result:
// {
// id: string;
// email: string;
// name: string;
// role: string;
// created_at: string;
// updated_at: string;
// }
Use Cases: - Type-safe function parameters - DTO (Data Transfer Object) definitions - API response types
Example:
import type { InferAttributes } from '@arcaelas/dynamite';
// Function with type-safe input
async function updateUser(
id: string,
data: Partial<InferAttributes<User>>
): Promise<User | undefined> {
const user = await User.first({ id });
if (user) {
await user.update(data);
}
return user;
}
// Usage
await updateUser("user-123", { name: "New Name", role: "admin" });
FilterableAttributes\<T>¶
Extracts only the filterable attributes (excludes relationships and non-attributes).
Usage:
import type { FilterableAttributes } from '@arcaelas/dynamite';
type UserFilters = FilterableAttributes<User>;
// Result: { id?: string; email?: string; name?: string; role?: string; ... }
Relationship Types¶
HasMany\<T>¶
Type for one-to-many relationships. Resolves to an array of the related model.
Syntax:
@HasMany(() => RelatedModel, "foreign_key")
declare relation_name: NonAttribute<HasMany<RelatedModel>>;
Characteristics: - Returns T[] (array of related records) - Empty array if no related records exist - Must be wrapped in NonAttribute<>
Example:
import { Table, HasMany, NonAttribute } from '@arcaelas/dynamite';
class User extends Table<User> {
@PrimaryKey()
declare id: string;
@HasMany(() => Post, "user_id")
declare posts: NonAttribute<HasMany<Post>>;
@HasMany(() => Comment, "user_id")
declare comments: NonAttribute<HasMany<Comment>>;
}
// Usage
const users = await User.where({}, {
include: { posts: true, comments: true }
});
users.forEach(user => {
console.log(`${user.name} has ${user.posts.length} posts`);
console.log(`${user.name} has ${user.comments.length} comments`);
});
HasOne\<T>¶
Type for one-to-one relationships. Resolves to a single related record or null.
Syntax:
@HasOne(() => RelatedModel, "foreign_key")
declare relation_name: NonAttribute<HasOne<RelatedModel>>;
Characteristics: - Returns T | null (single related record or null) - Only the first matching record is returned - Must be wrapped in NonAttribute<>
Example:
import { Table, HasOne, NonAttribute } from '@arcaelas/dynamite';
class User extends Table<User> {
@PrimaryKey()
declare id: string;
@HasOne(() => Profile, "user_id")
declare profile: NonAttribute<HasOne<Profile>>;
}
// Usage
const user = await User.first({ id: "user-123" }, {
include: { profile: true }
});
if (user?.profile) {
console.log(user.profile.bio);
}
BelongsTo\<T>¶
Type for many-to-one relationships. Resolves to a single parent record or null.
Syntax:
@BelongsTo(() => ParentModel, "local_foreign_key")
declare relation_name: NonAttribute<BelongsTo<ParentModel>>;
Characteristics: - Returns T | null (single parent record or null) - Requires a foreign key field in the model - Must be wrapped in NonAttribute<>
Example:
import { Table, BelongsTo, NonAttribute } from '@arcaelas/dynamite';
class Post extends Table<Post> {
@PrimaryKey()
declare id: string;
declare user_id: string; // Foreign key
@BelongsTo(() => User, "user_id")
declare author: NonAttribute<BelongsTo<User>>;
}
// Usage
const posts = await Post.where({}, {
include: { author: true }
});
posts.forEach(post => {
console.log(`${post.title} by ${post.author?.name || 'Unknown'}`);
});
Query Types¶
QueryOperator¶
Union type of all supported query operators.
Definition:
type QueryOperator =
| "="
| "!="
| "<"
| "<="
| ">"
| ">="
| "in"
| "not-in"
| "contains"
| "begins-with";
Usage:
// Equality
await User.where("role", "=", "admin");
// Comparison
await User.where("age", ">=", 18);
await User.where("balance", "<", 100);
// Array membership
await User.where("status", "in", ["active", "pending"]);
await User.where("role", "not-in", ["banned"]);
// String matching
await User.where("email", "contains", "@gmail.com");
await User.where("name", "begins-with", "John");
QueryOptions\<T>¶
Options for configuring query behavior.
Definition:
interface QueryOptions<T> {
order?: "ASC" | "DESC";
skip?: number;
limit?: number;
attributes?: (keyof InferAttributes<T>)[];
include?: Record<string, IncludeRelationOptions | boolean>;
}
Properties:
| Property | Type | Description |
|---|---|---|
order | "ASC" \| "DESC" | Sort order |
skip | number | Number of records to skip (offset) |
limit | number | Maximum records to return |
attributes | string[] | Specific fields to select |
include | object | Relationships to include |
Example:
const users = await User.where({ active: true }, {
order: "DESC",
skip: 20,
limit: 10,
attributes: ["id", "name", "email"],
include: {
orders: {
limit: 5,
order: "DESC"
}
}
});
WhereOptions\<T>¶
Extended options for where queries including relationship filtering.
Definition:
IncludeRelationOptions¶
Options for configuring included relationships.
Definition:
interface IncludeRelationOptions {
where?: Record<string, any>;
attributes?: string[];
order?: "ASC" | "DESC";
skip?: number;
limit?: number;
include?: Record<string, IncludeRelationOptions | boolean>;
}
Properties:
| Property | Type | Description |
|---|---|---|
where | object | Filters for related records |
attributes | string[] | Specific fields to select |
order | "ASC" \| "DESC" | Sort order for related records |
skip | number | Skip N related records |
limit | number | Limit related records |
include | object | Nested relationships |
Example:
const users = await User.where({}, {
include: {
orders: {
where: { status: "completed" },
attributes: ["id", "total", "created_at"],
order: "DESC",
limit: 10,
include: {
items: {
include: {
product: true
}
}
}
}
}
});
Best Practices¶
1. Always Use CreationOptional for Fields with Defaults¶
// Good
@Default(() => "active")
declare status: CreationOptional<string>;
// Bad - TypeScript will require status in create()
@Default(() => "active")
declare status: string;
2. Always Wrap Relationships in NonAttribute¶
// Good
@HasMany(() => Post, "user_id")
declare posts: NonAttribute<HasMany<Post>>;
// Bad - posts would be treated as a database column
@HasMany(() => Post, "user_id")
declare posts: Post[];
3. Use InferAttributes for Type-Safe Functions¶
// Good - type-safe parameter
function processUser(data: InferAttributes<User>) { ... }
// Bad - no type safety
function processUser(data: any) { ... }
4. Define Foreign Keys Explicitly¶
// Good - foreign key is declared
class Post extends Table<Post> {
declare user_id: string; // FK field
@BelongsTo(() => User, "user_id")
declare author: NonAttribute<BelongsTo<User>>;
}
// Bad - foreign key not declared
class Post extends Table<Post> {
@BelongsTo(() => User, "user_id")
declare author: NonAttribute<BelongsTo<User>>;
}