or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dependency-injection.mdindex.mdmodule-configuration.mdschema-definition.mdschema-factories.mdutility-functions.mdvalidation-pipes.md

utility-functions.mddocs/

0

# Utility Functions

1

2

Helper functions for generating dependency injection tokens, handling connection retry logic, and managing raw object definitions. These utilities support the core functionality of the NestJS Mongoose integration.

3

4

## Capabilities

5

6

### Token Generation Functions

7

8

Utility functions for creating dependency injection tokens used by the NestJS container.

9

10

#### getModelToken

11

12

Generates the dependency injection token used for model injection.

13

14

```typescript { .api }

15

/**

16

* Generates dependency injection token for a model

17

* @param model - Model name (typically the class name)

18

* @param connectionName - Optional connection name for multi-database setup

19

* @returns String token for dependency injection

20

*/

21

function getModelToken(model: string, connectionName?: string): string;

22

```

23

24

**Usage Examples:**

25

26

```typescript

27

import { getModelToken } from '@nestjs/mongoose';

28

29

// Basic model token

30

const userToken = getModelToken('User');

31

// Returns: 'UserModel'

32

33

// Model token with named connection

34

const userTokenWithConnection = getModelToken('User', 'users-db');

35

// Returns: 'users-db/UserModel'

36

37

// Use in custom providers

38

import { Module, Provider } from '@nestjs/common';

39

40

const customProviders: Provider[] = [

41

{

42

provide: 'USER_REPOSITORY',

43

useFactory: (userModel: Model<User>) => {

44

return new UserRepository(userModel);

45

},

46

inject: [getModelToken('User')],

47

},

48

{

49

provide: 'USER_CACHE_SERVICE',

50

useFactory: (userModel: Model<User>, cacheService: CacheService) => {

51

return new UserCacheService(userModel, cacheService);

52

},

53

inject: [getModelToken('User'), 'CACHE_SERVICE'],

54

},

55

];

56

57

@Module({

58

providers: [...customProviders],

59

exports: ['USER_REPOSITORY', 'USER_CACHE_SERVICE'],

60

})

61

export class UserRepositoryModule {}

62

63

// Testing with model tokens

64

import { Test, TestingModule } from '@nestjs/testing';

65

66

describe('UserService', () => {

67

let service: UserService;

68

let mockUserModel: Model<User>;

69

70

beforeEach(async () => {

71

const mockModel = {

72

find: jest.fn(),

73

findById: jest.fn(),

74

create: jest.fn(),

75

findByIdAndUpdate: jest.fn(),

76

findByIdAndDelete: jest.fn(),

77

};

78

79

const module: TestingModule = await Test.createTestingModule({

80

providers: [

81

UserService,

82

{

83

provide: getModelToken('User'),

84

useValue: mockModel,

85

},

86

],

87

}).compile();

88

89

service = module.get<UserService>(UserService);

90

mockUserModel = module.get<Model<User>>(getModelToken('User'));

91

});

92

93

it('should create a user', async () => {

94

const userData = { name: 'John Doe', email: 'john@example.com' };

95

mockUserModel.create = jest.fn().mockResolvedValue(userData);

96

97

const result = await service.create(userData);

98

expect(mockUserModel.create).toHaveBeenCalledWith(userData);

99

expect(result).toEqual(userData);

100

});

101

});

102

```

103

104

#### getConnectionToken

105

106

Generates the dependency injection token used for connection injection.

107

108

```typescript { .api }

109

/**

110

* Generates dependency injection token for a connection

111

* @param name - Optional connection name for multi-database setup

112

* @returns String token for dependency injection

113

*/

114

function getConnectionToken(name?: string): string;

115

```

116

117

**Usage Examples:**

118

119

```typescript

120

import { getConnectionToken } from '@nestjs/mongoose';

121

122

// Default connection token

123

const defaultToken = getConnectionToken();

124

// Returns: 'DatabaseConnection'

125

126

// Named connection token

127

const namedToken = getConnectionToken('analytics-db');

128

// Returns: 'analytics-db'

129

130

// Use in custom providers

131

const databaseProviders: Provider[] = [

132

{

133

provide: 'DATABASE_HEALTH_CHECK',

134

useFactory: (connection: Connection) => {

135

return new DatabaseHealthCheck(connection);

136

},

137

inject: [getConnectionToken()],

138

},

139

{

140

provide: 'ANALYTICS_DB_MANAGER',

141

useFactory: (connection: Connection) => {

142

return new DatabaseManager(connection);

143

},

144

inject: [getConnectionToken('analytics-db')],

145

},

146

];

147

148

// Multiple connections in service

149

@Injectable()

150

export class MultiDatabaseService {

151

constructor(

152

@Inject(getConnectionToken()) private defaultConnection: Connection,

153

@Inject(getConnectionToken('analytics-db')) private analyticsConnection: Connection,

154

) {}

155

156

async getConnectionInfo() {

157

return {

158

default: {

159

name: this.defaultConnection.name,

160

readyState: this.defaultConnection.readyState,

161

},

162

analytics: {

163

name: this.analyticsConnection.name,

164

readyState: this.analyticsConnection.readyState,

165

},

166

};

167

}

168

}

169

```

170

171

### Connection Retry Utility

172

173

RxJS operator for handling connection retry logic with configurable attempts and delays.

174

175

#### handleRetry

176

177

Creates an RxJS operator for connection retry logic.

178

179

```typescript { .api }

180

/**

181

* RxJS operator for connection retry logic

182

* @param retryAttempts - Number of retry attempts (default: 9)

183

* @param retryDelay - Delay between retries in milliseconds (default: 3000)

184

* @param verboseRetryLog - Enable verbose retry logging (default: false)

185

* @returns RxJS operator function

186

*/

187

function handleRetry(

188

retryAttempts?: number,

189

retryDelay?: number,

190

verboseRetryLog?: boolean

191

): <T>(source: Observable<T>) => Observable<T>;

192

```

193

194

**Usage Examples:**

195

196

```typescript

197

import { handleRetry } from '@nestjs/mongoose';

198

import { Observable, throwError } from 'rxjs';

199

import { retryWhen } from 'rxjs/operators';

200

201

// Basic retry configuration

202

const connectWithRetry = (uri: string) => {

203

return mongoose.connect(uri).pipe(

204

retryWhen(handleRetry(5, 2000, true)) // 5 attempts, 2 second delay, verbose logging

205

);

206

};

207

208

// Custom connection service with retry logic

209

@Injectable()

210

export class ConnectionService {

211

private connect(uri: string): Observable<Connection> {

212

return new Observable(subscriber => {

213

mongoose.connect(uri)

214

.then(connection => {

215

subscriber.next(connection);

216

subscriber.complete();

217

})

218

.catch(error => {

219

subscriber.error(error);

220

});

221

}).pipe(

222

retryWhen(handleRetry(10, 5000, true)) // 10 attempts, 5 second delay

223

);

224

}

225

226

async establishConnection(uri: string): Promise<Connection> {

227

return this.connect(uri).toPromise();

228

}

229

}

230

231

// Integration with module configuration

232

export class DatabaseConnectionFactory {

233

static createConnectionProvider(

234

uri: string,

235

options: { retryAttempts?: number; retryDelay?: number; verboseRetryLog?: boolean } = {}

236

): Provider {

237

return {

238

provide: 'DATABASE_CONNECTION',

239

useFactory: async () => {

240

const { retryAttempts = 9, retryDelay = 3000, verboseRetryLog = false } = options;

241

242

return new Observable(subscriber => {

243

mongoose.connect(uri)

244

.then(connection => subscriber.next(connection))

245

.catch(error => subscriber.error(error));

246

}).pipe(

247

retryWhen(handleRetry(retryAttempts, retryDelay, verboseRetryLog))

248

).toPromise();

249

},

250

};

251

}

252

}

253

```

254

255

### Raw Object Definition Utility

256

257

Function for marking object definitions as raw to bypass type transformation.

258

259

#### raw

260

261

Marks an object definition as raw, preventing Mongoose from applying type transformations.

262

263

```typescript { .api }

264

/**

265

* Marks an object definition as raw (bypasses type transformation)

266

* @param definition - Object definition to mark as raw

267

* @returns Object definition with raw marker

268

*/

269

function raw(definition: Record<string, any>): Record<string, any>;

270

```

271

272

**Usage Examples:**

273

274

```typescript

275

import { raw } from '@nestjs/mongoose';

276

277

@Schema()

278

export class FlexibleDocument {

279

@Prop({ required: true })

280

name: string;

281

282

// Raw nested object - no type enforcement

283

@Prop(raw({

284

metadata: { type: mongoose.Schema.Types.Mixed },

285

settings: {

286

theme: { type: String, default: 'light' },

287

notifications: { type: Boolean, default: true },

288

preferences: mongoose.Schema.Types.Mixed

289

},

290

analytics: {

291

views: { type: Number, default: 0 },

292

clicks: { type: Number, default: 0 },

293

customEvents: [mongoose.Schema.Types.Mixed]

294

}

295

}))

296

dynamicData: {

297

metadata: any;

298

settings: {

299

theme: string;

300

notifications: boolean;

301

preferences: any;

302

};

303

analytics: {

304

views: number;

305

clicks: number;

306

customEvents: any[];

307

};

308

};

309

310

// Raw array of mixed objects

311

@Prop(raw([{

312

type: { type: String, required: true },

313

data: mongoose.Schema.Types.Mixed,

314

timestamp: { type: Date, default: Date.now }

315

}]))

316

events: Array<{

317

type: string;

318

data: any;

319

timestamp: Date;

320

}>;

321

}

322

323

// Complex raw schema for configuration

324

@Schema()

325

export class ApplicationConfig {

326

@Prop({ required: true })

327

appName: string;

328

329

@Prop(raw({

330

database: {

331

mongodb: {

332

uri: String,

333

options: mongoose.Schema.Types.Mixed

334

},

335

redis: {

336

host: String,

337

port: Number,

338

options: mongoose.Schema.Types.Mixed

339

}

340

},

341

services: [{

342

name: { type: String, required: true },

343

enabled: { type: Boolean, default: true },

344

config: mongoose.Schema.Types.Mixed

345

}],

346

features: mongoose.Schema.Types.Mixed,

347

customFields: mongoose.Schema.Types.Mixed

348

}))

349

configuration: {

350

database: {

351

mongodb: {

352

uri: string;

353

options: any;

354

};

355

redis: {

356

host: string;

357

port: number;

358

options: any;

359

};

360

};

361

services: Array<{

362

name: string;

363

enabled: boolean;

364

config: any;

365

}>;

366

features: any;

367

customFields: any;

368

};

369

}

370

371

// Usage in service

372

@Injectable()

373

export class ConfigService {

374

constructor(

375

@InjectModel(ApplicationConfig.name)

376

private configModel: Model<ApplicationConfig>

377

) {}

378

379

async updateConfig(appName: string, configUpdate: any): Promise<ApplicationConfig> {

380

// Raw objects allow any structure in configUpdate

381

return this.configModel.findOneAndUpdate(

382

{ appName },

383

{

384

$set: {

385

'configuration.features': configUpdate.features,

386

'configuration.customFields': configUpdate.customFields

387

}

388

},

389

{ new: true }

390

).exec();

391

}

392

393

async addService(appName: string, service: { name: string; config: any }): Promise<ApplicationConfig> {

394

return this.configModel.findOneAndUpdate(

395

{ appName },

396

{

397

$push: {

398

'configuration.services': {

399

name: service.name,

400

enabled: true,

401

config: service.config // Any structure allowed

402

}

403

}

404

},

405

{ new: true }

406

).exec();

407

}

408

}

409

```

410

411

## Constants

412

413

Pre-defined constants used throughout the NestJS Mongoose integration.

414

415

```typescript { .api }

416

/** Default connection name when none is specified */

417

const DEFAULT_DB_CONNECTION = 'DatabaseConnection';

418

419

/** Injection token for Mongoose module options */

420

const MONGOOSE_MODULE_OPTIONS = 'MongooseModuleOptions';

421

422

/** Injection token for connection name */

423

const MONGOOSE_CONNECTION_NAME = 'MongooseConnectionName';

424

425

/** Symbol used to mark raw object definitions */

426

const RAW_OBJECT_DEFINITION = 'RAW_OBJECT_DEFINITION';

427

```

428

429

**Usage Examples:**

430

431

```typescript

432

import {

433

DEFAULT_DB_CONNECTION,

434

MONGOOSE_MODULE_OPTIONS,

435

MONGOOSE_CONNECTION_NAME,

436

RAW_OBJECT_DEFINITION

437

} from '@nestjs/mongoose';

438

439

// Check if using default connection

440

export function isDefaultConnection(connectionName?: string): boolean {

441

return !connectionName || connectionName === DEFAULT_DB_CONNECTION;

442

}

443

444

// Custom provider using constants

445

const configProvider: Provider = {

446

provide: 'CUSTOM_MONGOOSE_CONFIG',

447

useFactory: (options: MongooseModuleOptions, connectionName: string) => {

448

return {

449

options,

450

connectionName,

451

isDefault: connectionName === DEFAULT_DB_CONNECTION,

452

};

453

},

454

inject: [MONGOOSE_MODULE_OPTIONS, MONGOOSE_CONNECTION_NAME],

455

};

456

457

// Utility to check raw definitions

458

export function isRawDefinition(definition: any): boolean {

459

return definition && definition[RAW_OBJECT_DEFINITION] === true;

460

}

461

```

462

463

## Advanced Utility Patterns

464

465

### Token Generation for Dynamic Modules

466

467

```typescript { .api }

468

export class DynamicTokenGenerator {

469

static generateModelTokens(models: string[], connectionName?: string): string[] {

470

return models.map(model => getModelToken(model, connectionName));

471

}

472

473

static generateConnectionTokens(connectionNames: string[]): string[] {

474

return connectionNames.map(name => getConnectionToken(name));

475

}

476

477

static createProviderMap(

478

models: string[],

479

connectionName?: string

480

): Record<string, string> {

481

return models.reduce((map, model) => {

482

map[model] = getModelToken(model, connectionName);

483

return map;

484

}, {} as Record<string, string>);

485

}

486

}

487

488

// Usage in dynamic modules

489

@Module({})

490

export class DynamicDatabaseModule {

491

static forFeature(models: string[], connectionName?: string): DynamicModule {

492

const tokens = DynamicTokenGenerator.generateModelTokens(models, connectionName);

493

const providerMap = DynamicTokenGenerator.createProviderMap(models, connectionName);

494

495

return {

496

module: DynamicDatabaseModule,

497

providers: [

498

{

499

provide: 'MODEL_TOKENS',

500

useValue: tokens,

501

},

502

{

503

provide: 'PROVIDER_MAP',

504

useValue: providerMap,

505

},

506

],

507

exports: ['MODEL_TOKENS', 'PROVIDER_MAP'],

508

};

509

}

510

}

511

```