naming and getting a particular connection in typeorm - postgresql

Previously, typeorm seems to have allowed the use of a ConnectionManager that seems to have allowed to name a particular connection whilst creation and fetch/check the connection with the same name like this:
import { Connection, createConnection, getConnectionManager } from 'typeorm';
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions';
import * as tenantsOrmconfig from '../../tenants-orm.config';
export function getTenantConnection(tenantId: string): Promise<Connection> {
const connectionName = `tenant_${tenantId}`;
const connectionManager = getConnectionManager();
if (connectionManager.has(connectionName)) {
const connection = connectionManager.get(connectionName);
return Promise.resolve(connection.isConnected ? connection : connection.connect());
}
return createConnection({
...(tenantsOrmconfig as PostgresConnectionOptions),
name: connectionName,
schema: connectionName,
});
}
But, I'm confused now as to how to achieve this when I'm using a Datasource using a factory to create dynamic connection:
#Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => {
const host = configService.get('MY_DB_HOST');
const port = parseInt(configService.get('MY_DB_PORT'));
const user = configService.get('MY_DB_USER');
const password = configService.get('MY_DB_PASSWORD');
const dbName = configService.get('MY_DB_NAME');
return {
type: 'postgres',
host: host,
port: port,
username: user,
password: password,
database: dbName,
entities: entities,
synchronize: true,
};
}
})
],
controllers: [AppController],
providers: [AppService],
})
I'm trying to fetch an existing connection from the connection pool which typeorm is supposed to manage by default if it already exists, and that connection is supposed to belong to a tenant if it exists, else it should create a new connection for the tenant. How do I do this with a Datasource?
I can see that there is a datasourceInstance.manager.find() method, but, that seems to take an Entity which seems to query the database, and I can't find anything more useful in the docs.

Related

typeORM postgres don't seem to find database

I'm using windows 10, Nest.js and typeORM.
Previously, I had to create a new user\role uder my windows user - but now the ORM don't seem to find my db (called steamClone) - and calls a db named after my user:
error: database "Itay" does not exist
typeORM is configured like such encapsulated in a module:
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import {ConfigModule, ConfigService} from '#nestjs/config';
#Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (ConfigService: ConfigService) => ({
type: 'postgres',
host: ConfigService.get('DB_HOST'),
port: ConfigService.get('DB_PORT'),
username: ConfigService.get('DB_USER'),
password: ConfigService.get('DB_PASSWORD'),
database: ConfigService.get('DB_DATABASE'),
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
synchronize: true,
})
})
],
})
export class DatabaseModule {}
all of the parameters are stored in a .env file
running on localhost, default port and everything, postgres user etc.
would love to know how to solve this

Heroku Postgres - The server does not support SSL connections

I have been working on an small app and connecting with Heroku PostgreSQL, for many days was working right but now is showing me this SSL error
The server does not support SSL connections
I have been looking for solutions but I cannot find anything that works for me, my code is:
import pg from 'pg'
import db from '../config.js'
const pool = new pg.Pool({
host: db.host,
database: db.database,
user: db.user,
port: db.port,
password: db.password,
ssl: { rejectUnauthorized: false },
})
export default function query(text, params) {
return pool.query(text, params)
}
Try changing it from Pool to Client and then using that to connect and query.
async function get(){
const client = new pg.Client({
ssl: {
rejectUnauthorized: false
},
user: ...,
password: ...,
port: ...,
host: ...,
database: ...
});
client.connect();
const response = await client.query(`SELECT * FROM ...;`)
return response.rows
}
Double check your values in the Heroku database.
Also, in production, you should just need
const client = new pg.Client({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
},
}
The first set of code is for local connection to your db.
One last note, I would put your user, password, etc... into a .env file and don't commit that to your repo.
UPDATE:
You can also put this into a config file like ./db.config.js as the following
const pg = require('pg')
module.exports =
process.env.DATABASE_URL
?
new pg.Client({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
},
})
:
new pg.Client({
// connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
},
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
port: process.env.DATABASE_PORT,
host: process.env.DATABASE_HOST,
database: process.env.DATABASE
})
So if it is in production, it will use the database url, and if there is none (which is local) then it will use the username password connection.

TypeORM in NestJS can not connect to MongoDB

I install the mongodb software on my own Ubuntu server and I get the mongo string just like this mongodb://xxx:pass#42.212.159.109:27017,when I type this string in my local terminal and use mongosh mongodb://xxx:pass#42.212.159.109:27017, it works fine and the connection is success. But when I use this mongodb string in my nestjs project, when I run npm run start, the terminal output MongoServerError: Authentication failed.
app.module.ts
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
const username = configService.get('MONGO_USER');
const password = configService.get('MONGO_PASS');
const database = configService.get('MONGO_DATABASE');
const host = configService.get('MONGO_HOST');
const port = configService.get('MONGO_PORT');
return {
type: 'mongodb',
host,
port,
username,
password,
database,
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
};
},
The mongodb version is 4.1.3, TypeOrm version is 0.2.38.
Does anyone know what is the problem and how to solve it? Thank u.
I have figure out what the problem is, as the authSource of my mongodb is not the same one with the database to save data. So I should set the authSource option to admin, then it works.
return {
type: 'mongodb',
host,
port,
username,
password,
database,
authSource: 'admin',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
};
Maybe you should try to use the Database URL connection string instead of host, port, username, password, ...
So instead of using this
return {
type: 'mongodb',
host,
port,
username,
password,
database,
entities: ...
...
}
you should use this
return {
type: "mongodb",
url: configService.get("DATABASE_URL"),
entities: ...
...
}

Loopback4 with Mongodb authentification status code 500 error

i have been struggling with Loopback4 for days...Lb3 was so much easier...
my goal is to authenticate all of my routes except #get route.
configuration went well and when i tried to get route i got a message that route is authenticated, so i have put authenticate.skip(), and then got 500 status code:
ResolutionError: The key 'dataSources.mongoDS' is not bound to any value in context
It's probably a simple solution but i cannot find it...
my code is:
i have imported components in application.ts
this.component(AuthenticationComponent)
this.component(JWTAuthenticationComponent)
this.dataSource(MongoDsDataSource, UserServiceBindings.DATASOURCE_NAME)
this.bind(UserServiceBindings.USER_SERVICE).toClass(MyUserService);
this is my datasource code:
const config = {
name: 'mongoDS',
connector: 'mongodb',
url: '',
host: 'localhost',
port: 27017,
user: '',
password: '',
database: 'ropesdb',
useNewUrlParser: true
};
#lifeCycleObserver('datasource')
export class MongoDsDataSource extends juggler.DataSource
implements LifeCycleObserver {
static dataSourceName = 'mongoDS';
static readonly defaultConfig = config;
constructor(
#inject('dataSources.config.mongoDS', {optional: true})
dsConfig: object = config,
) {
super(dsConfig);
}
}
and this is my repository code:
export class RopeRepository extends DefaultCrudRepository<
Rope,
typeof Rope.prototype.id,
RopeRelations
> {
constructor(
#inject('dataSources.mongoDS') dataSource: MongoDsDataSource,
) {
super(Rope, dataSource);
}
}
I believe LoopBack uses the datasource filename to determine the name of the datasource and place the name in the context. For example, [name-in-kebab-case].datasource.ts will be datasource.NameInCamelCase in the context. Is MongoDsDataSource placed in mongo-ds.datasource.ts?

TypeORM doesn't support the database setting on the entity decorator

I'm trying to seperate my TypeORM project over multiple databases as it is growing in size, and its components are very discrete(yet interlinked, so i need to be able to have relations cross-database).
I am trying to do that using the database setting on the #Entity decorator, as described here: https://typeorm.io/#multiple-connections/using-multiple-databases-in-a-single-connection
I made a minimal reproducable example for this, with two entities that should in theory be put in different databases:
#Entity({ database: 'test' })
export default class Entity1 {
#PrimaryGeneratedColumn()
id?: number
#Column()
name?: string
#Column()
address?: string
}
and
#Entity({ database: 'database2' })
export default class Entity2 {
#PrimaryGeneratedColumn()
id?: number
#Column()
name?: string
#Column()
address?: string
}
Connection code:
import {createConnections} from "typeorm";
async function doDbExample() {
const connections = await createConnections([{
name: "db1Connection",
type: "postgres",
host: "db",
port: 5432,
username: "test",
password: "testPassword",
database: "test",
entities: [__dirname + "/entity/*{.js,.ts}"],
synchronize: true
}]);
console.log("Created connections")
}
doDbExample()
However, what happens is that both entities' table is put in the database of the connection. Am i doing something wrong, or is this a bug in TypeORM? It looks to me like it is not respecting the database setting any more.
I am running the code using ts-node-dev
I made a full minimal reproducable example, complete with dockerized setup of the database environment, on github: https://github.com/petterroea/TypeOrmBug-MRE
This is a setup issue. I solved it like this:
Modify the array entities so each connection/database has its own folder with entity files and name the entity you use the most as default:
// src/index.ts
await createConnections([
{
name: 'default',
host: 'SERVER1',
username: 'bob',
password: 'kiwi,
type: 'mssql',
database: 'db1',
...
"synchronize": true,
"entities": ["src/db1/entity/**/*.ts"],
},
{
name: 'connection2,
host: 'SERVER2',
username: 'Mike',
password: 'carrot',
type: 'mssql',
database: 'db2,
...
"synchronize": true,
"entities": ["src/db2/entity/**/*.ts"],
])
Create entity files for each database in its respective folder:
src/db1/entity/Fruit.ts > table in db1
src/db2/entity/Vegetables.ts > table in db2
With "synchronize": true each table will be created automatically in the correct database
Accessing data in the tables:
For the default connection::
import { Fruit} from 'src/db1/entity/Fruit.ts'
fruits() {
return Fruit.find()
}
For the non default connection:
import { getRepository } from 'typeorm'
import { Vegetable} from 'src/db2/entity/Vegetable.ts'
vegetables() {
return async () => await getRepository(Vegetable).find()
}
or
async vegetables() {
return await getRepository(vegetables, 'connection2').find()
}
I hope this helps someone else struggling with the same issues as you and me.