Sails_mysql adapter - mysql

I want to know how we can create more than one tables in MySQL using Node.js through ORM adapters. I have created a table through model i.e. 'us.js'
module.exports = {
identity: 'us',
connection: 'mysqlDB',
schema:true,
migrate: 'safe',
attributes: {
as_a: 'string',
i_want_to: 'string',
for_the:'string',
so_that:'string'
}
};
And built its connection as connections.js:
var mysqlAdapter = require('sails-mysql');
var mongoAdapter = require('sails-mongo');
module.exports = {
adapters: {
mongoAdapt: mongoAdapter,
mysqlAdapt: mysqlAdapter
},
connections: {
mysqlDB: {
adapter: 'mysqlAdapt',
host: 'localhost',
database:'user_stories',
user:'root',
password:'',
supportBigNumbers:true, //true/false
debug:['ComQueryPacket'], //false or array of node-mysql debug
options
trace:true //true/false
}
}
};
So with the same connection how can I create more than one tables in MySQL database.

Create a new model for a new table. In the model, specify those attributes which you want as a fields in the table.

Related

typeorm "CREATE DATABASE" migration

I need to create database before connection and work with db. I'm using nest.js typeorm, provided all configurations. When I start my application it says
"Unable to connect to the database. Error: ER_BAD_DB_ERROR: Unknown database 'test'".
Once again: there is not DB "Test" in my MySQL Workbench => when I start the application
I want the application to create the database itself (not by me manually)
Is it possible?
I found a way to achieve this for postgresql. Also I'm using Nest.js and Typeorm too. Firstly, I created two sql files (one for check if database exists and one for create db) and then a config file for database. These files contents are like below.
checkDbIfExists.sql
SELECT 1 FROM pg_database WHERE datname = 'test'
createDB.sql
CREATE DATABASE test
config.ts
import { DynamicModule } from '#nestjs/common';
import { TypeOrmModule, TypeOrmModuleOptions } from '#nestjs/typeorm';
import { createConnection, getManager } from 'typeorm';
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions';
import * as path from 'path';
const fs = require('fs');
const checkDBScript: string = fs
.readFileSync(path.join(__dirname, '../script/checkDBIfExists.sql'))
.toString();
const createDb: string = fs.readFileSync(path.join(__dirname, '../script/createDB.sql')).toString();
const CreateDBIfNotExists = async (options: TypeOrmModuleOptions): Promise<void> => {
const connection = await createConnection(options as PostgresConnectionOptions);
const manager = getManager();
const result = await manager.query(checkDBScript);
if (result.length === 0) await manager.query(createDb);
connection.close();
};
const DBConfig = async (): Promise<DynamicModule> => {
let options: TypeOrmModuleOptions = {
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'asd',
entities: [],
synchronize: true,
cli: {
migrationsDir: 'persistence/migrations'
}
};
await CreateDBIfNotExists(options);
options = { ...options, database: 'test' };
return TypeOrmModule.forRoot(options);
};
export default DBConfig;
Then I added these lines
nest-cli.json
"compilerOptions": {
"assets": ["persistence/script/*"]
}
app.module.ts
#Module({
imports: [DBConfig()]
...
NestJS can't create the database, you need to manually create it before starting your application.
If you want it to be automatic, you can use a docker service to create your database when starting your docker compose with docker-compose up
version: "3.6"
services:
db:
image: mysql:8.0.20
command: --default-authentication-plugin=mysql_native_password
restart: always
ports:
- 3306:3306
environment:
- MYSQL_DATABASE=<database-name>
- MYSQL_ROOT_PASSWORD=<password>
I am using TypeORM version 0.3.11, so while M. Erim Tuzcuoglu's solution works for now, it's using deprecated methods.
Here is my function that is based on the newer DataSource approach.
export const createDBIfNotExists = async (): Promise<void> => {
const dbOptions = dbConfig().db;
const { createDatabase, database } = dbOptions;
if (!createDatabase) {
return;
}
const dataSource = new DataSource({
type: 'postgres',
...dbOptions,
database: 'postgres',
});
await dataSource.initialize();
const result = await dataSource.query(
`SELECT 1 FROM pg_database WHERE datname = '${database}'`
);
if (!result.length) {
console.log(`Creating database with name "${database}"`);
await dataSource.query(`CREATE DATABASE "${database}"`);
}
await dataSource.destroy();
}
Specifying postgres as the database for the connection is a bit "hacky" because it assumes it's existence. However in my case that is acceptable. Without it it would fail to connect.
I should also mention that dbConfig function is very similar to the approach provided in Nest documentation:
// Use process.env for the values, I've hardcoded them just for clarity here
export const dbConfig = (): { db: IDBConfig } => ({
db: {
host: 'localhost',
port: 5432,
database: 'your-db-name',
username: 'username',
password: 'password',
migrationsRun: true,
createDatabase: true,
logging: true,
synchronize: false,
},
});
Then in my main.ts I just call the function:
async function bootstrap() {
await createDBIfNotExists();
// ...
}
This allows me to simply change POSTGRES_DB env variable and it would create and use this DB automatically when I start the app (while also checking for the RUN_MIGRATION env).
It's quite specific to the requirements I had, but I hope the general implementation example could help someone in the future.

How to renew connection of database for iam authentication

Using IAM database authentication the password expires after about 15 minutes. So I ideally have to renew the database connection before the password expires. I set up a timer on the first initialization of the database and query the passed time on each query. How can i refresh the password of the connection before the password expires? Or how can i destroy the old database object and renew the object if necessary?
The error message is: "PAM authentication failed for user iam_user".
code for getting IAM Password:
const pgp = require('pg-promise')();
const AWS = require('aws-sdk');
const ca =
'-----BEGIN CERTIFICATE-----\nMIID9DCCAtyg...
...wZfTUU=\n-----END CERTIFICATE-----\n';
const signer = new AWS.RDS.Signer({
region: process.env.REGION,
username: process.env.DATABASE_USER,
hostname: process.env.DATABASE_HOST,
port: parseInt(`${process.env.DATABASE_PORT}`, 10),
});
module.exports = pgp({
host: process.env.DATABASE_HOST,
port: process.env.DATABASE_PORT,
database: process.env.DATABASE_NAME,
user: process.env.DATABASE_USER,
ssl: { ca },
dialectOptions: { ssl: { require: true } },
password: signer.getAuthToken(),
});
injecting db object to graphql:
const db = require('../db/init');
server.use(
mount(
'/graphql',
graphqlHTTP( () => ({
schema: schema,
context: { startTime: Date.now(), db },
graphiql: true
})),
),
);
Using the database in the resolvers.
I could query the time of the creation of the database connection. Is there a possibility to renew the password if necessary? Or what is the best way to destroy the old database object and create a new database object?
const resolvers = {
Query: {
Post: (root, args, {db}) => {
console.log(args.id);
console.log(db.$config.options)
const postQuery = new PQ({
text:
'SELECT post_id as id FROM tbl_post where post_id = $1',
values: [parseInt(args.id, 10)],
});
return db.one(postQuery).catch((err) => console.log(err));
}
}
As suggested by vitaly-t i used a password function. To avoid adding latency this functions renews the password only every 15 minutes. If the pool gets continuously used in intervals lower than 10 seconds, than the connection stays open without calling the password function at all. According to my tests there are no new connections to the database opened at all.
const ca = '-----BEGIN CERTIFICATE-----\9DC...-----END CERTIFICATE-----\n';
const signer = new AWS.RDS.Signer({
region: process.env.REGION,
username: process.env.DATABASE_USER,
hostname: process.env.DATABASE_HOST,
port: parseInt(`${process.env.DATABASE_PORT}`, 10),
});
const SIGNER = { time: 0, password: undefined};
function getSignedPassword() {
const time = Date.now();
if (time - SIGNER.time > 900000) {
SIGNER.time = new Date().getTime();
SIGNER.password = signer.getAuthToken();
return SIGNER.password;
}
return SIGNER.password;
}
module.exports = pgp({
host: process.env.DATABASE_HOST,
port: process.env.DATABASE_PORT,
database: process.env.DATABASE_NAME,
user: process.env.DATABASE_USER,
ssl: { ca },
password: getSignedPassword,
});

How to create table inside dynamically created database in sequelize?

I am working on a rest api using nodejs, express and sequelize orm. The api i am creating is for a android application which is based on SAAS platform. Therefore, I need to create separate database for each user of my application. There will be a master database which will be used to identify the database credential for each user while logging in. The master database will be connected by default and in each api call, in each route i need to connect/create the user specific database including the tables.
/* This is my db.js file for master database connection using sequelize. */
require('dotenv').config();
const sequelize = require('sequelize');
module.exports = new sequelize('master_db', process.env.DB_USER, process.env.DB_PASS, {
host: process.env.DB_HOST,
dialect: 'mysql',
operatorAliases: false,
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
});
/* This is a model Demo.js */
const Sequelize = require('sequelize');
const db = require('../../db');
const Demo_table = db.define('demo_table', {
// attributes
demo_id: {
type: Sequelize.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
},
demo_name: {
type: Sequelize.INTEGER,
allowNull: false,
}
}, {
// options
timestamps: false,
freezeTableName: true,
});
module.exports = Demo_table;
/* This demo_route.js file in route folder*/
"use strict";
require('dotenv').config();
const express = require('express');
const router = express.Router();
const checkAuth = require('../middleware/auth');
//load controllers
const DemoController = require('../controllers/demo_member');
router.post('/demo_activity', checkAuth, DemoController.demo_activity);
module.exports = router;
/* This is the controller file demo_member.js*/
const moment = require('moment-timezone');
const Sequelize = require('sequelize');
const nodemailer = require("nodemailer");
const Op = Sequelize.Op;
//load models
const Demo = require('../models/Demo');
exports.create_demo_team = (req, res) => {
/* here i need to create the database of the user who is calling this api if the database(with tables) is not created else need to connect with the existing user's database and perform CRUD*/
}
I am expecting with the solution which will fulfil my requirement at the earliest. where i can create database dynamically, then create table and connect with it to perform CRUD.

How to get the mysql connection for mysql-session (not the Sequelize instance)?

I already have the Sequelize instance, but I need to get the mysql connection for mysql-session.
This is how the Sequelize instance looks like:
var Sequelize = require('sequelize');
var sequelize = new Sequelize( 'db_name', 'root', '',
{
host: 'localhost',
dialect: 'mysql',
pool: {
max: 5,
min: 0,
idle: 10000
}
}
);
module.exports = sequelize;
I use Passport.js for the authentication system, but as database, I use mysql. Therefore, I am working with Sequelize module.
I want to do something like this:
var connection = mysql.createConnection(options);
var sessionStore = new MySQLStore({}/* session store options */, connection);
But since I use Sequelize, I do not want to use the mysql.createConnection method but to get the db connection object from the sequelize object (instance of Sequelize).
How to get the mysql connection for express-mysql-session (not the Sequelize instance)?

sails js getting data from database without schema definition in model

I am new to SailsJs. I have a MySQL database with 123 tables with lots of fields. Now i want to use that database in my sails application. When i need to get data from any table i need to declare fields name, type etc in model like below
module.exports = {
tableName: 'Mytable',
adapter: 'someMysqlServer',
migrate: 'safe',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
id: {
type: 'number',
required:true
},
name: {
type: 'string',
required: true
}
}
};
Now I don't want to declare all the fields in model as i have so many tables/fields. So how can i select/insert/update data without this.
var connection = mysql.createConnection({
host: sails.config.connections.yourDbConnetion.host,
user: sails.config.connections.yourDbConnetion.user,
password: sails.config.connections.yourDbConnetion.password,
database: sails.config.connections.yourDbConnetion.database
});
YourFunction: function (req,res) {
connection.query('YOUR SQL QUERY ', function (err, result) {
if (err)
return res.send(err);
.........
});
}