or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-source.mdentity-definition.mdentity-schema.mdevents.mdfind-options.mdindex.mdmigrations.mdquery-builder.mdrelationships.mdrepository.md

entity-schema.mddocs/

0

# Entity Schema (Code-First)

1

2

Code-first entity definition system allowing dynamic entity creation without decorators, ideal for runtime schema generation and applications where entity structure is determined at runtime.

3

4

## Capabilities

5

6

### EntitySchema Class

7

8

Core class for defining entities programmatically without using decorator syntax.

9

10

```typescript { .api }

11

/**

12

* Programmatic entity definition without decorators

13

* @template T - Entity type

14

*/

15

class EntitySchema<T = any> {

16

/**

17

* Creates new entity schema

18

* @param options - Schema definition options

19

*/

20

constructor(options: EntitySchemaOptions<T>);

21

22

/** Schema configuration options */

23

readonly options: EntitySchemaOptions<T>;

24

}

25

26

/**

27

* Configuration options for entity schema

28

*/

29

interface EntitySchemaOptions<T> {

30

/** Entity name */

31

name: string;

32

33

/** Target constructor function (optional) */

34

target?: Function;

35

36

/** Database table name */

37

tableName?: string;

38

39

/** Database name */

40

database?: string;

41

42

/** Schema name */

43

schema?: string;

44

45

/** Column definitions */

46

columns: { [P in keyof T]: EntitySchemaColumnOptions };

47

48

/** Relation definitions */

49

relations?: { [key: string]: EntitySchemaRelationOptions };

50

51

/** Index definitions */

52

indices?: EntitySchemaIndexOptions[];

53

54

/** Unique constraint definitions */

55

uniques?: EntitySchemaUniqueOptions[];

56

57

/** Check constraint definitions */

58

checks?: EntitySchemaCheckOptions[];

59

60

/** Exclusion constraint definitions */

61

exclusions?: EntitySchemaExclusionOptions[];

62

63

/** Table inheritance configuration */

64

inheritancePattern?: "STI" | "CTI";

65

66

/** Discriminator column (for STI) */

67

discriminatorColumn?: string;

68

69

/** Default ordering */

70

orderBy?: Record<string, "ASC" | "DESC">;

71

72

/** Table engine (MySQL) */

73

engine?: string;

74

75

/** Synchronization flag */

76

synchronize?: boolean;

77

}

78

```

79

80

### Column Schema Options

81

82

Detailed column configuration for entity schemas.

83

84

```typescript { .api }

85

/**

86

* Column definition options for entity schema

87

*/

88

interface EntitySchemaColumnOptions {

89

/** Column database type */

90

type: ColumnType;

91

92

/** Column name in database */

93

name?: string;

94

95

/** Column length (for string types) */

96

length?: string | number;

97

98

/** Column precision (for decimal types) */

99

precision?: number;

100

101

/** Column scale (for decimal types) */

102

scale?: number;

103

104

/** Whether column allows NULL */

105

nullable?: boolean;

106

107

/** Default column value */

108

default?: any;

109

110

/** Whether column is primary key */

111

primary?: boolean;

112

113

/** Whether column is unique */

114

unique?: boolean;

115

116

/** Column comment */

117

comment?: string;

118

119

/** Whether column is generated */

120

generated?: true | "increment" | "uuid" | "rowid";

121

122

/** Whether column is select by default */

123

select?: boolean;

124

125

/** Whether column participates in inserts */

126

insert?: boolean;

127

128

/** Whether column participates in updates */

129

update?: boolean;

130

131

/** Column collation */

132

collation?: string;

133

134

/** Column charset */

135

charset?: string;

136

137

/** Value transformer */

138

transformer?: ValueTransformer | ValueTransformer[];

139

140

/** Array type indicator (PostgreSQL) */

141

array?: boolean;

142

143

/** Enum values */

144

enum?: Object | (string | number)[];

145

146

/** Spatial type indicator */

147

spatialFeatureType?: string;

148

149

/** SRID for spatial types */

150

srid?: number;

151

152

/** Creation date column */

153

createDate?: boolean;

154

155

/** Update date column */

156

updateDate?: boolean;

157

158

/** Delete date column (soft delete) */

159

deleteDate?: boolean;

160

161

/** Version column */

162

version?: boolean;

163

164

/** Tree level column */

165

treeLevel?: boolean;

166

167

/** Tree parent column */

168

treeParent?: boolean;

169

170

/** Tree children relation */

171

treeChildren?: boolean;

172

}

173

174

/**

175

* Value transformer interface for column serialization

176

*/

177

interface ValueTransformer {

178

/**

179

* Transforms value from entity to database

180

* @param value - Entity value

181

* @returns Database value

182

*/

183

to(value: any): any;

184

185

/**

186

* Transforms value from database to entity

187

* @param value - Database value

188

* @returns Entity value

189

*/

190

from(value: any): any;

191

}

192

```

193

194

### Relation Schema Options

195

196

Configuration for relationships in entity schemas.

197

198

```typescript { .api }

199

/**

200

* Relation definition options for entity schema

201

*/

202

interface EntitySchemaRelationOptions {

203

/** Relation type */

204

type: "one-to-one" | "one-to-many" | "many-to-one" | "many-to-many";

205

206

/** Target entity */

207

target: string | Function;

208

209

/** Inverse side property */

210

inverseSide?: string;

211

212

/** Whether relation is eager loaded */

213

eager?: boolean;

214

215

/** Cascade options */

216

cascade?: boolean | ("insert" | "update" | "remove" | "soft-remove" | "recover")[];

217

218

/** Whether relation is nullable */

219

nullable?: boolean;

220

221

/** Foreign key constraint name */

222

foreignKeyConstraintName?: string;

223

224

/** Create foreign key constraints */

225

createForeignKeyConstraints?: boolean;

226

227

/** Join column options */

228

joinColumn?: EntitySchemaJoinColumnOptions | EntitySchemaJoinColumnOptions[];

229

230

/** Join table options */

231

joinTable?: EntitySchemaJoinTableOptions;

232

233

/** Default ordering for relation */

234

orderBy?: Record<string, "ASC" | "DESC">;

235

236

/** Persistence enabled */

237

persistence?: boolean;

238

239

/** Primary relation indicator */

240

primary?: boolean;

241

}

242

243

/**

244

* Join column configuration for relations

245

*/

246

interface EntitySchemaJoinColumnOptions {

247

/** Join column name */

248

name?: string;

249

250

/** Referenced column name */

251

referencedColumnName?: string;

252

253

/** Foreign key constraint name */

254

foreignKeyConstraintName?: string;

255

}

256

257

/**

258

* Join table configuration for many-to-many relations

259

*/

260

interface EntitySchemaJoinTableOptions {

261

/** Join table name */

262

name?: string;

263

264

/** Database name */

265

database?: string;

266

267

/** Schema name */

268

schema?: string;

269

270

/** Join column (owner side) */

271

joinColumn?: EntitySchemaJoinColumnOptions;

272

273

/** Inverse join column */

274

inverseJoinColumn?: EntitySchemaJoinColumnOptions;

275

}

276

```

277

278

### Index and Constraint Options

279

280

Schema definitions for indexes and constraints.

281

282

```typescript { .api }

283

/**

284

* Index definition options for entity schema

285

*/

286

interface EntitySchemaIndexOptions {

287

/** Index name */

288

name?: string;

289

290

/** Indexed column names */

291

columns: string[];

292

293

/** Whether index is unique */

294

unique?: boolean;

295

296

/** Whether index is spatial (MySQL) */

297

spatial?: boolean;

298

299

/** Whether index is fulltext (MySQL) */

300

fulltext?: boolean;

301

302

/** Index method (PostgreSQL) */

303

using?: string;

304

305

/** Partial index condition (PostgreSQL) */

306

where?: string;

307

308

/** Whether to synchronize */

309

synchronize?: boolean;

310

}

311

312

/**

313

* Unique constraint definition options

314

*/

315

interface EntitySchemaUniqueOptions {

316

/** Constraint name */

317

name?: string;

318

319

/** Column names for unique constraint */

320

columns: string[];

321

}

322

323

/**

324

* Check constraint definition options

325

*/

326

interface EntitySchemaCheckOptions {

327

/** Constraint name */

328

name: string;

329

330

/** Check expression */

331

expression: string;

332

}

333

334

/**

335

* Exclusion constraint definition options (PostgreSQL)

336

*/

337

interface EntitySchemaExclusionOptions {

338

/** Constraint name */

339

name?: string;

340

341

/** Exclusion expression */

342

expression: string;

343

}

344

```

345

346

**Entity Schema Examples:**

347

348

```typescript

349

import { EntitySchema } from "typeorm";

350

351

// Define User entity without decorators

352

interface User {

353

id: number;

354

name: string;

355

email: string;

356

createdAt: Date;

357

updatedAt: Date;

358

posts: Post[];

359

profile: Profile;

360

}

361

362

export const UserSchema = new EntitySchema<User>({

363

name: "User",

364

tableName: "users",

365

columns: {

366

id: {

367

type: "int",

368

primary: true,

369

generated: "increment"

370

},

371

name: {

372

type: "varchar",

373

length: 100,

374

nullable: false

375

},

376

email: {

377

type: "varchar",

378

length: 255,

379

unique: true,

380

nullable: false

381

},

382

createdAt: {

383

type: "timestamp",

384

createDate: true

385

},

386

updatedAt: {

387

type: "timestamp",

388

updateDate: true

389

}

390

},

391

relations: {

392

posts: {

393

type: "one-to-many",

394

target: "Post",

395

inverseSide: "author",

396

cascade: ["insert", "update"]

397

},

398

profile: {

399

type: "one-to-one",

400

target: "Profile",

401

joinColumn: {

402

name: "profile_id",

403

referencedColumnName: "id"

404

},

405

cascade: true,

406

eager: true

407

}

408

},

409

indices: [

410

{

411

name: "IDX_USER_EMAIL",

412

columns: ["email"],

413

unique: true

414

},

415

{

416

name: "IDX_USER_NAME",

417

columns: ["name"]

418

}

419

],

420

uniques: [

421

{

422

name: "UQ_USER_EMAIL",

423

columns: ["email"]

424

}

425

],

426

checks: [

427

{

428

name: "CHK_USER_NAME_NOT_EMPTY",

429

expression: "LENGTH(name) > 0"

430

}

431

]

432

});

433

434

// Define Post entity

435

interface Post {

436

id: number;

437

title: string;

438

content: string;

439

publishedAt: Date | null;

440

author: User;

441

tags: Tag[];

442

}

443

444

export const PostSchema = new EntitySchema<Post>({

445

name: "Post",

446

tableName: "posts",

447

columns: {

448

id: {

449

type: "int",

450

primary: true,

451

generated: "increment"

452

},

453

title: {

454

type: "varchar",

455

length: 255,

456

nullable: false

457

},

458

content: {

459

type: "text",

460

nullable: false

461

},

462

publishedAt: {

463

type: "timestamp",

464

nullable: true

465

}

466

},

467

relations: {

468

author: {

469

type: "many-to-one",

470

target: "User",

471

inverseSide: "posts",

472

joinColumn: {

473

name: "author_id"

474

},

475

nullable: false

476

},

477

tags: {

478

type: "many-to-many",

479

target: "Tag",

480

joinTable: {

481

name: "post_tags",

482

joinColumn: { name: "post_id" },

483

inverseJoinColumn: { name: "tag_id" }

484

},

485

cascade: true

486

}

487

},

488

orderBy: {

489

publishedAt: "DESC"

490

}

491

});

492

```

493

494

### Dynamic Schema Generation

495

496

Create entity schemas dynamically at runtime:

497

498

```typescript

499

function createDynamicEntitySchema(

500

name: string,

501

fields: Array<{

502

name: string;

503

type: string;

504

required: boolean;

505

unique?: boolean;

506

}>

507

): EntitySchema {

508

const columns: any = {};

509

510

// Always include ID field

511

columns.id = {

512

type: "int",

513

primary: true,

514

generated: "increment"

515

};

516

517

// Add dynamic fields

518

fields.forEach(field => {

519

columns[field.name] = {

520

type: field.type,

521

nullable: !field.required,

522

unique: field.unique || false

523

};

524

});

525

526

// Add audit fields

527

columns.createdAt = {

528

type: "timestamp",

529

createDate: true

530

};

531

532

columns.updatedAt = {

533

type: "timestamp",

534

updateDate: true

535

};

536

537

return new EntitySchema({

538

name,

539

tableName: name.toLowerCase() + 's',

540

columns

541

});

542

}

543

544

// Usage

545

const ProductSchema = createDynamicEntitySchema('Product', [

546

{ name: 'name', type: 'varchar', required: true },

547

{ name: 'description', type: 'text', required: false },

548

{ name: 'price', type: 'decimal', required: true },

549

{ name: 'sku', type: 'varchar', required: true, unique: true }

550

]);

551

```

552

553

### Mixed Entity Definitions

554

555

Use entity schemas alongside decorator-based entities:

556

557

```typescript

558

// Traditional decorator approach

559

@Entity()

560

export class Category {

561

@PrimaryGeneratedColumn()

562

id: number;

563

564

@Column()

565

name: string;

566

567

@OneToMany(() => Product, product => product.category)

568

products: Product[];

569

}

570

571

// Schema-based approach

572

interface Product {

573

id: number;

574

name: string;

575

price: number;

576

category: Category;

577

}

578

579

export const ProductSchema = new EntitySchema<Product>({

580

name: "Product",

581

columns: {

582

id: { type: "int", primary: true, generated: "increment" },

583

name: { type: "varchar", length: 255 },

584

price: { type: "decimal", precision: 10, scale: 2 }

585

},

586

relations: {

587

category: {

588

type: "many-to-one",

589

target: Category, // Reference decorator-based entity

590

inverseSide: "products"

591

}

592

}

593

});

594

595

// Use both in DataSource

596

const dataSource = new DataSource({

597

// ...

598

entities: [Category, ProductSchema]

599

});

600

```

601

602

## Use Cases

603

604

Entity schemas are ideal for:

605

606

- **Dynamic applications** where entity structure is determined at runtime

607

- **Multi-tenant applications** with varying schemas per tenant

608

- **Configuration-driven systems** where entities are defined in external configuration

609

- **Legacy integration** where decorator modification is not possible

610

- **Code generation** where entities are generated from external sources

611

612

## Migration from Decorators

613

614

Convert decorator-based entities to schemas:

615

616

```typescript

617

// Before: Decorator-based

618

@Entity("users")

619

export class User {

620

@PrimaryGeneratedColumn()

621

id: number;

622

623

@Column({ unique: true })

624

email: string;

625

626

@OneToMany(() => Post, post => post.author)

627

posts: Post[];

628

}

629

630

// After: Schema-based

631

export const UserSchema = new EntitySchema<User>({

632

name: "User",

633

tableName: "users",

634

columns: {

635

id: { type: "int", primary: true, generated: "increment" },

636

email: { type: "varchar", unique: true }

637

},

638

relations: {

639

posts: {

640

type: "one-to-many",

641

target: "Post",

642

inverseSide: "author"

643

}

644

}

645

});

646

```