ื“ืœื’ ืœืชื•ื›ืŸ ื”ืจืืฉื™

Multi-ORM Deep Dive

Writing queries that work across TypeORM and MikroORM in Ever Gauzy.

Why Multi-ORM?โ€‹

Gauzy supports both TypeORM and MikroORM through the MultiORM decorator system. This allows:

  • TypeORM โ€” mature, widely used, great for PostgreSQL
  • MikroORM โ€” modern, identity map, unit-of-work pattern

The active ORM is determined by the DB_ORM environment variable.

Entity Decoratorsโ€‹

MultiORMEntityโ€‹

@MultiORMEntity("employee", {
mikroOrmRepository: () => MikroOrmEmployeeRepository,
})
export class Employee extends TenantOrganizationBaseEntity {
@MultiORMColumn()
name: string;

@MultiORMColumn({ nullable: true })
description?: string;
}

Relation Decoratorsโ€‹

// Many-to-One
@MultiORMManyToOne(() => Organization, { nullable: true })
@JoinColumn()
organization?: Organization;

// One-to-Many
@MultiORMOneToMany(() => Task, (task) => task.creator)
createdTasks?: Task[];

// Many-to-Many
@MultiORMManyToMany(() => Tag, (tag) => tag.employees)
tags?: Tag[];

Query Patternsโ€‹

Using CrudServiceโ€‹

Most queries go through TenantAwareCrudService:

// Find all with filters
const result = await this.service.findAll({
where: { status: "active" },
relations: ["user", "teams"],
order: { createdAt: "DESC" },
});

// Find one by ID
const employee = await this.service.findOneByIdString(id, {
relations: ["user"],
});

Repository Patternโ€‹

For complex queries, inject repositories:

@Injectable()
export class MyService {
constructor(
@InjectRepository(MyEntity)
private readonly repository: Repository<MyEntity>,
) {}
}

Conditional ORM Logicโ€‹

When you need ORM-specific behavior:

if (isTypeORM()) {
// TypeORM-specific query builder
const qb = this.repository.createQueryBuilder("entity");
} else {
// MikroORM-specific entity manager
const em = this.entityManager;
}