Nodejs mssql/msnodesqlv8 issue sending semicolon in database request - javascript

Attempting to build a basic API to interact with a MSSQL v12 database using Nodejs. I have been able to connect to the database using the mssql/msnodesqlv8 package but parameterized queries are failing with the following.
code: 'EREQUEST',
number: 102,
state: undefined,
originalError:
{ Error: [Microsoft][SQL Server Native Client 11.0][SQL Server]Incorrect syntax near ''. sqlstate: '42000', code: 102 },
name: 'RequestError' }
Debug: internal, implementation, error
I used SQL Server Profiler and saw that the query was coming in as such
exec sp_executesql N'declare #SecurityKey nvarchar (MAX);set #SecurityKey=#P1;exec database.getSecurityBySecurityId #SecurityKey;',N'#P1 nvarchar(20)',N'XXXXXXXX'
and failing. After some investigation it seems to be an issue with the semicolons after the declare and set statements as it is not allowed in TSQL (very new to MSSql, will need to read up). Removing the semicolons did indeed fix the issue when I ran the query manually.
So my question is this.. is there a way to get msnodesqlv8 to work with my version on |Mssql and if yes, how so? Is there a way to omit these semicolons.
If you think there is a better way, i would like to hear it as I am new to Nodejs + MSSql.
Contents of getSecurity.sql
exec database.getSecurityBySecurityId #SecurityKey
contents of index.js
"use strict";
const utils = require("../utils");
const api = async ({ sql, getConnection }) => {
const sqlQueries = await utils.loadSqlQueries("events");
const getSecurity = async SecurityKey => {
const cnx = await getConnection();
const request = await cnx.request();
request.input('SecurityKey', SecurityKey);
return request.query(sqlQueries.getSecurity);
};
return {
getSecurity
};
};
module.exports = { api };

I was able to work around this by editing the library.
In ./lib/msnodesqlv8.js you can find where is concatenates the query string
...
}
if (input.length) command = `declare ${input.join(',')} ${sets.join(';')};${command};`
if (output.length) {
command += `select ${output.join(',')};`
handleOutput = true
}
....
Editing this will allow you to control the flow.

Related

SCRAM-SERVER-FIRST-MESSAGE: client password must be a string

Ive read documentation from several pages on SO of this issue, but i havent been able to fix my issue with this particular error.
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string')
^
Error: SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string
at Object.continueSession (C:\Users\CNFis\Desktop\WulfDevelopments\ThePantry\node_modules\pg\lib\sasl.js:24:11)
at Client._handleAuthSASLContinue (C:\Users\CNFis\Desktop\WulfDevelopments\ThePantry\node_modules\pg\lib\client.js:257:10)
at Connection.emit (events.js:400:28)
at C:\Users\CNFis\Desktop\WulfDevelopments\ThePantry\node_modules\pg\lib\connection.js:114:12
at Parser.parse (C:\Users\CNFis\Desktop\WulfDevelopments\ThePantry\node_modules\pg-protocol\dist\parser.js:40:17)
at Socket.<anonymous> (C:\Users\CNFis\Desktop\WulfDevelopments\ThePantry\node_modules\pg-protocol\dist\index.js:11:42)
at Socket.emit (events.js:400:28)
at addChunk (internal/streams/readable.js:290:12)
at readableAddChunk (internal/streams/readable.js:265:9)
at Socket.Readable.push (internal/streams/readable.js:204:10)
its as if in my connectDB() function its not recognizing the password to the database. I am trying to run a seeder.js script to seed the database with useful information for testing purposes, and if i run npm run server which is a script that just starts a nodemon server, itll connect to the DB just fine. but when i try to run my script to seed data, i am returning this error.
import { Sequelize } from "sequelize";
import colors from "colors";
import dotenv from "dotenv";
dotenv.config();
const user = "postgres";
const host = "localhost";
const database = "thePantry";
const port = "5432";
const connectDB = async () => {
const sequelize = new Sequelize(database, user, process.env.DBPASS, {
host,
port,
dialect: "postgres",
logging: false,
});
try {
await sequelize.authenticate();
console.log("Connection has been established successfully.".bgGreen.black);
} catch (error) {
console.error("Unable to connect to the database:".bgRed.black, error);
}
};
export default connectDB;
above is my connectDB() file, and again, it works when i run the server normally. but i receive this error only when trying to seed the database. Ill post my seeder script below:
import dotenv from "dotenv";
import colors from "colors";
import users from "./data/users.js";
import User from "./models/userModel.js";
import connectDB from "./config/db.js";
dotenv.config();
console.log(process.env.DBPASS);
connectDB();
const importData = async () => {
try {
await User.drop();
await User.sync();
await User.bulkCreate(users);
console.log("Data Imported".green.inverse);
process.exit();
} catch (e) {
console.error(`${e}`.red.inverse);
process.exit(1);
}
};
const destroyData = async () => {
try {
await User.bulkDestroy();
console.log("Data Destroyed".red.inverse);
process.exit();
} catch (e) {
console.error(`${e}`.red.inverse);
process.exit(1);
}
};
if (process.argv[2] === "-d") {
destroyData();
} else {
importData();
}
Add your .env file in your project, I think your .env file is missing in your project folder.
add like this:
So, i may have figured this out by playing around in another project with sequelize, as it turns out, the initial connection to the database in my server.js file, honestly means nothing. Unlike Mongoose where the connection is available across the whole app. its not the same for Sequelize this connection that it creates is only apparent in certain places, for example i was trying the same process in my other project as i am here, except i was trying to read data from my DB using the model that i built with sequelize and i was receiving the same type error, i went into where i defined the model and made a sequelize connection there, and i was then able to read from the database using that object model.
Long story short, to fix the error in this app i have to place a connection to the database in the seeder.js file or i have to place a connection in the User model (this is ideal since ill be using the model in various places) to be able to seed information or read information from the database.
today i have same problem like this, so if you use database with type relational. you must define password from database.
const user = "postgres";
const host = "localhost";
const database = "thePantry";
const password = "yourdatabasepassword"; if null > const password = "";
const port = "5432";
but, if you use database with type non-relational, as long as the attributes are the same, you can immediately run the program as you defined it
I also faced this issue and another solution different from the accepted solution here solved my issue, so I wanted to explain that to this lovely community, too.
Firstly, when I faced the issue, ran my project in debug mode and reached the code below.
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
The problem here is actually obvious when I saw first, there is a problem in .env file as mentioned in the solutions above. In my process.env is defined as like as following line: DATABASE_URL=postgres://username:password#IP_adress:port/db_name and my config.js file is in the following format:
module.exports = {
"development": {
"url":"postgres://username:password#IP_adress:port/db_name",
"dialect": "postgres",
}, ...
}
So as a solution, I come with the following fix for the parameters that are inside Sequelize(...). My solution below is totally worked for me and I hope it also works for you too.
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.url, config);
}
Finally, the point you need to be careful about what you have written to the config file. That's the most important in this case.
Farewell y'all.
Here is my case. I have postgresql connection url in my enviroment like:
POSTGRES=postgres://postgres:test#localhost:5432/default
But my config getting like:
POSTGRES_DB_HOST=localhost
POSTGRES_DB_PORT=5432
...rest of configs
Now it has resolved.
I faced this issue because I was trying to execute nodemon from a parent folder. Once I changed my pwd, the error was resolved.
For your seeder script, i'm doing something similar but not using Sequilize, just the node-postgres package in an ExpressJS app.
To give context (so you know if this applies to your situation)
I run a separate script for testing, which uses database credentials to test batched emailing. So, I need to access my database (eventually will migrate it to an AWS lambda function).
I need to access my database and run sequential actions, since I'm not spinning up my server, all that 'under the hood' processes that would normally start your connection pool is probably not running. My guess ( I know it's an old post but this may help others).
Try passing your hardcoded password credentials. first on your seeder.js file. (i'm sure you've tried this already).
Try creating a new Pool within your seeder script and pass it your credentials (try hard coding it first to see if it works).
Pool in postgres takes a client config with the following properties (i use this to get mine to work).
const pool = new Pool({
user: '****',
database: '****',
password: '****',
port: 5432,
host: '****',
max: 5,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 5000,
})
I imagine sequilize will have a similar configuration, so try playing around with that.
Then I just connect to the pool and do everything I'd normally do.
Hope this helps with a bit of the troubleshooting. I had the EXACT same error message earlier. Ultimately I had to restructure my code to 'boot up' the Client/Connection Pool for the database. It sounds like you're not properly 'booting up' your connection so try doing it manually within your seeder script (don't pass process.env.DB_PASSWORD at first).
I saw this error when running a npx sequelize-cli db:... command
and my postgres server wasn't running or able to accept connections.
To fix it, I had to be running: postgres -D /usr/local/var/postgres in the background.

Custom auth (OAuth2) for Parse-server on docker container

So, as the title suggests, I'm looking for a way to integrate my own custom authentication service into the parse server, which is installed inside a docker container. This authentication is basically an OpenID implementation of KeyCloak.
The point is that I don't (and it would be best for my architecture not to) have parse server served with express on my local machine.
What I've been trying so far, was to search the internet, read the issues, read the parse server documents for JavaScript and the guide and other stuff to find out, how can I achieve it.
It seems that it doesn't matter what I do, at the end of each test, I get a 252 This authentication method is unsupported error! (this happens even if I use facebook, oauth, oauth2, etc).
So right now, the docker-compose service looks like this:
parse-server:
image: parseplatform/parse-server
ports:
- "${SERVER_PORT}:1337"
restart: "always"
volumes:
- ./server/parse/custom-auth:/parse-server/custom-auth
depends_on:
- mongodb
links:
- mongodb:mongo
environment:
- PARSE_SERVER_APPLICATION_ID=${APP_ID}
- PARSE_SERVER_MASTER_KEY=${MASTER_KEY}
- PARSE_SERVER_DATABASE_URI=mongodb://mongo:${MONGO_PORT}/dev
- PARSE_SERVER_START_LIVE_QUERY_SERVER=1
- PARSE_SERVER_LIVE_QUERY={"classNames":${LIVE_QUERY_CLASSES}}
- PARSE_SERVER_MOUNT_GRAPHQL=${GQL_API}
- PARSE_SERVER_MOUNT_PLAYGROUND=${GQL_PLAYGROUND}
- PARSE_SERVER_AUTH_PROVIDERS={"swwwan-mail-auth":{"module":"/parse-server/custom-auth/swwwan-mail-auth/index.js"}}
and the login/signup part:
export const loginWithParse = async (account: IUserColumnTypes) => {
if (account.username === null || account.password === null) {
throw "validation failed";
}
// #ts-ignore
const loggedIn = await Parse.User.logInWith("swwwan.mail-auth", {
authData: {
id: "",
access_token: "",
},
});
console.log({ loggedIn });
//return await Parse.User.logIn(account.username, account.password);
};
another alternative for login/signup:
export const loginWithParse = async (account: IUserColumnTypes) => {
if (account.username === null || account.password === null) {
throw "validation failed";
}
const u = new Parse.User();
u._linkWith("swwwan-mail-auth", {
authData: {
id: "tester",
access_token: "sample_access_token",
},
})
.then(res => console.log(res))
.catch(e => console.log(e));
//return await Parse.User.logIn(account.username, account.password);
};
UPDATE: by using the second alternative, I actually get the error:
error: Parse error: Invalid key name: authData.swwwan-mail-auth.id {"code":105,"stack":"Error: Invalid key name: authData.swwwan-mail-auth.id
Is there a way to make it work? probably I'm missing something here.
tnx :)
note that the 'dangle' in the link functions will be deprecated in the forthcoming 2.9 release of the Parse JS SDK
Sorry that the documentation isn't better yet. Will be getting some more work
What you're attempting is doable!
Your final error is giving one big clue: the name of your adapter can't have any characters that aren't valid for a javascript identifier. In this case, the - is causing a problem since when we save it in the database, the adapter name is used as a key.
The unit tests are often the best documentation and you may find them helpful in this case.
See:
the declaration of a custom adapter
Configuring the server to load the adapter (you're doing this right)
using the adapter

nodejs-dialogflow library returning TypeError: dialogflow.SessionsClient is not a constructor

I am trying to make a script that takes input from the user, runs it through Dialogflow, then returns it back to the user. The platform I am taking input from only supports Node.js. I am hosting the bot through glitch.com, but I don't think that's what's causing the issue. I wanted to check on here before I submit a bug report onto the GitHub repo.
var bot = 'the platform i use to accept inputs and send outputs'
bot.on("message", async message => {
console.log(message.content); // Log chat to console for debugging/testing
if (message.content.indexOf(config.prefix) === 0) { // Message starts with your prefix
let msg = message.content.slice(config.prefix.length); // slice of the prefix on the message
let args = msg.split(" "); // break the message into part by spaces
let cmd = args[0].toLowerCase(); // set the first word as the command in lowercase just in case
args.shift(); // delete the first word from the args
// You can find your project ID in your Dialogflow agent settings
const projectId = process.env.PROJECT_ID; //https://dialogflow.com/docs/agents#settings
const sessionId = 'quickstart-session-id';
var query = msg;
const languageCode = 'en-US';
// Instantiate a DialogFlow client.
const dialogflow = require('dialogflow');
const sessionClient = new dialogflow.SessionsClient();
// Define session path
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
text: query,
languageCode: languageCode,
},
},
};
// Send request and log result
sessionClient
.detectIntent(request)
.then(responses => {
console.log('Detected intent');
const result = responses[0].queryResult;
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
console.log(` Intent: ${result.intent.displayName}`);
} else {
console.log(` No intent matched.`);
}
})
.catch(err => {
console.error('ERROR:', err);
});
}
return;
});
That is the relevant part of the code. For those wondering, the process.env.PROJECT_ID is something glitch.com uses for anything private. Because I don't want random people getting their hands on my project id, I hide it in there and glitch hides it from anyone I don't explicitly invite.
Every time I execute this and try to query the bot, it returns an error Uncaught Promise Error: TypeError: dialogflow.SessionsClient is not a constructor.
If someone can direct me to what I'm missing, or what the problem is, that would be great!
As per #google-cloud/dialogflow - npm
IMPORTANT NOTE
Version 2.0.0 renames dialogflow to #google-cloud/dialogflow on npm, along with introducing TypeScript types.
So to update the dialogflow to use latest version, first uninstall dialogflow and then install with following command:
npm uninstall dialogflow
npm i #google-cloud/dialogflow
Also, if you were using older version 1.2.0 of dialogflow before then in code, make following changes as per their sample or refer the sample from above link (in require and to get the sessionPath):
const dialogflow = require('#google-cloud/dialogflow');
const sessionPath = sessionClient.projectAgentSessionPath(
projectId,
sessionId
);
It worked fine for me after doing this without any errors.
I figured it out. After many many refreshes, I decided to look at the npm documentation for it. Turns out some idiot listed the earliest version as 4.0.3, and the latest version as 0.7.0. I needed to explicitly tell it to use version 0.7.0 in order for it to work. Thank goodness!
Mine worked by reinstalling the dialogflow package
npm uninstall dialogflow
npm install dialogflow --save
put the code inside try and catch block. In my case by doing this, this error was removed.

create script to insert seed data into mongodb in node.js

I'm using mongoose and node.js (express), and I wish to insert seed data using script. Like when I do node scripts/createNotifications.js I can insert a data into my db.
My code
//createNotifications.js
const mongoose = require('mongoose')
const Notification = require('../api/models/notificationModel')
mongoose.Promise = global.Promise
module.exports = (async () => {
try {
const new_notification = await new Notification({
"userId" : mongoose.Types.ObjectId("5a3e76ce914e1d1bd854451d"),
"msg" : "Something"
}).save()
} catch(e) {
console.log('Error creating notifications. ', e)
}
})()
When I run the code I don't see any data been inserted. I have my server started in port 3000, do I have to connect to mongodb too in this file? since this file has nothing to do with my express app, it's just a separated file.
If you want to see this module running make sure the following
Make sure you've made connection with the database like mongoose.connect('mongodb://IP/DBName')
What you've posted above is just a module definition. It won't execute on its own. You'll have to require this module in your mail file, the file you're running with node for example node server.js and call the method. Something like
var notification = require(path/to/createNotifications);
notification();

CF Connect to the cloud controller

I use the following lib to connect to the cloud controller
https://github.com/prosociallearnEU/cf-nodejs-client
const endpoint = "https://api.mycompany.com/";
const username = "myuser";
const password = "mypass";
const CloudController = new (require("cf-client")).CloudController(endpoint);
const UsersUAA = new (require("cf-client")).UsersUAA;
const Apps = new (require("cf-client")).Apps(endpoint);
CloudController.getInfo().then((result) => {
UsersUAA.setEndPoint(result.authorization_endpoint);
return UsersUAA.login(username, password);
}).then((result) => {
Apps.setToken(result);
return Apps.getApps();
}).then((result) => {
console.log(result);
}).catch((reason) => {
console.error("Error: " + reason);
});
I try to run it against our API and its not working and Im not getting no error message in the console, what it can be ?
where does the space/org is handled here ? since when I connect from the cli it ask me to which space/org I want to connect...
Im able to login via the CLI, just from the code I cant, any idea what is missing here?
The issue it when I run it I dont get any error that can help to understand what is the root cause
I cloned the original git repository and modified some methods to support proxy. Please note that I modified just some methods to get the sample code working, but a complete refactor of the package is needed.
Basically what you have to do is to add a proxy parameter before calling the request method (this is done throughout the package, so several modifications are needed), for example this is for one of the methods in the Organization.js file:
getSummary (guid) {
const url = `${this.API_URL}/v2/organizations/${guid}/summary`;
const proxy = `${this.API_PROXY}`;
const options = {
method: "GET",
url: url,
proxy: proxy,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
}
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
You can find my changes in the git repository below:
https://github.com/adasilva70/cf-nodejs-client.git
I have also created a new sample below. This sample lists all organizations for a user, gets the first organization returned and lists its spaces. You can modify the code to provide a similar functionality that cf login provides (allow you to select an organization then a space).
const endpoint = "https://api.mycompany.com/";
const username = "youruser";
const password = "yourpassword";
const proxy = "http://proxy.mycompany.com:8080";
const CloudController = new (require("cf-nodejs-client")).CloudController(endpoint, proxy);
const UsersUAA = new (require("cf-nodejs-client")).UsersUAA;
const Apps = new (require("cf-nodejs-client")).Apps(endpoint, proxy);
const Orgs = new (require("cf-nodejs-client")).Organizations(endpoint, proxy);
CloudController.getInfo().then((result) => {
console.log(result);
UsersUAA.setEndPoint(result.authorization_endpoint, proxy);
return UsersUAA.login(username, password);
}).then((result) => {
//Apps.setToken(result);
//return Apps.getApps();
Orgs.setToken(result);
return Orgs.getOrganizations();
}).then((result) => {
console.log(result);
org_guid = result.resources[1].metadata.guid;
return Orgs.getSummary(org_guid);
}).then((result) => {
console.log(result);
}).catch((reason) => {
console.error("Error: " + reason);
});
I have done just minor tests to make sure the sample works, so use carefully. Also, the changes will only work for a case where proxy is needed now.
The first thing that strikes me on the library's github site is the warning:
Note: This package is not ready for a production App yet.
It also seems that the project is not being maintained as there are a number of tickets ooened that are quite a few months old that don't have a response.
Anyway, to figure out why the library is not working and producing no error message, I would check out the library source code and add some console logging statements, probably starting with the HttpUtils. For example:
requestWithDefaults(options, function (error, response, body) {
console.log("requestWithDefaults error: ", error)
console.log("requestWithDefaults response: ", response)
console.log("requestWithDefaults body: ", body)
...
}
Alternatively, you could try debugging the code by adding breakpoints to the requestWithDefaults and other key places in the library, using the nodejs debugger.
You could also try debugging the network calls similar to this how to monitor the network on node.js similar to chrome/firefox developer tools?
To understand how to use the library, I would take a look into the tests folder and look for a test that is similar to your use case. There are a reasonable amount if tests that look useful in the test/lib/model/cloudcontroller folder.
As for the question about spaces, I have found an example where you can pass in a space guid to return apps for that space guid.
CloudFoundrySpaces.getSpaceApps(space_guid, filter).then( ... )
I'm assuming the call you are using App.getApps() will return Apps for all spaces/organizations.

Categories

Resources