Skip to main content

Model Embedding

Model embedding in Hysteria ORM allows you to attach models directly to a SQL data source instance, providing a convenient way to access your models through the data source. This feature is similar to Prisma's client model access pattern.

Overview

When you embed models in a SQL data source instance, they become available as properties on the data source object, allowing you to access them directly without importing the model classes separately.

Basic Usage

Connecting with Embedded Models

import { SqlDataSource } from "hysteria-orm";
import { User } from "./models/User";
import { Post } from "./models/Post";

// Connect with embedded models
const sql = await SqlDataSource.connect({
models: {
user: User,
post: Post,
},
});

// Access models directly through the data source
const users = await sql.user.query().many();
const posts = await sql.post.query().many();

Using with Secondary Connections

// Create a secondary connection with embedded models
const anotherSql = await SqlDataSource.connectToSecondarySource({
models: {
user: User,
post: Post,
},
});

// Use the embedded models with the specific connection
const user = await anotherSql.user.insert(
{ name: "John Doe" },
{ useConnection: anotherSql }
);

Using with Temporary Connections

await SqlDataSource.useConnection(
{
type: "postgres",
host: "localhost",
port: 5432,
username: "user",
password: "password",
database: "mydb",
models: {
user: User,
post: Post,
},
},
async (sql) => {
const user = await sql.user.insert({ name: "John Doe" });
const posts = await sql.post.query().many();
}
);

TypeScript Support

For proper TypeScript support when using embedded models, use the AugmentedSqlDataSource type:

import { AugmentedSqlDataSource } from "hysteria-orm";
import { User } from "./models/User";
import { Post } from "./models/Post";

let sql: AugmentedSqlDataSource<{
user: typeof User;
post: typeof Post;
}>;

beforeAll(async () => {
sql = await SqlDataSource.connect({
models: {
user: User,
post: Post,
},
});
});

Error Handling

Duplicate Model Keys

The most common error occurs when you try to use a model key that conflicts with existing SqlDataSource properties or methods. The following will throw a HysteriaError:

// ❌ This will throw an error - 'connect' is a reserved method
await SqlDataSource.connect({
models: {
connect: User, // Error: Duplicate model keys while instantiating models
},
});

// ❌ This will also throw an error - 'query' is a reserved method
await SqlDataSource.connect({
models: {
query: User, // Error: Duplicate model keys while instantiating models
},
});

// ✅ This works correctly
await SqlDataSource.connect({
models: {
user: User,
post: Post,
},
});

Reserved Keywords

The following keywords are reserved and cannot be used as model keys:

  • connect
  • query
  • disconnect
  • startGlobalTransaction
  • commitGlobalTransaction
  • rollbackGlobalTransaction
  • closeConnection
  • isConnected
  • getDbType
  • rawQuery
  • useConnection
  • connectToSecondarySource

Important Notes

Static Singleton Connection Limitation

Important: Model embedding is not available with the static singleton connection pattern. You must use a SQL data source instance to embed models.

// ❌ This does NOT support model embedding
import { sql } from "hysteria-orm";
await sql.connect();
// Models are not embedded in the global sql instance

// ✅ This supports model embedding
const sqlInstance = await SqlDataSource.connect({
models: {
user: User,
post: Post,
},
});
// Models are embedded in sqlInstance

Model Independence

Embedded models can still be used as standalone entities. Embedding them in a data source instance is optional and provides convenience but doesn't change their core functionality.

// Models work both ways
const sql = await SqlDataSource.connect({
models: { user: User },
});

// Using embedded model
const user1 = await sql.user.query().first();

// Using standalone model (still works)
const user2 = await User.query().first();

Best Practices

  1. Use descriptive model keys: Choose meaningful names for your model keys that reflect the model's purpose.

  2. Type your data sources: Always use AugmentedSqlDataSource<T> for proper TypeScript support when embedding models.

  3. Avoid reserved keywords: Check that your model keys don't conflict with SqlDataSource methods or properties.

  4. Consider connection scope: Use embedded models when you need model access within a specific connection context.

  5. Error handling: Always handle potential HysteriaError exceptions when connecting with embedded models.