GraphQl mutation wrong result - javascript

I have some troubles with mutating data within Graphql. I am saving the origin image into my database and then mutating it with Graphql (external).
In the following points in the code I get the correct data
####################1111111111111111111####################
####################222222222222222####################
####################333333333333333####################
But at point
####################444444444444444444####################
after I mutate the data I am getting wrong image src. It is the edited image src and not the origin src I retrieved from database in my revertImages() function.
Although I pass the correct variable "newVariable" with correct data, the mutation takes over the mutation function edited data that I had previously passed, but takes over the newVariable data. Do I need to clear the cache maybe?
The newVariable data is:
{
productId: 'gid://shopify/Product/6166892019882',
image: {
altText: '',
id: 'gid://shopify/ProductImage/23268973543594',
src: 'https://cdn.shopify.com/s/files/1/0508/3516/1258/products/180622-05-2.jpg?v=1611416719'
}
}
After mutation the result is:
{
productImageUpdate: {
image: {
altText: null,
id: 'gid://shopify/ProductImage/23268973543594',
src: 'https://cdn.shopify.com/s/files/1/0508/3516/1258/products/180622-05-2.jpg?v=1611416762'
},
userErrors: []
}
}
Here are my functions:
const revertImages = async (ctx) => {
let dataToRevert = ctx.request.body.data;
const { accessToken } = ctx.session;
let productsDoc = await Product.find({ productId: { $in: dataToRevert.productId } });
if (!productsDoc) {
ctx.throw('Could not find products');
}
console.log('####################1111111111111111111####################');
console.log(productsDoc);
console.log('####################1111111111111111111####################');
const res = await revertProductImages(productsDoc, accessToken);
if (res) {
console.log('Products reverted');
ctx.response.status = 200;
}
}
async function revertProductImages(products, accessToken) {
console.log('Revert Product Images')
return new Promise((resolve, reject) => {
const map = {};
let updateProduct = null;
let variables = null;
products.forEach(async (item) => {
map[item.productId] = map[item.productId] + 1 || 1;
variables = {
"productId": `gid://shopify/Product/${item.productId}`,
"image": {
"altText": "",
"id": `gid://shopify/ProductImage/${item.imageId}`,
"src": item.originalSrc
}
};
console.log('####################222222222222222####################');
console.log(variables);
console.log('####################222222222222222####################');
updateProduct = await updateProductImage(UPDATE_PRODUCT_BY_ID, variables, accessToken);
if (updateProduct) {
const res = await removeProductFromDb(map);
if (res) {
resolve(res);
}
}
});
})
}
async function updateProductImage(queryName, variables, token) {
console.log('updateProductImage..');
const newVariable = variables;
console.log('####################333333333333333####################');
console.log(newVariable);
console.log('####################333333333333333####################');
return new Promise(async (resolve, reject) => {
let res = null;
try {
res = await axios({
headers: {
'X-Shopify-Access-Token': token,
},
method: 'post',
data: {
query: queryName,
variables: newVariable,
},
url: url,
});
} catch (err) {
console.log(err.message);
}
if (res) {
console.log('Image updated ✔️');
console.log('####################444444444444444444####################');
console.log(res.data.data);
console.log('####################444444444444444444####################');
resolve(res);
} else {
reject('Can not update image');
}
}).catch((err) => {
console.log(err);
});
}

Maybe I didn't understood correctly but here's an answer...
I cannot find the src property in available fields for this mutation (i'm not talking about the ImageInput but the image object).
Can you try with the following request :
mutation productImageUpdate($productId: ID!, $image: ImageInput!) {
productImageUpdate(productId: $productId, image: $image) {
image {
id
originalSrc
transformedSrc
}
userErrors {
field
message
}
}
}
The docs says :
originalSrc : The location of the original image as a URL.
transformedSrc : The location of the transformed image as a URL.
Maybe what you are expecting is in originalSrc ?

Related

Broadcasting to all clients with Deno websocket

I want to add notifications to an application I've developed.
Unfortunately, Deno has removed the ws package.(https://deno.land/std#0.110.0/ws/mod.ts)
That's why I'm using the websocket inside the denon itself. Since it doesn't have many functions, I have to add some things myself.
For example, sending all messages to open clients.
What I want to do is when the pdf is created, a (data, message) comes from the socket and update the notifications on the page according to the incoming data.
I keep all open clients in a Map. and when the pdf is created, I return this Map and send it to all sockets (data, message).
However, this works for one time.
server conf...
import {
path,
paths,
ctid,
} from "../deps.ts";
const users = new Map();
const sockets = new Map()
const userArr = [];
export const startNotif = (socket,req) => {
const claims = req.get("claims");
const org = req.get("org");
claims.org = org;
console.log("connected")
users.set(claims.sub, {"username":claims.sub,"socket":socket})
users.forEach((user)=>{
if(userArr.length === 0){
userArr.push(user)
}
else if(userArr.every((w)=> w.username !== user.username) )
userArr.push(user)
})
sockets.set(org, userArr)
function broadcastMessage(message) {
sockets.get(org).map((u)=>{
console.log(u.socket.readyState)
u.socket.send(message)
})
}
if (socket.readyState === 3) {
sockets.delete(uid)
return
}
const init = (msg) => {
socket.send(
JSON.stringify({
status: "creating",
})
);
};
const ondata = async (msg) => {
const upfilepath = path.join(paths.work, `CT_${msg.sid}_report.pdf`);
try {
const s=await Deno.readTextFile(upfilepath);
if(s){
socket.send(
JSON.stringify({
status: "end",
})
);
} else {
socket.send(
JSON.stringify({
status: "creating",
})
);
}
} catch(e) {
if(e instanceof Deno.errors.NotFound)
console.error('file does not exists');
}
};
const end = () => {
try {
const endTime = Date.now()
const msg = "Your PDF has been created"
const id = ctid(12) // random id create
broadcastMessage(
JSON.stringify({
id: id,
date: endTime,
status: "done",
message: msg,
read: 'negative',
action: 'pdf'
})
);
} catch (e) {
console.log(400, "Cannot send.", e);
}
}
socket.onmessage = async (e) => {
const cmd = JSON.parse(e.data);
if(cmd.bid === 'start'){
await init(cmd)
}
if(!cmd.bid && cmd.sid){
await ondata(cmd)
}
if(cmd.bid === 'end'){
await end();
}
}
socket.onerror = (e) => {
console.log(e);
};
}
client conf...
export const webSocketHandler = (request) =>
new Promise((res, rej) => {
let url;
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
url = `http://localhost:8080/api/notifications/ws`.replace('http', 'ws');
} else {
url = `${window.location.origin}/api/notifications/ws`.replace('http', 'ws');
}
const token = JSON.parse(sessionStorage.getItem('token'));
const orgname = localStorage.getItem('orgname');
const protocol = `${token}_org_${orgname}`;
const socket = new WebSocket(url, protocol);
const response = Object.create({});
socket.onopen = function () {
socket.send(
JSON.stringify({
bid: 'start',
})
);
};
socket.onmessage = function (event) {
response.data = JSON.parse(event.data);
if (response.data.status === 'creating') {
socket.send(
JSON.stringify({
sid: request.sid,
})
);
} else if (response.data.status === 'end') {
socket.send(
JSON.stringify({
bid: 'end',
})
);
} else if (response.data.status === 'done') {
try {
res(response);
} catch (err) {
rej(err);
}
}
};
socket.onclose = function (event) {
response.state = event.returnValue;
};
socket.onerror = function (error) {
rej(error);
};
});
onclick function of button I use in component...
const donwloadReport = async (type) => {
const query = `?sid=${sid}&reportType=${type}`;
const fileName = `CT_${sid}_report.${type}`;
try {
type === 'pdf' && setLoading(true);
const response = await getScanReportAction(query);
const request = {
sid,
};
webSocketHandler(request)
.then((data) => {
console.log(data);
dispatch({
type: 'update',
data: {
id: data.data.id,
date: data.data.date,
message: data.data.message,
action: data.data.action,
read: data.data.read,
},
});
})
.catch((err) => {
console.log(err);
});
if (type === 'html') {
downloadText(response.data, fileName);
} else {
const blobUrl = await readStream(response.data);
setLoading(false);
downloadURL(blobUrl, fileName);
}
} catch (err) {
displayMessage(err.message);
}
};
Everything works perfectly the first time. When I press the download button for the pdf, the socket works, then a data is returned and I update the notification count with the context I applied according to this data.
Later I realized that this works in a single tab. When I open a new client in the side tab, my notification count does not increase. For this, I wanted to keep all sockets in Map and return them all and send a message to each socket separately. But in this case, when I press the download button for the second time, no data comes from the socket.
Actually, I think that I should do the socket initialization process on the client in the context. When you do this, it starts the socket 2 times in a meaningless way.
In summary, consider an application with organizations and users belonging to those organizations. If the clients of A, B, C users belonging to X organization are open at the same time and user A pressed a pdf download button, I want A, B, C users to be notified when the pdf is downloaded.
I would be very grateful if someone could show me a way around this issue.
Have you looked at the BroadcastChannel API? Maybe that could solve your issue. See for example:
Deno specific: https://medium.com/deno-the-complete-reference/broadcast-channel-in-deno-f76a0b8893f5
Web/Browser API: https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API

set timer inside a loop for graphql query

The thing I'm doing here is fetching anime characters from anilist graphql api. The reason I've added a loop is so I could fetch data from a certain character id to a limit. For example 1-100. But I want to respect their API rate limits and so I'd like a way to limit my requests to 1 per second. Hence, I've used setTimeout, but I still got rate-limited from the API and using setInterval only keeps on looping it every 5 seconds. Like the same data gets fetched every 5 seconds.
Is there any way I can make it as I've mentioned?
My code:
const fs = require("fs");
const number = 3;
const axios = require("axios");
async function fetchData() {
for (let i = 1; i <= number; i++) {
const query = axios
.post(
"https://graphql.anilist.co",
{
query: `query character(
$id: Int
$page: Int
$sort: [MediaSort]
$onList: Boolean
$withRoles: Boolean = false
) {
Character(id: $id) {
id
name {
first
middle
last
full
native
userPreferred
alternative
alternativeSpoiler
}
image {
large
}
favourites
isFavourite
isFavouriteBlocked
description
age
gender
bloodType
dateOfBirth {
year
month
day
}
media(page: $page, sort: $sort, onList: $onList) #include(if: $withRoles) {
pageInfo {
total
perPage
currentPage
lastPage
hasNextPage
}
edges {
id
characterRole
voiceActorRoles(sort: [RELEVANCE, ID]) {
roleNotes
voiceActor {
id
name {
userPreferred
}
image {
large
}
language: languageV2
}
}
node {
id
type
isAdult
bannerImage
title {
userPreferred
}
coverImage {
large
}
startDate {
year
}
mediaListEntry {
id
status
}
}
}
}
}
}`,
variables: {
id: i,
withRoles: false,
},
},
{
headers: {
"Content-Type": "application/json",
},
}
)
.then((response) => {
// console.log(response.data.data.Character)
const jsonContent =
JSON.stringify(response.data.data.Character, null, 4) + ", ";
fs.appendFile("./chars.json", jsonContent, function (err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
})
.catch((error) => console.log(`Code: ${error}`, error));
}
}
fetchData();
Something like that will work for you (Asuming all the rest was ok):
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function fetchData() {
for (let i = 1; i <= number; i++) {
// So in case your function is called in loop - request will be delayed
await delay(5000); // TODO: Change to whatever you need
const query = axios.post(
"https://graphql.anilist.co",
{
query: someQuery, // TODO: Set your query here
variables: { id: i, withRoles: false }
},
{
headers: { "Content-Type": "application/json" }
}
);
try {
const response = await query;
const jsonContent = JSON.stringify(response.data.data.Character, null, 4) + ", ";
fs.appendFile("./chars.json", jsonContent, function (err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
} catch (e) {
console.log(`Code: ${e}`, e);
}
}
}

Node function not working, await part is not getting executed in the given function

While hitting API I'm getting function from my services/ElasticSearch.js and for some reason function there is not working after the axios part.
In the below file I've called function elasticService.updateDocument this function has been brought from another file.
'''
class ProductController {
constructor() { }
async saveProduct(req, res) {
console.log('ITs coming here')
let { _id, Product } = req.body;
if (_id) delete req.body._id;
let elasticResult;
try {
if (Product && Product.Category) {
req.body.Category = Product.Category
delete Product.Category
}
if (Product && Product.URL) {
const exists = await ProductService.checkProductByUrl(Product.URL);
_id = exists._id
}
const result = await ProductService.saveProduct(req.body, _id);
if (result) {
if (_id) {
console.log('Here.... UPDATE')
const savedProduct = await ProductModel.createPayload(req.body);
console.log(savedProduct,'saved_product')
let elaticDoc = await this.createElasticDocData(savedProduct);
console.log(elaticDoc.id,'elasticResult')
elaticDoc.id = result._id;
elaticDoc = new Elastic(elaticDoc);
console.log(elaticDoc,'<----------elaticdoc-------------->')
elasticResult = await elasticService.updateDocument(JSON.stringify(elaticDoc), req.body.Category)
console.log(elasticResult,'elasticResult')
}
else {
console.log('Here.... ADD')
const savedProduct = await ProductModel.createPayload(result);
let elaticDoc = await this.createElasticDocData(savedProduct);
elaticDoc.id = result._id;
elaticDoc = new Elastic(elaticDoc);
elasticResult = await elasticService.createDocument(JSON.stringify(elaticDoc), req.body.Category)
}
const response = new Response(1, "Product is saved successfully", "", "", { product: result, elasticResult: elasticResult });
return res.status(200).send(response);
}
const response = new Response(0, "Error in saving Product", 0, "Product not saved", {});
return res.status(200).send(response);
} catch (error) {
const response = new Response(0, "Unexpected Error", 0, error, {});
return res.status(400).send(response);
}
}
'''
This is the elasticappsearch file where above mentioned is coming from and for some reason it's not working after axios.patch part.
'''
const private_key = process.env.elastic_private_key
const search_key = process.env.elastic_search_key
const axios = require("axios")
class ElasticAppSearch {
async updateDocument(body, engine) {
console.log('Its coming in updateDOCS here')
const response = await axios.patch(`${process.env.elastic_url}/${engine}/documents`, body, {
headers: {
Authorization: `Bearer ${private_key}`,
},
});
console.log(response,'<--===-=-=-=-=-=-=-=-=-=-=-=-response')
return response.data
}
'''

Async wait for function to be done

I'm strugeling with async/await order, I need the code to wait for the getAttachements and proceed after but thats not working atm. I have looked at some options on SE for example a callback function but i did not get it to work yet.
processJsonToXML()
async function processJsonToXML() {
for (let i = 0; i < wordpressOutput.length; i++) {
imageUrls = []
let obj = wordpressOutput[i];
let content = processContent(obj.Content)
await getAttachments().then(attachments =>{
const filledXml = xmlTemplate(
{
title: obj.Title,
content: content,
date: obj.Date,
summary: obj.Excerpt,
unixTime: moment(obj.Date).unix(),
attachments: attachments
}
)
fs.writeFile(`xml-files/${obj.Title}.xml`, filledXml, function (err) {
if (err) throw err;
console.log('File is created successfully.');
});
})
}
}
Second part is the code to fetch an url and create a object out of it with the info I need in the first function.
async function getAttachments(){
const attachments: attachment[] = []
imageUrls.forEach(async url => {
let filename = extractUsingRegex(url, /([a-zA-Z0-9\s_\\.\-\(\):])+(.png|.jpg)/gm);
await fetch(url).then(response => {
response.buffer().then(resolvedBuffer => {
let attachment: attachment = {
type: response.type,
content: resolvedBuffer.toString('base64'),
filename: filename,
size: response.size.toString()
}
console.log(attachment);
attachments.push(attachment)
})
});
})
return attachments
}
Your first part of the code should look like this
processJsonToXML();
async function processJsonToXML() {
await Promise.all(
wordpressOutput.map(async (obj) => {
imageUrls = [];
let content = processContent(obj.Content);
let attachments = await getAttachments();
const filledXml = xmlTemplate({
title: obj.Title,
content: content,
date: obj.Date,
summary: obj.Excerpt,
unixTime: moment(obj.Date).unix(),
attachments: attachments,
});
fs.writeFile(`xml-files/${obj.Title}.xml`, filledXml, function (err) {
if (err) throw err;
console.log("File is created successfully.");
});
}) );}
And Second part of your code should look like this
async function getAttachments(){
const attachments: attachment[] = []
await Promise.all(
imageUrls.map(async url => {
let filename = extractUsingRegex(url, /([a-zA-Z0-9\s_\\.\-\(\):])+(.png|.jpg)/gm);
await fetch(url).then(response => {
response.buffer().then(resolvedBuffer => {
let attachment: attachment = {
type: response.type,
content: resolvedBuffer.toString('base64'),
filename: filename,
size: response.size.toString()
}
console.log(attachment);
attachments.push(attachment)
})
});
}));
return attachments
}
I hope this will help

can't get a correct JSON format, instead i am messing up

What do i want?
good question, isn't it? Well...
I am working on a application to calculate budgets with electron-vue.
In my App i try to save the users in a JSON file to create a opportunity to hold them after a application restart.
the JSON File should look like this:
{
"deniz": {
"salary": 1234,
},
"hüseyin": {
"salary": 4321,
}
}
What do i get?
I am getting this instead:
{
"deniz": {
"salary": 1234
}
}{
"hüseyin": {
"salary": 4321
}
}
Problem is, its a wrong JSON format. I am creating a whole new obj inside a obj.
How am i doing this?
I created a userDataControllerMixin.js to separate the logic from the component it self.
I have two InputFields in my component, 1.userName and 2.userSalary to collect the user data.
Inside my userDataControllerMixin.js:
export const userDataControllerMixin = {
data() {
return {
userDataAbsPath: 'src/data/userData.json',
};
},
mounted() {
this.getUsers();
},
methods: {
// FETCH THE userData.json
getUsers() {
const fs = require('fs');
const loadJSON = fs.readFile('src/data/userData.json', 'utf8', (err, data) => {
if (err) {
console.log(`failed to read file: ${err}`);
}
// console.log(data);
});
return loadJSON;
},
// USING THIS CONSTRUCTOR TO BUILD A JSON FORMAT
User(user, salary) {
this[user] = {
salary: Number(salary),
};
return user;
},
// GET INPUT FROM USERS INPUTBOX
getInput(inputName, inputSalary) {
const userName = this.inputName;
const userSalary = this.inputSalary;
const user = new this.User(userName, userSalary);
console.log(user);
this.createOrLoadJSON(user);
},
// CREATES A JSON WITH DATA FROM THE USERS
createOrLoadJSON(data) {
const fs = require('fs');
const json = JSON.stringify(data, null, 4);
if (fs.existsSync(this.userDataAbsPath)) {
console.log('file exists!');
fs.appendFileSync(this.userDataAbsPath, json);
} else {
console.log('file not exists!');
fs.writeFile(this.userDataAbsPath, json, (error) => {
if (error !== null) {
console.log(error);
}
});
}
this.postUsers();
},
// PRINTS DATA FROM userData.json TO DOM
postUsers() {
},
},
};
How can i fix this?
Problem is, appendFile method is no concat method. It just add some text after another.
You must concat your json with Object.assign first.
createOrLoadJSON(data) {
const fs = require('fs');
if (fs.existsSync(this.userDataAbsPath)) {
console.log('file exists!');
const existingJSON = fs.readFileSync(this.userDataAbsPath, "utf8"); // read file and return encoded value
const newJSON = Object.assign(JSON.parse(existingJSON), data); // concatenate file value and new data
fs.writeFile(this.userDataAbsPath, JSON.stringify(newJSON, null, 4)); // rewrite file
} else {
console.log('file not exists!');
fs.writeFile(this.userDataAbsPath, JSON.stringify(data, null, 4), (error) => { // if file does not exist stringify data here
if (error !== null) {
console.log(error);
}
});
}
this.postUsers();
},
Working example:
// proper concat with Object.assign
var assign = {
foo: 'bar'
};
var assign2 = {
bar: 'baz'
};
var assign3 = Object.assign(assign, assign2);
console.log('Object assign: ', assign3);
// appendFile look more like this
var append = {
foo: 'bar'
};
var append2 = {
bar: 'baz'
};
var append3 = JSON.stringify(append) + JSON.stringify(append2);
console.log('fs.appendFile: ', append3);

Categories

Resources