Nestjs - Typeorm custom connection name - connection

I have a Nestjs db Module and it works perfectly
#Module({
imports: [
TypeOrmModule.forRootAsync({
useFactory: () => {
return {
name: 'default', // <=== here
type: "mysql",
...
};
},
}),
TypeOrmModule.forFeature(entities, 'default'), // <=== here
],
exports: [TypeOrmModule],
})
export class DBModule {}
if I change the connection name to anything else rather then 'default' say 'test' I get an error
#Module({
imports: [
TypeOrmModule.forRootAsync({
useFactory: () => {
return {
name: 'test', // <=== here
type: "mysql",
...
};
},
}),
TypeOrmModule.forFeature(entities, 'test'), // <=== here
],
exports: [TypeOrmModule],
})
export class DBModule {}
[Nest] 10746 - 05/15/2021, 5:55:34 PM [ExceptionHandler] Nest can't resolve dependencies of the test_UserEntityRepository (?). Please make sure that the argument testConnection at index [0] is available in the TypeOrmModule context.
Potential solutions:
- If testConnection is a provider, is it part of the current TypeOrmModule?
- If testConnection is exported from a separate #Module, is that module imported within TypeOrmModule?
#Module({
imports: [ /* the Module containing testConnection */ ]
})
The error seams to only show up if I use TypeOrmModule.forRootAsync
For TypeOrmModule.forRoot if works!
Is there any different way to indicate the connection name? I need to add another connection and can't do it because of this error. Really would like to use 'forRootAsync'

Pass the connection name as follows.
#Module({
imports: [
TypeOrmModule.forRootAsync({
name: 'test', // <=== here
useFactory: () => {
return {
type: "mysql",
...
};
},
}),
TypeOrmModule.forFeature(entities, 'test'), // <=== here
],
exports: [TypeOrmModule],
})
export class DBModule {}

Related

Nestjs can't create dynamic module with config import

I am trying to create a DynamicModule in Nestjs, but it seems I can't properly use useFactory to inject ConfigModule in the process.
If I use a hardcoded boolean instead of config.get('cache').enabled everything works as expected, but I receive the following error if I try to use config:
TypeError: Cannot read properties of undefined (reading 'get')
Here's the code I arranged so far:
app.module.ts
#Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
validate,
}),
CoreModule.registerAsync({
useFactory: (config: ConfigService) => ({
cacheEnabled: config.get('cache').enabled,
}),
imports: [ConfigModule],
injects: [ConfigService],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
core.module.ts
#Module({})
export class CoreModule {
static registerAsync = (options: {
useFactory: (...args: any[]) => { cacheEnabled: boolean };
imports: any[];
injects: any[];
}): DynamicModule => {
const imports = [];
const providers = [];
if (options.useFactory().cacheEnabled) imports.push(HttpCacheModule);
return {
module: CoreModule,
imports,
providers,
};
};
}

NestJS Standalone app can't inject Sequelize instance using connection token

I'm still quite new to NestJS. I'm trying to implement a standalone app that connect to both external/remote source DB and the app DB.
Now I got stuck at Nest can't resolve dependencies of the SourceDbQueryService (ModuleRef, ?). Please make sure that the argument {{token}} at index [1] is available in the EtlModule context.
The {{token}} here is supposedly a string returned from getConnectionToken(connectionName), ex.: sourceDbConnection when connectionName = sourceDb
Here are my modules setup example:
/src/db/source-db-module.ts
#Module({
imports: [
ConfigModule,
LoggingModule,
SequelizeModule.forRootAsync({
imports: [ConfigModule],
inject: [SourceDbConfig],
useFactory: (config: SourceDbConfig) => {
return {
...config,
name: SourceDbConfig.DefaultConnectionName,
autoLoadModels: false,
}
},
}),
],
exports: [SequelizeModule],
})
export class SourceDbModule {}
/src/jobs/etl-module.ts
#Module({
imports: [
ConfigModule,
LocalDbModule,
/** Contains Local repositories with decorated Models, using connection from LocalDbModule */
RepositoryModule,
SourceDbModule,
SequelizeModule.forFeature([], SourceDbConfig.DefaultConnectionName),
],
providers: [
{
provide: SourceDbQueryService,
inject: [ModuleRef, getConnectionToken(SourceDbConfig.DefaultConnectionName)],
useFactory(moduleRef: ModuleRef, sequelize: Sequelize) {
return new SourceDbQueryService(moduleRef, sequelize)
},
},
],
exports: [SourceDbQueryService],
})
export class EtlModule {}
/src/jobs/test-query-source-db.ts
async function bootstrap(): Promise<void> {
try {
const appContext = await NestFactory.createApplicationContext(EtlModule)
appContext.init()
const sourceDb = appContext.get(SourceDbQueryService)
const totalRecordsCount = await sourceDb.count({
// ...filters,
})
console.log(
`retrieved source DB results: (total items: ${totalItemsCount})`
)
appContext.close()
} catch (err) {
console.error(err)
process.exit(-1)
}
}
bootstrap()
Please help, what am I missing here?
Thanks!
Update: Workaround
For now I'm using a workaround by providing Sequelize instance directly from my own factory like this:
/src/db/source-db-module.ts
#Module({
imports: [
ConfigModule,
LoggingModule,
],
providers: [
// WORKAROUND: For SequelizeModule.forRootAsync() injection by connection token not working
{
provide: getConnectionToken(SourceDbConfig.DefaultConnectionName),
inject: [SourceDbConfig],
useFactory(config: SourceDbConfig) {
const { host, port, username, password, database, dialect } = config
return new Sequelize({
host,
port,
username,
password,
database,
dialect,
})
},
},
{
provide: SourceDbQueryService,
inject: [ModuleRef, SourceDbConfig, getConnectionToken(SourceDbConfig.DefaultConnectionName)],
useFactory(moduleRef: ModuleRef, config: SourceDbConfig, sequelize: Sequelize) {
const { schema, viewName } = config
return new SourceDbQueryService(moduleRef, sequelize, { schema, viewName })
},
},
],
exports: [
getConnectionToken(SourceDbConfig.DefaultConnectionName),
SourceDbQueryService,
],
})
export class SourceDbModule {}
/src/jobs/etl-module.ts
#Module({
imports: [
ConfigModule,
LocalDbModule,
/** Contains Local repositories with decorated Models, using connection from LocalDbModule */
RepositoryModule,
SourceDbModule,
],
})
export class EtlModule {}

Routing problem when application is starting Ionic 4

We are developing an application with Ionic 4 with the framework Angular.
We have an issue when we log to the application.
You can see the error on the picture:
My code is here:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { TabsPage } from './tabs.page';
const routes: Routes = [
{
path: 'tabs',
component: TabsPage,
children: [
{
path: 'tab1',
children: [
{
path: '',
loadChildren: '../tab1/tab1.module#Tab1PageModule'
}
]
},
{
path: 'tab2',
children: [
{
path: '',
loadChildren: '../tab2/tab2.module#Tab2PageModule'
}
]
},
{
path: 'tab3',
children: [
{
path: '',
loadChildren: '../tab3/tab3.module#Tab3PageModule'
}
]
},
{
path: '',
redirectTo: '/tabs/tab2',
pathMatch: 'full'
}
]
},
{
path: '',
redirectTo: '/tabs/tabs/tab2',
pathMatch: 'full'
}
];
#NgModule({
imports: [
RouterModule.forChild(routes)
],
exports: [RouterModule]
})
export class TabsPageRoutingModule {}
I don't believe in magic but when i delete one dot on the loadchildren exemple :
../tab3/tab3.module#Tab3PageModule -> ./tab3/tab3.module#Tab3PageModule
I do it on all the loadchildreds I'm saving the page I try to log in, same problem
and after I reput the dot like this
./tab3/tab3.module#Tab3PageModule -> ../tab3/tab3.module#Tab3PageModule
I'm saving, I try to log in again and it works fine. With this problem, we can't compile on ios.
I think you have to resolve relative paths for your tabs. Use augury chrome to check and resolve your routing. Also try to simplify your routing.
{
path: 'tab2',
loadChildren: () => import('./tab2/tab2.module').then(m => m.Tab2PageModule)
},

Preloading Strategy issue for forChild routes

My application is a bit large in size. It contains many feature modules and most are lazily loaded. I want to preload a lazily loaded module, which is included in forChild routes.
For this, I have referred to Angular documentation and followed their steps. I have provided a custom preloading strategy service mentioned below.
This is my custom preloading strategy file:
#Injectable()
export class CustomPreloadingWithDelayStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
if (route.data && route.data['preload']) {
return load();
} else {
return Observable.of(null);
}
}
}
app-routing file,
const routes: Routes =
[
XXX,
{
path: '',
data: {
base: true
},
component: MyComp,
children: [
{
path: 'page1/:id',
loadChildren: 'XXXXXXX'
},
{
path: 'page2',
loadChildren: 'XXXXXXXX'
},
{
path: 'page3',
loadChildren: 'app/feature-modules/folder1/my-folder1-module#Folder1Module'
}];
#NgModule({
imports: [RouterModule.forRoot(routes, {useHash: true, preloadingStrategy: CustomPreloadingWithDelayStrategy})],
exports: [RouterModule],
entryComponents: [ ]
})
export class AppRoutingModule {}
My Folder1Module's routing file:
const routes: Routes = [{
path: 'sub-page1/:data1/:data2',
loadChildren: 'app/feature-modules/sub-pages/pages/sub-page1.module#SubPage1Module'
}, {
path: 'sub-page2/:data1',
loadChildren: 'app/feature-modules/sub-pages/pages/sub-page2.module#SubPage2Module',
data: {preload: true}
}];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class Folder1RoutingModule {
}
So when I open this route /page3/sub-page1/data1/data2, SubPage2Module is to be preloaded. But that is not happening.
I have spent nearly 2 hours to understand why the module is not pre-loaded even when I was doing everything right.
The problem lies with children, any route that is defined and further distributed with children is considered as a normal route even if you've defined your modules within the children with the help of loadChildren. The preloadingStrategy just takes modules to preload and not path/routes. The moment you've defined your routes under children it considers it as normal route and moves on to scan other routes that are provided with loadChildren. Following is the interpretation of Angular with your routes:
const routes: Routes =
[
XXX, // Normal path
{
path: '',
data: {
base: true
},
component: MyComp,
children: [ // Normal path (no module) as children is used, move on
{
path: 'page1/:id',
loadChildren: 'XXXXXXX'
},
{
path: 'page2',
loadChildren: 'XXXXXXXX'
},
{
path: 'page3',
loadChildren: 'app/feature-modules/folder1/my-folder1-module#Folder1Module'
},
],
},
{ path: 'abc', loadChildren: '../path/to/module#AbcModule', data: { preload: true }} // Module found, preload it!
];
If you debug closely in your custom CustomPreloadingWithDelayStrategy then you will observe that your route /page3/sub-page1/data1/data2 can't even make up to the route parameter of preload() method because preloading is all about loading module and not about loading routes. However, our route abc does make an appearance! Hope it helps :)

unhandled Promise rejection: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document

i work on a angular 4 project as front end for an asp.net MVC and API in the same solution when i set my routes i get the above error.
my code as following
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { RouterModule, Routes } from '#angular/router';
import { DashboardComponent } from
'../../Components/dashboard/dashboard.component';
import { TraitComponent } from '../../Components/trait/trait.component';
const routes: Routes = [
{ path: ' ', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component:DashboardComponent },
{ path: 'Trait', component: TraitComponent },
//{ path: 'heroes', component: }
];
#NgModule({
imports: [
RouterModule.forRoot(routes) ,
CommonModule
],
exports: [RouterModule],
})
export class MyAppRoutingModuleModule {
i register/import the "myapprouting "and in my appmodule
that is code in my appComponent
<nav>
<a routerLink="localhost:56800/dashboard">Dashboard</a>
<a routerLink="localhost:56800/Trait">Heroes</a>
</nav>
<!-- <app-trait></app-trait>-->
<router-outlet>
</router-outlet>
In your app.module.ts, add the following :
{provide: APP_BASE_HREF, useValue: '/'}
to your **providers : [ ] ** so it would be like this :
providers: [{provide: APP_BASE_HREF, useValue: '/'},SomeService,AnotherService]
app.module.ts
import { APP_BASE_HREF } from '#angular/common'; <-- add those ***
const appRoutes: Routes = [
{ path: 'secondpage', component: SecondPageComponent },
];
#NgModule({
declarations: [
AppComponent,
NameEditorComponent,
ProfileEditorComponent,
SecondPageComponent
],
imports: [
BrowserModule,
// other imports ...
ReactiveFormsModule,
RouterModule.forRoot(
appRoutes,
{ enableTracing: true } //
)
],
providers: [{provide: APP_BASE_HREF, useValue: '/'}], <-- add those **** bootstrap: [AppComponent]
})
export class AppModule { }
Try to change the routerLink to this :
[routerLink]="['/dashboard']
[routerLink]="['/Trait']

Resources