I have tried to setup a data migration service using postgrator version 7.1.0. I have the following code
import Postgrator from "postgrator";
import pg from "pg";
import { dirname } from "path";
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
async function doMigration() {
// Create a client of your choice
const client = new pg.Client({
host: "0.0.0.1",
port: 9075,
database: "test",
user: "test",
password: "!testPwd",
});
try {
// Establish a database connection
await client.connect();
// Create postgrator instance
const postgrator = new Postgrator({
migrationDirectory: __dirname + '/migration-scripts',
driver: "pg",
database: "test",
schemaTable: "migration_version",
execQuery: (query) => client.query(query),
});
await postgrator.migrate();
console.log("schema migration completed successfully")
} catch (error) {
console.error(error);
}
// Once done migrating, close your connection.
await client.end();
}
doMigration();
But I got an error when running the above code
TypeError: invalid pattern
Related
I am trying to use the Get method from the code below. I can use the Post method to post new instances to the database but my Get method is not working. When I tried to use the Get method I encountered the "AxiosError: Request failed with status code 404" error.
This is my code that contains the Get and Post methods:
const express = require('express');
const mongoose = require('mongoose');
const { ObjectId } = require('mongodb');
const { connectToDb, getDb, URI } = require('./db');
const Root = require('../models/Root');
const port = process.env.PORT || 7000;
const URL = 'http://localhost:7000'
const axios = require('axios');
// init & middleware
const app = express();
const router = express.Router();
app.use(express.json());
mongoose.set('strictQuery', false);
mongoose.set('bufferCommands', false);
let db
connectToDb((err) => {
if (!err) {
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
}
});
mongoose.connect(URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
// POST
app.post('/roots', async (req, res) => {
const { root_id, node_id, name } = req.body;
if (!root_id || !node_id || !name) {
return res
.status(400).send({ error: 'Please provide all required fields' });
}
const root = new Root({ root_id, node_id, name });
try {
const savedRoot = await root.save();
res.send(root);
} catch (err) {
//console.error('Error saving root:', err);
res.status(400).send(err);
}
});
// GET
app.get('/roots/:root_id', async (req, res) => {
try {
const response = await axios.get(
`${URL}/roots?filter={"where":{"root_id":${req.params.root_id}}}`
);
res.status(200).json(response.data);
} catch (err) {
console.error('Error getting root:', err);
res.status(400).send(err);
// res.status(500).json({ error: 'Could not fetch the root' });
}
});
// DELETE
app.delete('/roots/:root_id', async (req, res) => {
try {
await axios.delete(`${URL}/roots/${req.params.root_id}`);
res.status(200).json({ message: 'Root deleted successfully' });
} catch (err) {
console.error('Error getting root:', err);
res.status(400).send(err);
// res.status(500).json({ error: 'Could not delete the root' });
}
// Call to a method to delete all children nodes of the tree in the Node tables
});
// PATCH
app.patch('/roots/:root_id', async (req, res) => {
try {
const response = await axios.patch(
`${URL}/roots/${req.params.root_id}`,
req.body
);
res.status(200).json(response.data);
} catch (err) {
res.status(500).json({ error: 'Could not update the root' });
}
});
I use this code to connect to the database:
// Use this file to connect to database - easy to switch between local and cloud for testing
const{MongoClient} = require('mongodb')
let dbConnection
// Connect to local database
let URI = 'mongodb://127.0.0.1:27017/PM_AI'
module.exports = {
connectToDb: (cb) => {
MongoClient.connect(URI)
// MongoClient.connect(cloudURI)
.then((client) => {
dbConnection = client.db()
return cb()
})
.catch(err => {
console.log(err)
return cb(err)
})
},
getDb: () => dbConnection,
URI
}
ERROR LOG for the error that I encounter:
{
"message": "Request failed with status code 404",
"name": "AxiosError",
"stack": "AxiosError: Request failed with status code 404\n at settle (D:\\CSDS_395_Project\\AI-PM\\node_modules\\axios\\dist\\node\\axios.cjs:1900:12)\n at IncomingMessage.handleStreamEnd (D:\\CSDS_395_Project\\AI-PM\\node_modules\\axios\\dist\\node\\axios.cjs:2944:11)\n at IncomingMessage.emit (node:events:525:35)\n at endReadableNT (node:internal/streams/readable:1359:12)\n at process.processTicksAndRejections (node:internal/process/task_queues:82:21)",
"config": {
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
},
"adapter": [
"xhr",
"http"
],
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1,
"env": {},
"headers": {
"Accept": "application/json, text/plain, */*",
"User-Agent": "axios/1.3.3",
"Accept-Encoding": "gzip, compress, deflate, br"
},
"method": "get",
"url": "http://localhost:7000/roots?filter={\"where\":{\"root_id\":1}}"
},
"code": "ERR_BAD_REQUEST",
"status": 404
}
The URL that I use to test my method in Postman is http://localhost:7000/roots/1.
Please let me know what am I doing wrong with my code here.
Thank you very much!
In your expressjs server file, the url you are using in mongoose.connect() refers to the expressjs server itself instead of localhost mongodb instance
So in your server.js/app.js or whatever is your main expressjs server file,
const MONGO_URL = 'mongodb://127.0.0.1:27017/PM_AI'
I can also see that you are using both mongo client and mongoose which I don't understand why... You only need one of these libaries to connect to mongodb from your backend
Also your code is pretty messed up so I've made the following changes
No need to use mongoose strict query and other configurations, simply using mongoose.connect() in latest mongoose version is enough. As mongodb connection establishes, you can launch your server
In terminal, write npm install dotenv. It is a package that is used to access variables in .env file, without it your server won't work properly
I've removed mongo client as it is not needed, simply using mongoose is enough
I don't know why you are making axios requests to your own server. This axios thing is what is causing 404 error. You should use axios only when you need to make api calls from frontend, or make api calls from your backend to some other backend server. For your own server, you should always prefer using a controller function for every route otherwise you will get 404 error. By controller function, I mean instead of axios.get, you need to execute mongoModel.delete() instead of axios.delete() or return mongoModel.findById() instead of axios.get()
For mongodb connection, use MONGO_URL and for connecting your own server, use URL
So the final version of your code should look like:
const express = require('express');
const mongoose = require('mongoose');
const { ObjectId } = require('mongodb');
const Root = require('../models/Root');
const MONGO_URL = 'mongodb://127.0.0.1:27017/PM_AI'
const axios = require('axios');
// For environmental variables in .env file
const dotenv = require("dotenv")
dotenv.config()
// init & middleware
const app = express();
const router = express.Router();
app.use(express.json());
const port = process.env.PORT || 7000
const URL = `http://localhost:${port}`
mongoose.connect(MONGO_URL).then(() => {
console.log("Mongodb connected")
app.listen(port,() =>
{console.log("Server started") }
});
// POST
app.post('/roots', async (req, res) => {
const { root_id, node_id, name } = req.body;
if (!root_id || !node_id || !name) {
return res
.status(400).send({ error: 'Please provide all required fields' });
}
const root = new Root({ root_id, node_id, name });
try {
const savedRoot = await root.save();
res.send(root);
} catch (err) {
//console.error('Error saving root:', err);
res.status(400).send(err);
}
});
// GET
app.get('/roots/:root_id', async (req, res) => {
try {
const response = await axios.get(
`${URL}/roots?filter={"where":{"root_id":${req.params.root_id}}}`
);
res.status(200).json(response.data);
} catch (err) {
console.error('Error getting root:', err);
res.status(400).send(err);
// res.status(500).json({ error: 'Could not fetch the root' });
}
});
// DELETE
app.delete('/roots/:root_id', async (req, res) => {
try {
await axios.delete(`${URL}/roots/${req.params.root_id}`);
res.status(200).json({ message: 'Root deleted successfully' });
} catch (err) {
console.error('Error getting root:', err);
res.status(400).send(err);
// res.status(500).json({ error: 'Could not delete the root' });
}
// Call to a method to delete all children nodes of the tree in the Node tables
});
// PATCH
app.patch('/roots/:root_id', async (req, res) => {
try {
const response = await axios.patch(
`${URL}/roots/${req.params.root_id}`,
req.body
);
res.status(200).json(response.data);
} catch (err) {
res.status(500).json({ error: 'Could not update the root' });
}
});
I need to create a mysql connection in nodejs , but the credentials for the mysql comes from a third party credential manager service. Can somebody suggest me a way to achieve this?
database.js - i am using connection from this file in all other database operations
const mysql = require("mysql");
const {env} = require('./globals')
const connection = mysql.createConnection({
host: env.DATABASE.HOST,
user: env.DATABASE.USER,
password: env.DATABASE.PASSWORD,
database: env.DATABASE.NAME,
multipleStatements: true
});
connection.connect(function (err) {
if (err) {
console.log("Error in DB connection");
console.log("err", err);
} else console.log("Connected!");
});
module.exports = connection
globals.js
const {getSecret} = require('../src/service')
require("dotenv").config();
async function getCredentials() {
const result = await getSecret()
return JSON.parse(result?.SecretString || {})
}
const credentials = getCredentials() // not working, and i can't use await here
const env = {
DATABASE: {
HOST: credentials.ip_address,
PASSWORD: credentials.password,
NAME: credentials.dbname,
USER: credentials.username,
},
SKU: process.env.SKU
}
module.exports.env = env
Your 2 main options are:
Don't export connection but export an async function that returns a connection.
Write an init() function that sets up your database connection, and ensure it's one of the first things your application calls before anything else.
Well first, you need to fix up that globals.js file. Logic that depends on an async function must be async itself. You can just move everything into the async function like so:
const {getSecret} = require('../src/service')
require("dotenv").config();
async function getCredentials() {
const result = await getSecret()
const credentials = JSON.parse(result?.SecretString || {})
return {
DATABASE: {
HOST: credentials.ip_address,
PASSWORD: credentials.password,
NAME: credentials.dbname,
USER: credentials.username,
},
SKU: process.env.SKU
}
}
module.exports = { getCredentials }
And since even your database connection in database.js depends on this async function, it will have to be async as well:
const mysql = require("mysql");
const {getCredentials} = require('./globals')
const getConnection = getSecret().then(function (env) {
const connection = mysql.createConnection({
host: env.DATABASE.HOST,
user: env.DATABASE.USER,
password: env.DATABASE.PASSWORD,
database: env.DATABASE.NAME,
multipleStatements: true
});
connection.connect(function (err) {
if (err) {
console.log("Error in DB connection");
console.log("err", err);
} else console.log("Connected!");
});
return connection;
})
module.exports = getConnection
Whenever I try to run the function refreshStock() in an endpoint in one of the API endpoints /api/seller/deactivate it gives me this error:
Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (net.js:1318:16)
at listenInCluster (net.js:1366:12)
at Server.listen (net.js:1452:7)
at C:\Users\***\Documents\GitHub\***\***\.next\server\pages\api\seller\deactivate.js:191:10
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command
It looks like it's trying to restart the server, but it happens after it compiles, is there something I'm doing wrong, I've followed a couple of tutorials on medium, and they give this same type of code, just not ES Modules. I want to use ES Modules because it is what my database functions are written in.
Server.js:
import express from 'express';
import { createServer } from 'http';
import next from 'next';
import models from './server/models';
import { genStock } from './server/lib/functions';
import { Server } from 'socket.io';
const port = parseInt(process.env.PORT || '3000', 10);
const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler = nextApp.getRequestHandler();
const app = express();
const server = createServer(app);
const io = new Server(server);
const Users = models.users;
io.use(async (socket, next) => {
const err = new Error('Unauthorized');
err.data = { message: 'Unauthorized, please try again later.' };
try {
if (!socket.handshake.auth.token) return next(err);
let user = await Users.findOne({
where: {
socket_token: socket.handshake.auth.token,
},
});
if (!user) {
console.log('unauthenticated socket');
socket.disconnect();
next(err);
}
await Users.update(
{ socket_id: socket.id },
{
where: {
socket_token: socket.handshake.auth.token,
},
},
);
next();
} catch (e) {
console.log(e);
next(e);
}
});
io.on('connection', async (socket) => {
// Works fine
const stock = await genStock();
socket.emit('updateStock', stock);
});
// Fails with address already in use :::3000
export async function refreshStock() {
const stock = await genStock();
io.emit('updateStock', stock);
}
nextApp.prepare().then(async () => {
app.all('*', (req, res) => nextHandler(req, res));
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
This is meant to refresh the stock after a seller deactivates their account and sends all users the new stock.
/api/seller/deactivate
....
await refreshStock();
....
I figured it out, I just split up the WebSocket server and the next.js one. I have whitelisted local IPs that may appear to only allow server-to-server communication. Although I don't think this is full-proof as there is most likely a better way to have this type of communication but for now it works.
/**
* This server cannot be imported in /api folders, it won't work.
* Although it can import other functions
* */
import express from 'express';
import { createServer } from 'http';
import session from 'express-session';
import { Server } from 'socket.io';
import { genStock } from './server/lib/stockFunctions';
import { sessionStore } from './server/lib/session';
import passport from './server/lib/passport';
import models from './server/models';
const authorizedIPs = ['::1', '127.0.0.1', '::ffff:127.0.0.1'];
const Users = models.users;
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: `http://localhost:3000`,
methods: ['GET', 'POST'],
credentials: true,
},
});
const wrap = (middleware) => (socket, next) => middleware(socket.request, {}, next);
io.use(
wrap(
session({
secret: "---",
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
path: '/',
sameSite: 'lax',
},
store: sessionStore,
}),
),
);
io.use(wrap(passport.initialize()));
io.use(wrap(passport.session()));
io.use(async (socket, next) => {
const err = new Error('Unauthorized');
err.data = { message: 'Unauthorized, please try again later.' };
try {
const user = socket.request.user;
if (!user) return next(err);
await Users.update(
{ socket_id: socket.id },
{
where: {
id: user.id,
},
},
);
next();
} catch (e) {
console.log(e);
next(e);
}
});
io.on('connection', async (socket) => {
const stock = await genStock();
socket.emit('updateStock', stock);
});
app.post('/refresh-stock', async function (req, res) {
const ip = req.ip;
if (!authorizedIPs.includes(ip)) {
console.log(ip);
return res.status(401).json({ success: false });
}
const newStock = await genStock();
io.emit('updateStock', newStock);
return res.status(200).json({ success: true });
});
httpServer.listen(3001);
console.log(`> Websockets ready on http://localhost:3001`);
Having the following code
connection.js
import pkg from "pg";
const { Client } = pkg;
let connection = undefined;
export async function connect() {
const client = new Client({
user: "postgres",
host: "localhost",
database: "dbname",
password: "password",
port: "5432",
});
connection = await client.connect();
}
export async function query(text, values) {
try {
await connection.query(text, values);
} catch (error) {
console.error(error.message);
}
}
I intend that when calling the connect function a value is assigned to the connection variable that will then be used in the query function
This is how I call the connect method
index.js
import { connect } from "./src/connection.js";
import { handleStep1 } from "./src/step1.js";
async function init() {
await connect();
await handleStep1();
}
init();
And I intend to call the query function from another file as follows
step1.js
import { query } from "./connection.js";
export async function handleStep1() {
const results = await query("SELECT * FROM public.user", []);
console.log(results);
}
But here when calling the query function it gives me the following error message Cannot read property 'query' of undefined
What is the correct way to assign a value to a variable that will later be used in different script calls?
Thanks in advance
You can simply export a variable which is intialized and import it anywhere you want.
export async function connect() {
const client = new Client({
user: "postgres",
host: "localhost",
database: "dbname",
password: "password",
port: "5432",
});
connection = await client.connect();
}
export async function query(text, values) {
try {
await connection.query(text, values);
} catch (error) {
console.error(error.message);
}
}
// export let connection = connect();
// import it in other files. like import{ connection } from from "./connection.js";
//if you need to all connect only once. just update the line to
let connection = connect(); //remove the connection imports in other files.
I have written this login command (Login.ts) for oclif in typescript. It is supposed to get some info in the login command of the cli, then create a token with jwt and write it in a file.
import Command from '#oclif/command'
import axios from 'axios'
import {flags} from '#oclif/command'
const bcrypt = require('bcrypt');
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
export class LoginCommand extends Command {
static flags = {
user: flags.string({dependsOn:['passw']}),
//email: flags.string({dependsOn:['passw'],exlucsive:['user']}),
passw: flags.string()
}
async run() {
const {flags} = this.parse(LoginCommand);
var mysql=require('mysql')
var connection=mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'Vangelis98!',
database: 'vag'
});
await connection.query(`SELECT user,pass,email,quotas FROM users WHERE user=?`,[`${flags.user}`], function (err, result, fields) {
if (err) throw err;
console.log(`${flags.user}`);
console.log(result[0].pass);
const password=result[0].pass;
if(bcrypt.compareSync(`${flags.passw}`, password)) {
var fs=require('fs');
var privateKey = fs.readFileSync('private.key');
var jwt=require('jsonwebtoken');
var token = jwt.sign({user:`${flags.user}`,passw:`${flags.passw}`}, privateKey, { algorithm: 'RS256' });
fs.writeFileSync("temptoken.txt",token);
} else {
console.log("Wrong username or password\n");
}
});
}
}
I am running the command file like this:
energy Login --user afro --passw whatever12
And it runs correctly, but it never terminates, why? how can I fix this?
My guess would be that the database connection is not closed and therefore the program does not terminate.