or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mddata-operations.mddatabase-adapters.mdentity-modeling.mdindex.mdsql-conditions.md

configuration.mddocs/

0

# Configuration

1

2

Database configuration, schema updates, and utility functions for entity management and persistence. HibernateTS provides comprehensive configuration options for database schema management, automatic change tracking, and entity lifecycle management.

3

4

## Capabilities

5

6

### Database Schema Updates

7

8

Automatic database schema synchronization based on entity model definitions.

9

10

```typescript { .api }

11

/**

12

* Updates database schema to match model definitions

13

* @param modelRootPath - Path to directory containing model files

14

* @param opts - Update options including database configuration

15

* @returns Promise that resolves when schema update is complete

16

*/

17

function updateDatabase(modelRootPath: string, opts?: UpdateOpts): Promise<void>;

18

19

interface UpdateOpts {

20

/** Database adapter class (constructor) for creating connections */

21

dbPoolGEnerator?: DataBaseBaseStatic;

22

/** Database name to update schema for */

23

modelDb?: string;

24

}

25

26

interface DataBaseBaseStatic {

27

new(...args: any[]): DataBaseBase;

28

}

29

```

30

31

**Usage Examples:**

32

33

```typescript

34

import { updateDatabase, MariaDbBase } from "hibernatets";

35

import path from "path";

36

37

// Basic schema update

38

await updateDatabase(path.join(__dirname, "models"));

39

40

// Schema update with custom database adapter

41

await updateDatabase(path.join(__dirname, "models"), {

42

dbPoolGEnerator: MariaDbBase

43

});

44

45

// Schema update with specific database name

46

await updateDatabase(path.join(__dirname, "models"), {

47

modelDb: "my_custom_database"

48

});

49

50

// Automated schema update in application startup

51

async function initializeApplication() {

52

try {

53

console.log("Updating database schema...");

54

await updateDatabase("./src/entities");

55

console.log("Database schema updated successfully");

56

} catch (error) {

57

console.error("Schema update failed:", error);

58

process.exit(1);

59

}

60

}

61

```

62

63

### Change Tracking and Interception

64

65

Automatic property change tracking and database synchronization.

66

67

```typescript { .api }

68

/**

69

* Intercepts property setters to automatically trigger database updates

70

* @param object - Entity instance to intercept

71

* @param opts - Interception configuration options

72

*/

73

function intercept<T>(object: T, opts?: InterceptParams): void;

74

75

interface InterceptParams {

76

/** Enable interception of array methods like push/filter */

77

interceptArrayFunctions?: boolean;

78

/** Database connection to use for updates */

79

db?: DataBaseBase;

80

}

81

```

82

83

**Usage Examples:**

84

85

```typescript

86

import { intercept, load, queries } from "hibernatets";

87

88

// Basic property interception

89

const user = await load(User, 1);

90

intercept(user);

91

92

// Changes are automatically tracked

93

user.name = "Updated Name";

94

user.email = "new@example.com";

95

96

// Execute all pending updates

97

await queries(user);

98

99

// Interception with array function tracking

100

const userWithPosts = await load(User, 1, [], { deep: true });

101

intercept(userWithPosts, {

102

interceptArrayFunctions: true

103

});

104

105

// Array operations are tracked

106

userWithPosts.posts.push(new Post());

107

userWithPosts.posts[0].title = "Updated Title";

108

109

// All changes are persisted

110

await queries(userWithPosts);

111

```

112

113

### Entity Utility Functions

114

115

Core utility functions for working with entities and their database representations.

116

117

```typescript { .api }

118

/**

119

* Gets the primary key value of an entity

120

* @param object - Entity instance

121

* @returns Primary key value

122

*/

123

function getId(object: any): number;

124

125

/**

126

* Sets the primary key value of an entity

127

* @param object - Entity instance

128

* @param id - New primary key value

129

*/

130

function setId(object: any, id: number): void;

131

132

/**

133

* Checks if an entity is persisted to database

134

* @param object - Entity instance

135

* @returns True if entity exists in database

136

*/

137

function isPersisted(object: any): boolean;

138

139

/**

140

* Gets database configuration for an entity or constructor

141

* @param obj - Entity instance or constructor

142

* @returns Database configuration object

143

*/

144

function getDBConfig<TableClass = any>(obj: ISaveAbleObject | ConstructorClass<TableClass> | TableClass): DataBaseConfig<TableClass>;

145

146

/**

147

* Gets database representation of an entity for storage

148

* @param object - Entity instance

149

* @returns Object with database column mappings

150

*/

151

function getRepresentation(object: any): { [key: string]: unknown };

152

```

153

154

**Usage Examples:**

155

156

```typescript

157

import {

158

getId, setId, isPersisted,

159

getDBConfig, getRepresentation,

160

load, save

161

} from "hibernatets";

162

163

// Working with entity IDs

164

const user = new User();

165

user.name = "Alice";

166

167

console.log(getId(user)); // undefined (not persisted yet)

168

console.log(isPersisted(user)); // false

169

170

await save(user);

171

console.log(getId(user)); // 123 (assigned after save)

172

console.log(isPersisted(user)); // true

173

174

// Manual ID assignment

175

const newUser = new User();

176

setId(newUser, 999);

177

newUser.name = "Bob";

178

179

// Get database configuration

180

const config = getDBConfig(User);

181

console.log("Table name:", config.table);

182

console.log("Primary key:", config.modelPrimary);

183

console.log("Columns:", Object.keys(config.columns));

184

185

// Get database representation

186

const dbRepresentation = getRepresentation(user);

187

console.log("DB data:", dbRepresentation);

188

// Output: { id: 123, name: "Alice", email: "alice@example.com", ... }

189

```

190

191

### Update Management

192

193

Advanced update tracking and batch processing for entity changes.

194

195

```typescript { .api }

196

/**

197

* Adds a pending database update to an entity's update queue

198

* @param obj - Entity instance

199

* @param update - Update operation to queue

200

*/

201

function pushUpdate(obj: any, update: any): void;

202

203

/**

204

* Updates a specific property of an entity in the database

205

* @param object - Entity instance

206

* @param key - Property key to update

207

* @param value - New value for the property

208

* @param opts - Update options

209

* @returns Promise resolving to number of affected rows

210

*/

211

function update(object: any, key: string, value: any, opts?: any): Promise<number>;

212

```

213

214

**Usage Examples:**

215

216

```typescript

217

import { pushUpdate, update, queries, load } from "hibernatets";

218

219

// Manual update queuing

220

const user = await load(User, 1);

221

222

// Queue multiple updates

223

pushUpdate(user, { field: "name", value: "New Name" });

224

pushUpdate(user, { field: "email", value: "new@email.com" });

225

226

// Execute all queued updates

227

await queries(user);

228

229

// Direct property update

230

const affectedRows = await update(user, "lastLogin", new Date());

231

console.log(`Updated ${affectedRows} rows`);

232

233

// Batch property updates

234

async function batchUpdateUser(userId: number, updates: Record<string, any>) {

235

const user = await load(User, userId);

236

237

for (const [key, value] of Object.entries(updates)) {

238

await update(user, key, value);

239

}

240

241

return user;

242

}

243

244

const updatedUser = await batchUpdateUser(123, {

245

name: "Alice Smith",

246

email: "alice.smith@example.com",

247

lastLogin: new Date()

248

});

249

```

250

251

### Database Configuration Class

252

253

Complete database configuration management for entities.

254

255

```typescript { .api }

256

/**

257

* Configuration class for entity database mapping

258

*/

259

interface DataBaseConfig<T> {

260

/** Primary key field name */

261

modelPrimary: string;

262

/** Database table name */

263

table: string;

264

/** Column definitions mapped by property name */

265

columns: { [key: string]: ColumnDefinition<any> };

266

/** Table-level options */

267

options: any;

268

/** Reference key field name */

269

referenceKey: string;

270

271

/**

272

* Creates new instance of the entity

273

* @returns New entity instance

274

*/

275

createInstance(): T;

276

}

277

278

/**

279

* Individual column configuration

280

*/

281

interface ColumnDefinition<K> {

282

/** Property name in the model class */

283

modelName: string;

284

/** Corresponding column name in database */

285

dbTableName: string;

286

/** Relationship mapping configuration */

287

mapping?: any;

288

/** Inverse relationship definitions */

289

inverseMappingDef?: any;

290

/** Primary key generation strategy */

291

primaryType?: "auto-increment" | "custom";

292

/** Column-specific options */

293

opts?: any;

294

}

295

```

296

297

**Usage Examples:**

298

299

```typescript

300

import { getDBConfig } from "hibernatets";

301

302

@table({ name: "user_accounts" })

303

class User {

304

@primary()

305

id: number;

306

307

@column()

308

name: string;

309

310

@mapping(Mappings.OneToMany, Post, "userId")

311

posts: Post[];

312

}

313

314

// Access complete configuration

315

const userConfig = getDBConfig(User);

316

317

console.log("Configuration details:");

318

console.log("- Table:", userConfig.table); // "user_accounts"

319

console.log("- Primary key:", userConfig.modelPrimary); // "id"

320

console.log("- Reference key:", userConfig.referenceKey); // "id"

321

322

// Inspect column configurations

323

Object.entries(userConfig.columns).forEach(([propName, columnDef]) => {

324

console.log(`Column ${propName}:`, {

325

dbName: columnDef.dbTableName,

326

hasMapping: !!columnDef.mapping,

327

isPrimary: !!columnDef.primaryType

328

});

329

});

330

331

// Create new instance using configuration

332

const newUser = userConfig.createInstance();

333

console.log("New instance:", newUser); // Empty User instance

334

```

335

336

### Type Utilities

337

338

Type-safe utilities for working with entity objects and their properties.

339

340

```typescript { .api }

341

/**

342

* Type-safe Object.values() implementation

343

* @param obj - Object to extract values from

344

* @returns Array of object values with preserved typing

345

*/

346

function objectValues<T>(obj: T): Array<T[keyof T]>;

347

348

/**

349

* Custom utility type for omitting keys from objects

350

*/

351

type CustomOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

352

```

353

354

**Usage Examples:**

355

356

```typescript

357

import { objectValues } from "hibernatets";

358

359

interface UserData {

360

id: number;

361

name: string;

362

email: string;

363

}

364

365

const userData: UserData = {

366

id: 1,

367

name: "Alice",

368

email: "alice@example.com"

369

};

370

371

// Type-safe value extraction

372

const values = objectValues(userData);

373

// Type: (string | number)[]

374

// Value: [1, "Alice", "alice@example.com"]

375

376

// Usage with entity configurations

377

const config = getDBConfig(User);

378

const columnDefs = objectValues(config.columns);

379

// Type: ColumnDefinition<any>[]

380

381

// Iterate with type safety

382

columnDefs.forEach(column => {

383

console.log(`Column: ${column.modelName} -> ${column.dbTableName}`);

384

});

385

```

386

387

### Advanced Configuration Patterns

388

389

Complex configuration scenarios and best practices for application setup.

390

391

```typescript

392

import {

393

updateDatabase, intercept, getDBConfig,

394

MariaDbBase, withMariaDbPool, setMariaDbPoolDefaults

395

} from "hibernatets";

396

import path from "path";

397

398

// Application configuration manager

399

class HibernateTSConfig {

400

private static initialized = false;

401

private static modelPaths: string[] = [];

402

403

static async initialize(options: {

404

modelPaths: string[];

405

autoSchema?: boolean;

406

dbPoolGenerator?: DataBaseBaseStatic;

407

interceptByDefault?: boolean;

408

}) {

409

if (this.initialized) return;

410

411

this.modelPaths = options.modelPaths;

412

413

// Set up database defaults

414

if (options.dbPoolGenerator) {

415

setMariaDbPoolDefaults({

416

connectionLimit: 20,

417

minimumIdle: 5,

418

idleTimeout: 300000

419

});

420

}

421

422

// Update database schema if requested

423

if (options.autoSchema !== false) {

424

for (const modelPath of options.modelPaths) {

425

await updateDatabase(modelPath, {

426

dbPoolGEnerator: options.dbPoolGenerator

427

});

428

}

429

}

430

431

this.initialized = true;

432

console.log("HibernateTS configuration initialized");

433

}

434

435

static createEntityWithDefaults<T>(

436

EntityClass: new () => T,

437

data: Partial<T>,

438

options: { enableInterception?: boolean } = {}

439

): T {

440

const entity = Object.assign(new EntityClass(), data);

441

442

if (options.enableInterception !== false) {

443

intercept(entity, {

444

interceptArrayFunctions: true

445

});

446

}

447

448

return entity;

449

}

450

451

static async validateEntityConfiguration<T>(

452

EntityClass: new () => T

453

): Promise<boolean> {

454

try {

455

const config = getDBConfig(EntityClass);

456

457

// Validate basic configuration

458

if (!config.table || !config.modelPrimary) {

459

throw new Error("Missing table or primary key configuration");

460

}

461

462

// Validate columns

463

if (Object.keys(config.columns).length === 0) {

464

throw new Error("No columns configured");

465

}

466

467

// Test instance creation

468

const instance = config.createInstance();

469

if (!instance) {

470

throw new Error("Cannot create entity instance");

471

}

472

473

return true;

474

} catch (error) {

475

console.error(`Entity validation failed:`, error);

476

return false;

477

}

478

}

479

480

static getModelSummary() {

481

// This would typically iterate through loaded models

482

return {

483

initialized: this.initialized,

484

modelPaths: this.modelPaths,

485

loadedModels: [] // Would be populated with actual model information

486

};

487

}

488

}

489

490

// Usage example

491

async function setupApplication() {

492

await HibernateTSConfig.initialize({

493

modelPaths: [

494

path.join(__dirname, "entities"),

495

path.join(__dirname, "models")

496

],

497

autoSchema: true,

498

dbPoolGenerator: MariaDbBase,

499

interceptByDefault: true

500

});

501

502

// Validate entity configurations

503

const isUserValid = await HibernateTSConfig.validateEntityConfiguration(User);

504

const isPostValid = await HibernateTSConfig.validateEntityConfiguration(Post);

505

506

if (!isUserValid || !isPostValid) {

507

throw new Error("Entity configuration validation failed");

508

}

509

510

console.log("Application setup complete");

511

}

512

```

513

514

### Error Handling

515

516

Enhanced error handling and debugging utilities for database operations.

517

518

```typescript { .api }

519

/**

520

* Enhanced Error class with cause chain support

521

*/

522

class Exception extends Error {

523

/**

524

* Creates exception with nested error information

525

* @param message - Error message

526

* @param error - Underlying error that caused this exception

527

*/

528

constructor(message: string, error: Error);

529

}

530

```

531

532

**Usage Examples:**

533

534

```typescript

535

import { Exception, load, save } from "hibernatets";

536

537

// Error handling with context

538

async function safeDatabaseOperation<T>(

539

operation: () => Promise<T>,

540

context: string

541

): Promise<T> {

542

try {

543

return await operation();

544

} catch (error) {

545

throw new Exception(

546

`Database operation failed in ${context}`,

547

error as Error

548

);

549

}

550

}

551

552

// Usage with comprehensive error context

553

try {

554

const user = await safeDatabaseOperation(

555

() => load(User, 999),

556

"user loading"

557

);

558

559

await safeDatabaseOperation(

560

() => save(user),

561

"user saving"

562

);

563

} catch (error) {

564

if (error instanceof Exception) {

565

console.error("Operation failed:", error.message);

566

console.error("Root cause:", error.cause);

567

}

568

}

569

```

570

571

### Extended Map Utilities

572

573

Type-safe extended map implementations for managing key-value pairs with automatic JSON serialization.

574

575

```typescript { .api }

576

/**

577

* Extended Map implementation with type-safe value access and JSON serialization

578

* @template T - ExtendedMapItem type defining key and value structure

579

* @template ValueMap - Mapped type for value types by key

580

*/

581

class ExtendedMap<T extends ExtendedMapItem<string, any>, ValueMap extends { [key in T["key"]]: ReturnType<T["parsed"]> } = {

582

[key in T["key"]]: any;

583

}> extends Map<T["key"], ExtendedMapItem<T["key"], ValueMap[T["key"]]>> {

584

/**

585

* Creates new ExtendedMap instance

586

* @param itemClass - Constructor for map items

587

* @param parentArray - Optional array to sync with

588

*/

589

constructor(itemClass: new () => T, parentArray?: Array<T>);

590

591

/**

592

* Gets parsed value for a key with fallback support

593

* @param key - Map key

594

* @param fallback - Optional fallback value

595

* @returns Parsed value of type ValueMap[K]

596

*/

597

getValue<K extends T["key"]>(key: K, fallback?: ValueMap[K]): ValueMap[K];

598

599

/**

600

* Sets parsed value for a key

601

* @param key - Map key

602

* @param val - Value to set

603

*/

604

setValue<K extends T["key"]>(key: K, val: ValueMap[K]): void;

605

606

/**

607

* Iterate over parsed values

608

* @returns Iterator of parsed values

609

*/

610

entryValues(): IterableIterator<ReturnType<T["parsed"]>>;

611

612

/**

613

* Iterate over each value with callback

614

* @param callbackfn - Function called for each key-value pair

615

*/

616

forEachValue(callbackfn: <K extends T["key"]>(value: ValueMap[K], key: K, map: ExtendedMap<T>) => void): void;

617

}

618

619

/**

620

* Extended Map Item for storing key-value pairs with JSON serialization

621

* @template K - Key type (string-based)

622

* @template T - Value type

623

*/

624

@table()

625

class ExtendedMapItem<K extends string = string, T = any> {

626

/** Primary key for database storage */

627

@primary()

628

id: number;

629

630

/** JSON-serialized value */

631

@column()

632

value: string;

633

634

/** Map key */

635

@column()

636

key: K;

637

638

/**

639

* Parse stored JSON value

640

* @returns Parsed value of type T

641

*/

642

parsed(): T;

643

644

/**

645

* Set value with JSON serialization

646

* @param value - Value to serialize and store

647

*/

648

setStringified(value: T): void;

649

}

650

```

651

652

**Usage Examples:**

653

654

```typescript

655

import { ExtendedMap, ExtendedMapItem } from "hibernatets";

656

657

// Define custom map item type

658

interface UserSettings {

659

theme: "dark" | "light";

660

notifications: boolean;

661

language: "en" | "es" | "fr";

662

}

663

664

interface SettingsMap {

665

theme: "dark" | "light";

666

notifications: boolean;

667

language: "en" | "es" | "fr";

668

}

669

670

// Create extended map for user settings

671

const settingsMap = new ExtendedMap<ExtendedMapItem<keyof SettingsMap, any>, SettingsMap>(

672

ExtendedMapItem,

673

[]

674

);

675

676

// Set values with automatic JSON serialization

677

settingsMap.setValue("theme", "dark");

678

settingsMap.setValue("notifications", true);

679

settingsMap.setValue("language", "en");

680

681

// Get values with type safety and fallbacks

682

const theme = settingsMap.getValue("theme", "light"); // "dark"

683

const notifications = settingsMap.getValue("notifications", false); // true

684

const language = settingsMap.getValue("language", "en"); // "en"

685

686

// Iterate over all values

687

settingsMap.forEachValue((value, key) => {

688

console.log(\`Setting \${key}: \${value}\`);

689

});

690

691

// Working with extended map items directly

692

const themeItem = new ExtendedMapItem<"theme", "dark" | "light">();

693

themeItem.key = "theme";

694

themeItem.setStringified("dark");

695

696

console.log(themeItem.parsed()); // "dark"

697

console.log(themeItem.value); // "\"dark\""

698

```