Running raw complicated queries with sequelize - javascript

I have a peculiar problem. I have a joined query due to the distribution of data in various table. I want to run this as raw sql query using node module for sequelize as alot existing code is associated using sequelize orm. I do not want to use orm here but just a plain raw query.
SELECT testmodel.bacode, testmodel2.paopkey from (SELECT ptr.paopkey as paopkey, psgkey.pskey from (SELECT * FROM pts where paopkey = 4 and ptr_active = 1) ptr,
pt_sg psgkey where ptr.pkey = psgkey.pkey) testmodel2,
pt_act testmodel where testmodel.pskey = testmodel2.pskey;
Any advise if the above query can be run as raw query and the data can be captured as result.
Also when I run the below code with below sequelize code, I get
the error "_sequelize.default.query is not a function"
import Sequelize from 'sequelize';
async function getTestDataList(opcoKey) {
const testdata = await Sequelize.query(`SELECT testmodel.bacode, testmodel2.paopkey from (SELECT ptr.paopkey as paopkey, psgkey.pskey from (SELECT * FROM pts where paopkey = 4 and ptr_active = 1) ptr,
pt_sg psgkey where ptr.pkey = psgkey.pkey) testmodel2,
pt_act testmodel where testmodel.pskey = testmodel2.pskey;`,
{ type: Sequelize.QueryTypes.SELECT }).then(function (results) {
// SELECT query - use then
})
return toPlain(testdata);
}
Dbclient code using sequelize instance is as follows
import config from 'config';
import Sequelize from 'sequelize';
class DataSource { constructor() {this.DBclient = null; }
initializeDB(dbCredentials) { const dataSource = config.datasource;
const options = { host: "127.0.0.1", dialect: dataSource.dialect, port: dataSource.port, logging: false, };
const { password } = dbCredentials || dataSource;
this.DBclient = new Sequelize( dataSource.database, "root", "root", options, );
} getDBClient() { return this.DBclient; }}export default new DataSource();

You should store a created Sequelize connection and use it to call query method:
const sequelize = new Sequilize(connection_options_here)
const testdata = await sequelize.query(`SELECT testmodel.bacode, testmodel2.paopkey from (SELECT ptr.paopkey as paopkey, psgkey.pskey from (SELECT * FROM pts where paopkey = 4 and ptr_active = 1) ptr,
pt_sg psgkey where ptr.pkey = psgkey.pkey) testmodel2,
pt_act testmodel where testmodel.pskey = testmodel2.pskey;`,
{ type: Sequelize.QueryTypes.SELECT })
I removed then in the above code because there is no need in it thus you use await.

Related

How to update parameterized SELECT query in node.js with postgres

I have a problem with fetching specific columns from the database. I want to fetch balance for a user with provided user_id and currency.
And I'm getting >[ { '?column?': 'USD' } ] for provided currency = 'USD', instead of [ {'USD': 1.2}]. And when I don't use column name then I'm fetching whole balances for a user.
The table is looking something like this:
user_id | USD | EUR | GBP | ...
123123 1.2 2.3 3.4
(Balances for that user in that currency), so for user 123123, his USD balance is 1.2, EUR is 2.3 and GBP is 3.4
import dotenv from 'dotenv';
import pkg from 'pg';
dotenv.config();
const {Pool, Client} = pkg
const DB_USER = process.env.DB_USER;
const DB_HOST = process.env.DB_HOST;
const DB_DATABASE = process.env.DB_DATABASE;
const DB_PASSWORD = process.env.DB_PASSWORD;
const DB_PORT = process.env.DB_PORT;
const credentials = {
user: DB_USER,
host: DB_HOST,
database: DB_DATABASE,
password: DB_PASSWORD,
port: DB_PORT,
};
async function getBalance(user_id, currency) {
const pool = new Pool(credentials);
const res = await pool.query('SELECT $1 FROM wallet WHERE user_id = $2;', [currency, user_id]);
console.log(res.rows);
await pool.end();
}
You cannot parameterise a column name, you'll need to build the SQL string dynamically for that:
async function getBalance(user_id, currency) {
const client = new Client(credentials);
await client.connect();
const query = 'SELECT '+client.escapeIdentifier(currency)+' FROM wallet WHERE user_id = $1;';
const res = await client.query(query, [user_id]);
console.log(res.rows);
await client.end();
}
You might also want to validate the currency names to be existing columns (and not 'user_id'), like
if (!['USD', 'EUR', 'GBP'].includes(currency)) throw new RangeError('Currency not available');

SvelteKit: How to call mongodb without using endpoints?

(1/9/2023) Update : SvelteKit now supports server only load functions and Form actions to send requests to the server.
I want to call my database, but I don't want it be able to get accessed by end users by them going to the API endpoint that I set up. I was wondering how I would be able to just call my database from a file in the lib folder and just returning the data there. When I try it I get the error global not defined:
lib/db.js:
import dotenv from "dotenv";
dotenv.config();
import { MongoClient } from "mongodb";
const uri = process.env["MONGODB_URI"];
const options = {
useUnifiedTopology: true,
useNewUrlParser: true,
};
let client;
let clientPromise;
if (!uri) {
throw new Error("Please add your Mongo URI to .env.local");
}
if (process.env["NODE_ENV"] === "development") {
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options);
global._mongoClientPromise = client.connect();
}
clientPromise = global._mongoClientPromise;
} else {
client = new MongoClient(uri, options);
clientPromise = client.connect();
}
export default clientPromise;
routes/items/index.js:
import clientPromise from "$lib/db";
export async function get() {
const client = await clientPromise;
const db = client.db();
const data = await db.collection("items").find({}).toArray();
const items = data.map(({ name }) => ({ name }));
if (items) {
return {
body: {
items,
},
};
}
}
My attempt:
lib/stores/items.js
import clientPromise from "$lib/db";
import { writable } from "svelte/store";
export const items= writable([]);
const fetchItems = async () => {
const client = await clientPromise;
const db = client.db();
const data = await db.collection("items").find({}).toArray();
const items = data.map(({ name }) => ({ name }));
substances.set(items);
};
fetchItems();
Trying the above code in various places always yields a global not defined error in the client.
I found one question from someone with the same problem, but I couldn't figure out how to create a helper file.
Protecting API is done on back-end side. Usually it either server (like NodeJS) or tools Nginx/Apache (proxy, etc.). You're basically looking for Content-Security-Policy topic, which is vaporous but not related to SvelteKit.
Btw, calling DB directly from the Front-end wouldn't be secure and is not possible.
To get data from any database, you should create enpoint
For user authentication, you can create handle hook:
export async function handle({ request, resolve }) {
let user = await authenticate(request)
request.locals.user = user
request.locals.isAuthenticated = !!user
if (request.path.startsWith('/api')) {
if (!user) {
return {
status: 401,
body: JSON.stringify({
error: {
message: 'Unauthorized'
}
})
}
}
const response = await resolve(request)
return response
}

Checking if a value exists in a column of a database from a promisified Postgres query

Here's my code:
const util = require('util')
const { Client } = require('pg');
const db = new Client({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
}
});
db.connect();
const queryP = util.promisify(db.query)
async function doStuff() {
let inDatabase = await queryP.call(db, 'SELECT EXISTS(SELECT 1 FROM searchtable WHERE val = $1) AS it_does_exist', [testValue]);
console.log("In the Database: " + inDatabase);
}
Essentially, I'm trying to return some kind of binary option (true/false) where the inDatabase is set to one thing if the 'testValue' is found in the table's 'val' column and the other thing if it isn't. I tried adapting this:
Check value if exists in column
but I keep getting an object returned, instead of the true/false it says should be returned...thanks for any and all help!
Output of JSON.stringify() is:
2021-05-10T22:26:17.723899+00:00 app[web.1]: In the Database: {"command":"SELECT","rowCount":1,"oid":null,"rows":[{"it_does_exist":false}],"fields":[{"name":"it_does_exist","tableID":0,"columnID":0,"dataTypeID":16,"dataTypeSize":1,"dataTypeModifier":-1,"format":"text"}],"_parsers":[null],"_types":{"_types":{"arrayParser":{},"builtins":{"BOOL":16,"BYTEA":17,"CHAR":18,"INT8":20,"INT2":21,"INT4":23,"REGPROC":24,"TEXT":25,"OID":26,"TID":27,"XID":28,"CID":29,"JSON":114,"XML":142,"PG_NODE_TREE":194,"SMGR":210,"PATH":602,"POLYGON":604,"CIDR":650,"FLOAT4":700,"FLOAT8":701,"ABSTIME":702,"RELTIME":703,"TINTERVAL":704,"CIRCLE":718,"MACADDR8":774,"MONEY":790,"MACADDR":829,"INET":869,"ACLITEM":1033,"BPCHAR":1042,"VARCHAR":1043,"DATE":1082,"TIME":1083,"TIMESTAMP":1114,"TIMESTAMPTZ":1184,"INTERVAL":1186,"TIMETZ":1266,"BIT":1560,"VARBIT":1562,"NUMERIC":1700,"REFCURSOR":1790,"REGPROCEDURE":2202,"REGOPER":2203,"REGOPERATOR":2204,"REGCLASS":2205,"REGTYPE":2206,"UUID":2950,"TXID_SNAPSHOT":2970,"PG_LSN":3220,"PG_NDISTINCT":3361,"PG_DEPENDENCIES":3402,"TSVECTOR":3614,"TSQUERY":3615,"GTSVECTOR":3642,"REGCONFIG":3734,"REGDICTIONARY":3769,"JSONB":3802,"REGNAMESPACE":4089,"REGROLE":4096}},"text":{},"binary":{}},"RowCtor":null,"rowAsArray":false}

How should I structure the data layer of a node.js server using node-postgres client?

I am working on a server in Node.js that uses node-postgres database client. I am trying to follow the 3 layer architecture (controllers, services, models). So far I have been using a Pool for all queries. However, now I need to perform transactions and that requires a single client throughout the whole transaction. I came up with a solution to pass an optional client parameter into the query function (without supplying the client, the query will be performed on the default pool). This way, the service layer can create a client and call other services that perform database operations with the created client in order to perform a transaction. However this means I will also have to add the optional client parameter into every service that is responsible for retrieving the data. Is the solution I came up with a good approach or are there any better solutions? Iam also unsure how should the model layer look like without using an ORM and wasn't able to find any examples. Would you say I should use an ORM like sequalize? I will appreciate any advice, so feel free to point out anything.
Code example:
./db/index.js
const { Pool, Client } = require("pg");
const config = require("../config");
const pool = new Pool({
connectionString: config.databaseURL,
max: 20,
ssl: {
rejectUnauthorized: false,
},
});
/**
* #param {object} obj
* #param {string} obj.query
* #param {any[]} [obj.values]
* #param {Client} [obj.client]
*/
exports.query = ({ query, values, client }) => {
return client === undefined
? pool.query(query, values)
: client.query(query, values);
};
// returns the client
exports.connect = () => {
return pool.connect();
};
./models/pipe.model.js
const db = require("../db");
/**
* #param {number | string} id ID of the pipe
* #param {import("pg").Client} [client]
*/
exports.getById = (id, client) => {
const query = `SELECT id, price, state, tone_id, rank_id FROM pipe
WHERE id = $1`;
return db.query({ query, values: [id], client });
};
./services/pipe.service.js
const pipeModel = require("../models/pipe.model");
const StatusError = require("../helpers/error");
/**
* #param {number | string} id
* #param {import("pg").Client} [client]
*/
exports.getById = async (id, client) => {
let rows, rowCount;
try {
({ rows, rowCount } = await pipeModel.getById(id, client));
} catch (err) {
throw new StatusError(500, "Error retrieving data");
}
if (rowCount !== 1) {
throw new StatusError(404, "Pipe with gived ID not found");
}
return rows[0];
};

How to mock pg in JavaScript?

I am new to mock concept and javascript programming either. I want to to mock pg (postgres module) in the javascript program. I can imitate very simple scenario, but in actual I don't.
Here is my userHandler.js:
var pg = require('pg');
var connectionString = process.env.DATABASE_URL || 'postgres://admin:admin#localhost:5432/mydb';
exports.handlePost = function(req,res){
var results = [];
// Grab data from http request
var adata = [req.body.Username, ..., req.body.FaxNum]; //Ignore for short.
// Get a Postgres client from the connection pool
pg.connect(connectionString, function(err, client, done) {
// SQL Query > Insert Data
var func_ = 'SELECT Dugong.Users_Add($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19)';
var addUser_ = client.query(func_, adata);
addUser_.on('error', function(error){
var data = {success : false,
username : req.body.Username,
reason : {errmsg : error.detail,
errid : 'addUser_' }};
return res.json(data);
});
addUser_.on('end',function(result){
var data = {success : true, username : req.body.Username};
console.log('Insert record completed');
return res.json(data);
});
// Handle Errors
if(err) {
console.log(err);
return ;
}
return;
});
};
And here is my unit test file. m_users_page.js:
var express = require('express');
var router = express.Router();
var test = require('unit.js');
var mock = require('mock');
var httpMocks = require('node-mocks-http');
var real_users_page = require('../routes/users_page.js');
var b = mock("../routes/userHandler.js", {
pg: {
connect: function (connectionString,callback) {
if(connectionString === 'postgres://admin:admin#localhost:5432/skorplusdb'){
console.log('333');
//pseudo object
var client = {query : function(func_, adata, cb){
cb(null,adata);
}};
client.on('error', 'test emit the error in my mock unit.');
//pseudo done object
var done = function(){};
callback(null, client, done);
return ;
}
}
}
}, require);
describe('Test with static login', function(){
it('Test simple login', function(done){
var request = httpMocks.createRequest({
method: 'POST',
url: '/users',
body: { Username:"Je", ..., FaxAreaCode:'232'} //Ignore for short
});
var response = httpMocks.createResponse();
b.handlePost(request,response, function(){
var data = response._getData();
console.log("7777777777" + data);
done();
});
});
});
Here is the error :
$ mocha testing/m_users_page.js
Test with static login
333
1) Test simple login
0 passing (7ms)
1 failing
1) Test with static login Test simple login:
TypeError: Object #<Object> has no method 'on'
at Object.mock.pg.connect (testing/m_users_page.js:22:14)
at Object.exports.handlePost (routes/userHandler.js:30:6)
at Context.<anonymous> (testing/m_users_page.js:63:5)
My questions are:
What is a proper way to do a unit test in Node + Express + Mock + node-mocks-http?
How to find good framework with well document I must read. After several days, I started to circling around the result from search engines. They are too simple, I can't adapt it to my problem.
First, make sure you understand the difference between unit tests and integration tests. If you want to test against the actual db, even if it has a dummy data set, that's an integration test and it doesn't need a mock: just connect to the database with the dummy data.
But suppose you want to test your webserver module, and you want to mock the db. First, pass the database module as a parameter rather than requiring pg directly. Also, wrap the postgres interface with your own class:
const { Pool } = require('pg');
module.exports = class DatabaseInterop {
// Connection parameters can be passed to the constructor or the connect method, parameters to
// DatabaseInterop::connect will override the initial constructor parameters.
constructor ({
user,
password,
database,
host,
logger={log: console.log, err: console.error},
}) {
this.logger = logger;
this._params = {
user,
password,
database,
host,
};
}
connect (params) {
const {
user,
password,
database,
host,
} = Object.assign({}, this._params, params);
this._pool = new Pool({
user,
password,
database,
host,
});
['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGTERM'
].forEach(function (sig) {
process.on(sig, async () => {
logger.log(`Exiting for ${sig}...`);
process.exit(0);
});
});
return this;
}
async stop () {
return this._pool.end();
}
runQuery (queryString, params=[]) {
return params.length ? this._pool.query(queryString, params) : this._pool.query(queryString);
}
};
Now to mock it out, you can simply extend your custom class in your test file:
const DatabaseInterop = require('/path/to/database_interop.js');
class MockDB extends DatabaseInterop {
connect () {
// no-op
}
runQuery (qs, ...params) {
// return whatever
}
stop () {
// noop
}
}
Now for your tests you can inject the mock and your actual system inject the actual interface.

Categories

Resources