A variable has no status key, but var.status gives string - javascript

Its a mongoose/express app, I have a route like this:
// ..
Posts.find({})
.then(function(posts) {
var data = _.chain(posts).filter(function(post) {
if(post.comment) {
return post.updatedAt <= post.comment.lastCreatedAt;
} else {
return true;
}
}).each(function(post) {
if(post.comment) {
post.status = 'OK';
} else {
post.status = 'NOT OK';
}
console.log("post")
console.log(post)
console.log("post.status")
console.log(post.status)
}).value();
})
// ..
But the log is
"post"
{
_id: ***,
title: 'test',
content: 'test',
user: ***
}
"post.status"
OK
why there's no status in first console.log(post) ?

The post is a Document object which means it has a custom toJSON method that only yields the properties of your schema and the _id.
You can get an object representation of the document via the toObject method.

Related

How to add a field to a GraphQL document?

Let's say this is my graphql query:
mutation Test ($input: UpdateUserAccountInput!) {
updateUserAccount(input: $input) {
... on UpdateUserAccountPayload {
userAccount {
name
}
}
}
}
I want to modify to have the following fragment:
... on Error {
message
}
I was able to figure out that I can get AST using parse from graphql package, i.e.
import {
parse,
gql,
} from 'graphql';
parse(gql`
mutation Test ($input: UpdateUserAccountInput!) {
updateUserAccount(input: $input) {
... on UpdateUserAccountPayload {
userAccount {
name
}
}
}
}
`)
Now I am trying to figure out how to add ... on Error { message } to this query.
The problem that I am trying to solve is that my tests sometimes quietly fail because mutation returns an error that I did not capturing. I am extending my GraphQL test client to automatically request errors for every mutation and throw if error is returned.
I assume there exists some utilities that allow me to inject fields into AST, but so far I was not able to find them.
I think I figured it out.
Here is my solution:
const appendErrorFieldToMutation = (query: string) => {
const inlineErrorFragmentTemplate = {
kind: 'InlineFragment',
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: {
kind: 'Name',
value: 'message',
},
},
],
},
typeCondition: {
kind: 'NamedType',
name: {
kind: 'Name',
value: 'Error',
},
},
};
const document = parseGraphQL(query);
if (document.definitions.length !== 1) {
throw new Error('Expected only one definition');
}
const definition = document.definitions[0] as OperationDefinitionNode;
if (definition.operation !== 'mutation') {
return query;
}
if (definition.selectionSet.selections.length !== 1) {
throw new Error('Expected only one document selection');
}
const documentSelection = definition.selectionSet.selections[0] as InlineFragmentNode;
const errorField = documentSelection.selectionSet.selections.find((selection) => {
return (selection as InlineFragmentNode).typeCondition?.name.value === 'Error';
});
if (!errorField) {
// #ts-expect-error – Intentionally mutating the AST.
documentSelection.selectionSet.selections.unshift(inlineErrorFragmentTemplate);
}
return printGraphQL(document);
};
I've not used any utilities, so perhaps there is a smarter way to do the same.

Assignment of Nuxt Axios response to variable changes response data content

async fetch() {
try {
console.log(await this.$api.events.all(-1, false)); // <-- First log statement
const res = await this.$api.events.all(-1, false); // <-- Assignment
console.log(res); // <-- Second log statement
if (!this.events) {
this.events = []
}
res.data.forEach((event, index) => {
const id = event.hashid;
const existingIndex = this.events.findIndex((other) => {
return other.hashid = id;
});
if (existingIndex == -1) {
this.events.push(events);
} else {
this.events[existingIndex] = event;
}
});
for (var i = this.events.length - 1; i >= 0; --i) {
const id = this.events[i].hashid
const wasRemoved =
res.data.findIndex((event) => {
return event.hashid == id
}) == -1
if (wasRemoved) {
this.events.splice(i, 1)
}
}
this.$store.commit('cache/updateEventData', {
updated_at: new Date(Date.now()),
data: this.events
});
} catch (err) {
console.log(err)
}
}
// The other functions, maybe this somehow helps
async function refreshTokenFirstThen(adminApi, func) {
await adminApi.refreshAsync();
return func();
}
all(count = -1, description = true) {
const func = () => {
return $axios.get(`${baseURL}/admin/event`, {
'params': {
'count': count,
'description': description ? 1 : 0
},
'headers': {
'Authorization': `Bearer ${store.state.admin.token}`
}
});
}
if (store.getters["admin/isTokenExpired"]) {
return refreshTokenFirstThen(adminApi, func);
}
return func();
},
Both log statements are giving slightly different results even though the same result is expected. But this only happens when is use the function in this specific component. When using the same function in other components, everything works as expected.
First data output:
[
{
"name": "First Name",
"hashid": "VQW9xg7j",
// some more correct attributes
},
{
"name": "Second name",
"hashid": "zlWvEgxQ",
// some more correct attributes
}
]
While the second console.log gives the following output:
[
{
"name": "First Name",
"hashid": "zlWvEgxQ",
// some more correct attributes, but this time with reactiveGetter and reactiveSetter
<get hashid()>: reactiveGetter()
​​ length: 0
​​​​ name: "reactiveGetter"
​​​​ prototype: Object { … }
​​​​<prototype>: function ()
​​​<set hashid()>: reactiveSetter(newVal)
​​​​length: 1
​​​​name: "reactiveSetter"
​​​​prototype: Object { … }
​​​​<prototype>: function ()
},
{
"name": "Second name",
"hashid": "zlWvEgxQ",
// some more correct attributes and still without reactiveGetter and reactiveSetter
}
]
As it can be seen, somehow the value of my hashid attribute changes, when assigning the response of the function call.
The next weird behavior happening here, is that the first object where the hashid field changes also gets reactiveGetter and reactiveSetter (but the second object in the array does not get these).
So it looks to me like something is happening with the assignment that I don't know about. Another guess would be that this has something to do with the Vuex store, because I do not change the Vuex tore in the other place where I use the same function.
It is verified that the backend always sends the correct data, as this is dummy data, consisting of an array with two objects with some attributes. So no other data except this two objects is expected.
Can someone explain to me why this behavior occurs?
There are few problems...
Do not use console.log with objects. Browsers tend to show "live view" of object - reference
this.events.findIndex((other) => { return other.hashid = id; }); is wrong, you are using assignment operator (=) instead of identity operator (===). That's why the hashid of the first element changes...

How can i assign nested data to a new variable?

I want to create a new variable line and make it contain nested data.
What I am expecting as result:
{
description: "descriptionString",
vatInfo : {
vatAccount: {
vatCode : "vatCode"
}
}
}
How I am doing it:
export function changeProductOnLine(originalLine, product, customer, invoice) {
let line = { ...originalLine, product }
if (product) {
const vatCode = getProductVatCode(line, invoice)
line.description = buildLineDescription(product.name, product.description)
line.vatInfo.vatAccount.vatCode = "v10"
return line
}
Is it correct what I am doing ? Can it work ?
What you're doing is close, but you need to keep in mind that when you use a spreader like that, what you'll end up with is this:
{
description: "descriptionString",
vatInfo : {
vatAccount: {
vatCode : "vatCode"
}
},
product: {
description: "descriptionString",
vatInfo : {
vatAccount: {
vatCode : "vatCode"
}
}
}
}
What I think you want is for product to overwrite the values, but not end up with a 'product' property in your object, based on what you explained you wanted. Try this:
export function changeProductOnLine(originalLine, product, customer, invoice) {
if (product) {
return {
...originalLine,
// since these are the last thing in the new obj it will overwrite anything in the obj
description: buildLineDescription(product.name, product.description),
vatInfo: {
vatAccount : {
vatCode: getProductVatCode(line, invoice)
}
}
}
} else {
return line
}
}
This way, you also don't end up creating a new variable in memory just to modify it slightly then return it. It all happens at once, and ONLY if you have a arg 'product' value other than undefined or null

Can't Store Result of GraphQL Query - Always undefined

I am doing a query and have already logged the result. Everything works as it should, however when I want to continue working with the result it always is "undefined" (see 2nd logging).
I am sure I am missing out on something obvious here but would really love to get your help :)
render() {
let saved;
this.props.apolloClient
.watchQuery<Query>({
query: gql`
query($id: ID!) {
element(id: $id) {
children {
... on TextNote {
name
description
type
}
}
}
}
`,
variables: { id: 0 }
})
.subscribe(({ data: { element: { children } } }) => {
console.log(children); // this is the wanted result
saved = children;
});
console.log("save");
console.log(saved); // this is undefined for some reason
If children gives you the correct result, can you not just assign your variable saved to your this.props.apolloClient function and return children inside the subscribe call?
Something like:
render() {
const saved = this.props.apolloClient
.watchQuery<Query>({
query: gql`
query($id: ID!) {
element(id: $id) {
children {
... on TextNote {
name
description
type
}
}
}
}
`,
variables: { id: 0 }
})
.subscribe(({ data: { element: { children } } }) => {
console.log(children); // this is the wanted result
return children; // <-- return the value here
});
console.log("save");
console.log(saved); // <-- should have children assigned to saved

mongoose findOneAndUpdate deletes nested vars

In my express/mongoose code when I update a nested var it deletes any other nested vars in the object I didn't update?
My schema:
var MySchema = new Schema({
active: { type: Boolean, required: true, default: true },
myvar: {
useDefault: { type: Boolean, required: true },
custom: { type: String },
default: { type: String }
}
});
My express middleware update function:
var updateData = req.body;
MySchema.findOneAndUpdate({ active: true }, updateData, function(err, myschema) {
if (err) throw err;
if (!myschema) { response(403, { success:false, message: "myschema not updated." }, res); }
// success
response(200, { success:true, message: "myschema updated." }, res);
});
The record initially look like this:
{
"myvar": {
"useDefault": true,
"custom": "some custom var",
"default": "some value"
}
}
When I submit an update to say the myvar.useDefault value the record ends up like this:
{
"myvar": {
"useDefault": false
}
}
Can anyone advise how to update only the targeted var and leave any other vars as they were?
The answer was to convert the response.body object to dot notation and pass that modified object to mongoose findOneAndUpdate. Thanks to #btkostner on Gitter for the answer and his toDot function. Here is the relevant bits of code:
function(req, res) {
// convert response to dot notation so objects retain other values
var dotData = toDot(req.body, '.');
MySchema.findOneAndUpdate({ active: true }, dotData, function(err, myschema) {
...
}
// author: #btcostner
function toDot (obj, div, pre) {
if (typeof obj !== 'object') {
throw new Error('toDot requires a valid object');
}
if (pre != null) {
pre = pre + div;
} else {
pre = '';
}
var iteration = {};
Object.keys(obj).forEach(function(key) {
if (_.isPlainObject(obj[key])) {
Object.assign(iteration, _this.toDot(obj[key], div, pre + key));
} else {
iteration[pre + key] = obj[key];
}
});
return iteration;
};
NOTE: I had to convert the toDot() function to ES5 for my project, here is the original ES6 version: github.com/elementary/houston/blob/master/src/lib/helpers/dotNotation.js

Categories

Resources