Knex sometime return an empty string - mysql

I'm using knex with MYSQL. I have a function that I called to show the data to the user, Also I'm using a view table which has 5 right join on it and I think it will take some time to return values from the table plus I added the WHERE condition on my knex and it looks like this :
var showClass = (teacherId , ClassId){
return new Promise((resolve , reject)=>{
knex.select().from('v_cardex_details').where({teacherId }).andWhere({id : ClassId}).then(classes =>{
resolve(classes)
}).catch(err=>{
console.error(`Show Teacher class Error: ${err}`)
reject (err)
})
})
}
and I call this general function to response some request something like this
exports.EditClass = (req,res)=>{
knex('Table').update({//Some update stuff here}).then(()=>{
showClass(req.user.id, req.params.id).then(data=>{
return res.status(200).json({data , message:''})
})
}).catch()
}
With the same input, this function after updating returns value and some times it returns an empty string, especially when it's on the hosting server most of the time it returns nothing but { message : '' }

Try to create simplified code by removing all the unnecessary wrappers and you might find where your problem is. AFAIK there is no way that that your {data , message:''} would create an object containing just {message: ''} without any additional attributes.
> var data = []
undefined
> {data, foo:1}
{ data: [], foo: 1 }
> data = undefined
undefined
> {data, foo:1}
{ data: undefined, foo: 1 }
> {data1, foo:1}
ReferenceError: data1 is not defined
The problem you are experiencing does not exist in from the code you have shared (though there are syntax errors and other problems).
EDIT:
res.json() uses JSON.stringify() to convert js object to JSON strings. So if value of data in your code is undefined instead of and array, that could explain the behavior you are experiencing:
λ node
> JSON.stringify({ test: undefined })
'{}'
As you can see JSON.stringify() omits the attributes with value undefined from the output JSON string.

Related

console.log is different from json.push

I am using node.js to export a collection that I have in firestore.
Until now the connection and the selection of the documents of the collection work perfectly.
I am trying to save the structure in a json file but the result is not what I expected.
This is the output in the physical file:
enter image description here
On the right of the photo, it will be seen as presented by the console.log and on the right it is displayed as recorded by json.push
I can't get the physical file to have the structure shown in the console.log.
I appreciate all your help.
as you will see the structure here is failing: "USBCALI|AFILIADO|uqcMSoxdwCTQoLzS2J6brNTZ3Dy2",
":",
{.....
should be: USBCALI|AFILIADO|uqcMSoxdwCTQoLzS2J6brNTZ3Dy2 : {.....
this is the code
const jsonfile = require('jsonfile')
function start (db, file, collection) {
const ref = db.collection(collection)
const json = []
console.log(`Getting ${collection}...`)
ref
.get()
.then((snapshot) => {
snapshot.forEach((doc) => {
console.log(doc.id, ':', doc.data())
json.push(doc.id, ':', doc.data())
})
console.log(`Writing ${file}...`)
jsonfile.writeFile(file, json, {spaces: 2}, err => {
if (err) {
console.error(err)
} else {
console.log(`Collection ${collection} successfully written to ${file}.`)
}
})
})
.catch((err) => {
console.log('Error getting documents', err)
})
}
module.exports = start
Let me explain whats going on here
console.log(doc.id, ':', doc.data())
Is logging out the information how you would think you would like it to be
json.push(doc.id, ':', doc.data()) is pushing 3 elements into the array every time its called.
What you really want to do is manipulate the data properly into an object using a map function. I'm making some assumptions based on all the info I have here, but I'm guessing you want to do something like
var docs snapshot.map( doc => ({[doc.id] : doc.data()})
json.push(docs)
instead of
snapshot.forEach((doc) => {
console.log(doc.id, ':', doc.data())
json.push(doc.id, ':', doc.data())
})
You could also do (this is a bit more verbose than the map method but will essentially do the same thing. The map function is like select in sql or Linq, its handy to transform data from one form into another 😀
snapshot.forEach((doc) => {
var currentItem = {[doc.id] : doc.data()}
json.push(currentItem)
})
Since you have used some es6 notation, I'm assuming that Computed Property Names are supports, if not let me know and Ill come up with another soloution

TypeError: Converting circular structure to JSON when getting data from mysql DB

I'm following an angular-nodeJS tutorial and I'm trying to recover data from a MySQL database. Here's my db creation script:
CREATE DATABASE ng_games_db;
USE ng_games_db;
CREATE TABLE games (
id INT (11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(180),
description TEXT(255),
image VARCHAR(200),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
My db connection works cause I can add entries to my only table from my app. However, when I try to get the data with this method:
public async list (req : Request, res : Response) : Promise<void> {
const games = await pool.query('SELECT * FROM games');
res.json(games);
}
I get the following error:
(node:5828) UnhandledPromiseRejectionWarning: TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Query'
| property '_timer' -> object with constructor 'Timer'
--- property '_object' closes the circle
at JSON.stringify (<anonymous>)
at stringify (C:\Users\Dave\Documents\angular-mysql-crud\server\node_modules\express\lib\response.js:1123:12)
at ServerResponse.json (C:\Users\Dave\Documents\angular-mysql-crud\server\node_modules\express\lib\response.js:260:14)
at C:\Users\Dave\Documents\angular-mysql-crud\server\build\controllers\gamesController.js:23:17
at Generator.next (<anonymous>)
at fulfilled (C:\Users\Dave\Documents\angular-mysql-crud\server\build\controllers\gamesController.js:5:58)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
I've been searching the internet for a while trying to fix it but I've had no luck so far.
EDIT: Here is a library I've used before that might work for your situation:
https://www.npmjs.com/package/flatted
JSON.stringify doesn't handle circular references very well, like other serializers might pass a reference, stringify() crashes. You can try this, which will remove circular references:
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
JSON.stringify(games, getCircularReplacer());
// {"otherData":123}
Here is a link where the code snippet came from:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value
In the footnotes of the link above, there is also mention of cycle.js which handles circular references.
https://github.com/douglascrockford/JSON-js/blob/master/cycle.js
Ultimately, you need to find a JSON serializer/ deserializer that is capable of decoding these references.
FOR PEOPLE STILL HAVING ISSUES:
For those who still have an issue with this after adding the flatted package, you need to add this line in after you create your database pool: pool.query = util.promisify(pool.query); - source: https://mhagemann.medium.com/create-a-mysql-database-middleware-with-node-js-8-and-async-await-6984a09d49f4
If you are using typescript it will complain but simply add // #ts-ignore above it and you should be fine.
You will now be able to make mysql select queries using try/catch and async/await!!
This command works fine for your problem:
pool.query ('SELECT * FROM games', function (err, rows) {res.send (rows);});

How to cast fetch API response to a specific type in TypeScript?

I'm trying to cast the response of an API call into a specific type in my code (TypeScript). However, I didn't succeed to get the response casted to my type, but only Object.
I tried several ways, in particular what is described here: https://www.carlrippon.com/fetch-with-async-await-and-typescript/
Type:
export interface MyType{
id: number;
name: string;
date: Date;
}
Fetch code:
export default class api {
static async get<T>(url: string): Promise<T> {
return new Promise(resolve => {
fetch(url)
.then(response => response.json())
.then(body => {
resolve(body);
});
});
}
}
Caller:
const result = await api.get<MyType[]>(
"my-url-here"
);
I expect result to be of type MyType[], but it is Object[]. (with all the fields)
Further, I tried to change the type of the name field to number (while always keeping the same response from API, i.e. name is some string non-convertible to number) and expected some type casting error, but there was none. result is still created with the same content and with the same type:
result: Array(3) [Object, Object, Object]
It seems that there isn't any casting at all.
Can you please tell me where I'm wrong at, and show me what to do?
Thank you very much.
expected some type casting error, but there was none.
TypeScript doesn't cast. It asserts. It is a way for you to focefully tell the compiler what something will be at runtime. If it doesn't turn out to be that at runtime its on you.
Fix
Options, either:
change the backend response so it matches what you are asserting.
change the assertion to match what the backend is returning.
More
TypeScript Assertion

React.js: setState method setting variable to a string instead of object... is there a workaround?

I am trying to fetch a simple JSON element from express.js. I am trying have React assign it to a state variable on the front end. I am using this code to do so:
componentDidMount() {
fetch("/user")
.then(response => response.json())
.then(result => this.setState({myUser:result}))
}
But when I run typeof myUser after this setState command, it says string instead of object. I've tried using JSON.parse(), etc. But either I get an error or it continues to assign the data as a string rather than JSON. What sort of syntax do I need to use in this fetch-then context to coerce the data assignment to be JSON?
I have read this link:
With this code:
componentDidMount(){
fetch('https://abx.com/data/tool.json').then(response =>{
if (!response.ok) throw Error('Response not ok')
return response.json(); // This is built in JSON.parse wrapped as a Promise
}).then(json => {
this.setState({"sections" : json});
}).catch(err =>{
console.log(err);
});
}
But it doesn't solve the problem. I ran this code directly in my application verbatim. When I run typeof on the variable, it says string instead of object. I looked at other posts on Stack Overflow, but I did not see a solution to this.
I figured out what was going wrong (after many hours of experimenting):
On the server side, I was creating a "homegrown" JSON object using string and variable concatenation. I also tried creating the JSON object by doing this:
var str = "name:" + name + ", department:" + department
var user = {str};
Both of these were not working in subtle ways... despite trying different types of gadgetry on the client side, I couldn't get React to interpret the data as a JSON object. But then I had an idea to construct the JSON on the server side (in Express.js) like this:
var user = {};
user["name"] = name;
user["department"] = department;
That immediately cleared things up on the server side and the client side. When using setState() in React, it now sets the value as an object (which was the goal all along).
I think this can be useful to others... if React doesn't seem to understand the JSON, perhaps it is being sent from the server in a subtly incorrect format.

Multicast observable: attempting to subscribe results in "cannot read property 'subscribe' of undefined" error

I have a need in my code to perform an AJAX request and send the resulting data to two different places, so I figured using a multicast observable was the easiest way of achieving this. My code looks like this:
In the constructor for my 'app' object:
this.getEpisodeDescription = (id) => jsonLoader("http://www.randomtext.me/api/lorem/p-2/8-24", "text_out");
function jsonLoader (url, field)
{
let stream = Rx.Observable.ajax ({ url: url, crossDomain: true })
.retry (1)
.pluck ("response");
if (field !== undefined)
return stream.pluck(field);
else
return stream;
}
I've successfully used this method before to retrieve data for a single receiver, so I'm sure this is working OK. The caller is new, however:
loadSummary (id)
{
let cachedValue = this.summaries.get(id);
if (cachedValue !== undefined) return Rx.Observable.of(cachedValue);
let observable = this.app.getEpisodeDescription(id);
let multicast = observable.multicast ().refCount ();
multicast.subscribe(result => this.summaries.put(id, result));
return multicast;
}
When I try executing this method, I get the following stack trace:
Uncaught TypeError: Cannot read property 'subscribe' of undefined
at Observable.ConnectableObservable._subscribe (app.js:44193)
at Observable._trySubscribe (app.js:10253)
at Observable.subscribe (app.js:10241)
at RefCountOperator.call (app.js:44275)
at Observable.subscribe (app.js:10238)
at AsyncAction.SubscribeOnObservable.dispatch (app.js:71532)
at AsyncAction._execute (app.js:21083)
at AsyncAction.execute (app.js:21058)
at AsyncScheduler.flush (app.js:21156)
(Ignore file name and line numbers -- I'm using webpack and it doesn't seem to be producing a working line number map at the moment)
Any ideas what's going on? Specifically, how does it happen that I get an object out of the call to multicast that has appropriate subscribe etc methods, but when you try to subscribe to it it apparently can't subscribe to the parent?
The first parameter to the multicast() operator is either Subject factory function or a Subject instance.
This means you should be using it like this if you want to have one shared Subject instance:
let multicast = observable.multicast(new Subject()).refCount();
... or like this to make a new Subject for every observer:
let multicast = observable.multicast(() => new Subject()).refCount();