For creating an action at hasura I'm using the following node.js code (still at an experimental stage) in glitch.com -
const execute = async (gql_query, variables) => {
const fetchResponse = await fetch(
"https://example.com/v1/graphql",
{
method: "POST",
body: JSON.stringify({
query: gql_query,
variables: variables
})
}
);
// console.log('DEBUG: ', fetchResponse);
const data = await fetchResponse.json();
console.log("DEBUG: ", data);
return data;
};
// paste the code from codegen here
const ACTION_INSERT_PAYSLIP_GET_DRIVER_PAYMENT_DATA = `
query getDriverPaymentData ($orders: [Int!]!) {
company_order (where: {company_order_id: {_in: $orders}}) {
company_order_details (distinct_on: stage_cost_driver_id) {
stage_cost_driver_id
company_user {
delivery_salary
}
}
}
}`
// Request Handler
app.post('/action_insert_payslip', async (req, res) => {
// get request input
const { order_list } = req.body.input
console.log('Input', order_list)
const orders = order_list.order_id
console.log('Item: ', orders)
const { data:driverPaymentData, errors:driverPaymentError} = await execute(ACTION_INSERT_PAYSLIP_GET_DRIVER_PAYMENT_DATA, orders)
console.log('Driver Payment Data: ', driverPaymentData)
// run some business logic
// success
return res.json({
// payslip_list: "<value>"
payslip_list: order_list
})
});
The query getDriverPaymentData produces an output like the following in hasura api explorer:
{
"data": {
"company_order": [
{
"company_order_details": [
{
"stage_cost_driver_id": 1,
"company_user": {
"delivery_salary": 20
}
},
{
"stage_cost_driver_id": 6,
"company_user": {
"delivery_salary": 10
}
}
]
},
{
"company_order_details": [
{
"stage_cost_driver_id": 6,
"company_user": {
"delivery_salary": 10
}
}
]
}
]
}
}
But in the log, I'm getting the following output:
Input { order_id: [ 247, 260, 253 ] }
Item: [ 247, 260, 253 ]
DEBUG: { errors:
[ { extensions: [Object],
message:
'parsing HashMap failed, expected Object, but encountered Array' } ] }
Driver Payment Data: undefined
It says that it expects object but encountered array. But from what I see, I'm already getting an object "data": {[....]} with array inside it from the output at hasura's API console.
What am I missing here? How can I get the data of stage_cost_driver_id and delivery_salary?
Shouldn't variables be an object?
body: JSON.stringify({
query: gql_query,
variables: {orders: variables}
})
Related
I've read many similar questions and have tried a bunch of code. Unfortunately, I'm not getting my code to run :-(
So, the situation is as follows: In a route of a node.js server, I have to respond with a filtered array of Objects. Unfortunately, whatever I do, I always get an empty array [] back. The filter is a bit tricky in my opinion, as it consists of a string comparison AND an async call to a library function. With the console output, I can clearly see that the correct element is found, but at the same time I see that I've already received the object...
Here is some code that exemplifies my challenge:
let testArray = [
{
id: 'stringId1',
data: {
someDoc: {
moreContent: 'Some random content',
type: 'noInterest'
}
}
},
{
id: 'stringId2',
data: {
someDoc: {
moreContent: 'Some random content',
type: 'ofInterest'
}
}
},
{
id: 'stringId3',
data: {
someDoc: {
moreContent: 'Some random content',
type: 'ofInterest'
}
}
}
]
// code from a library. Can't take an influence in it.
async function booleanWhenGood(id) {
if (id in some Object) {
return { myBoolean: true };
} else {
return { myBoolean: false };
}
}
// Should return only elements with type 'ofInterest' and that the function booleanWhenGood is true
router.get('/', function(res,req) {
tryOne(testArray).then(tryOneResult =>{
console.log('tryOneResult', tryOneResult);
});
tryTwo(testArray).then(tryTwoResult => {
console.log("tryTwoResult ", tryTwoResult);
});
result = [];
for (const [idx, item] of testArray.entries() ) {
console.log(idx);
if (item.data.someDoc.type === "ofInterest") {
smt.find(item.id).then(element => {
if(element.found) {
result.push(item.id);
console.log("ID is true: ", item.id);
}
});
}
if (idx === testArray.length-1) {
// Always returns []
console.log(result);
res.send(result);
}
}
})
// A helper function I wrote that I use in the things I've tried
async function myComputeBoolean(inputId, inputBoolean) {
let result = await booleanWhenGood(inputId)
if (result.myBoolean) {
console.log("ID is true: ", inputId);
}
return (result.myBoolean && inputBoolean);
}
// A few things I've tried so far:
async function tryOne(myArray) {
let myTmpArray = []
Promise.all(myArray.filter(item => {
console.log("item ", item.id);
myComputeBoolean(item.id, item.data.someDoc.type === "ofInterest")
.then(myBResult => {
console.log("boolean result", myBResult)
if (myBResult) {
tmpjsdlf.push(item.id);
return true;
}
})
})).then(returnOfPromise => {
// Always returns [];
console.log("returnOfPromise", myTmpArray);
});
// Always returns []
return(myTmpArray);
}
async function tryTwo(myArray) {
let myTmpArray = [];
myArray.forEach(item => {
console.log("item ", item.id);
myCompuBoolean(item.id, item.data.someDoc.type === "ofInterest")
.then(myBResult => {
console.log("boolean result", myBResult)
if (myBResult) {
myTmpArray.push(item.did);
}
})
});
Promise.all(myTmpArray).then(promiseResult => {
return myTmpArray;
});
}
Asynchronous programming is really tough for me in this situation... Can you help me get it running?
I didn't inspect your attempts that closely, but I believe you are experiencing some race conditions (you print return and print the array before the promises resolve).
However you can alwayd use a regular for loop to filter iterables. Like this:
let testArray = [
{
id: 'stringId1',
data: {
someDoc: {
moreContent: 'Some random content',
type: 'noInterest'
}
}
},
{
id: 'stringId2',
data: {
someDoc: {
moreContent: 'Some random content',
type: 'ofInterest'
}
}
},
{
id: 'stringId3',
data: {
someDoc: {
moreContent: 'Some random content',
type: 'ofInterest'
}
}
}
]
async function booleanWhenGood(id) {
if (id in { 'stringId1': 1, 'stringId2': 1 }) { // mock object
return { myBoolean: true };
} else {
return { myBoolean: false };
}
}
async function main() {
let filtered = []
for (item of testArray)
if ((await booleanWhenGood(item.id)).myBoolean && item.data.someDoc.type === 'ofInterest')
filtered.push(item)
console.log('filtered :>> ', filtered);
}
main()
const network = {
blockchain:'eos',
protocol:'https',
host:'jungle2.cryptolions.io',
port:443,
chainId: 'e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473',
sign: true,
broadcast: true,
debug: true,
verbose: false,
}
try {
const scatterInfo = await ScatterJS.scatter.connect('eosbetdice');
console.log({scatterInfo})
if ( scatterInfo ) {
const scatter = ScatterJS.scatter;
const requiredFields = { accounts:[network] };
const scatterVal = await scatter.getIdentity(requiredFields);
console.log({scatter,scatterVal})
if ( scatterVal ) {
const account = scatter.identity.accounts.find(x => x.blockchain === 'eos');
console.log("account",account)
const result = await api.transact({
actions: [{
account: 'eosio.token',
name: 'transfer',
authorization: [{
actor: account.name,
permission:'active',
signatures:[signature],
available_keys:[account.publicKey]
}],
data: {
from: 'abceristest2',
to: account.name,
quantity: betAsset,
memo: memo
},
}]
}, {
blocksBehind: 3,
expireSeconds: 30,
});
console.log({result})
return result;
}
} return false;
} catch ( exception ) {
console.log( exception )
}
I expect the transfer function will be work fine but It give me 401 unauthorized error. This transfer function hit the api of jungle testnet , "http://jungle.eosgen.io/v1/chain/get_required_keys"
How I can authenticate this function?
Error which I got, when this transfer function run
I don't check your codes in detail, but I think it is needed to set the data of "abceristest2" to authorization parameter.
I'm writing a GraphQL query that will return mongoose data:
export const getInventory = () => {
let query = {
deletedAt: null
};
let stocks = await StockModel.find(query)
.sort({ material: 1 });
// Now separate each inventory item per material
let inventory = {};
stocks.map(stock => {
if (inventory[stock.material]) {
inventory[stock.material].quantity += stock.quantity;
} else {
let clone = Object.assign({}, stock);
clone.lot = null;
clone.expirationDateTime = null;
clone.partNumber = null;
clone.manufacturer = null;
inventory[stock.material] = clone;
}
});
let list = Object.keys(inventory).map(key => {
return inventory[key];
});
return list;
};
Here is my inventory GraphQL query:
const inventory = {
type: new GraphQLList(StockType),
description: "Get all inventory",
resolve(root, args, context) {
return getInventory();
}
};
When running the following query:
{
viewer {
inventory() {
id
quantity
lot
}
}
}
I'm getting the following GraphQL error:
{
"errors": [
{
"message": "Expected value of type \"Stock\" but got: [object Object].",
"locations": [
{
"line": 3,
"column": 5
}
],
"stack": "Expected value of type \"Stock\" but got: [object Object].\n\nGraphQL request (3:5)\n2: viewer {\n3: inventory {\n ^\n4: id\n\n at invalidReturnTypeError (/dev/node_modules/graphql/execution/execute.js:766:10)\n at completeObjectValue (/dev/node_modules/graphql/execution/execute.js:758:13)\n at completeValue (/dev/node_modules/graphql/execution/execute.js:660:12)\n at completeValueWithLocatedError (/dev/node_modules/graphql/execution/execute.js:580:21)\n at completeValueCatchingError (/dev/node_modules/graphql/execution/execute.js:556:21)\n at /dev/node_modules/graphql/execution/execute.js:684:25\n at Array.forEach (<anonymous>)\n at forEach (/dev/node_modules/iterall/index.js:83:25)\n at completeListValue (/dev/node_modules/graphql/execution/execute.js:680:24)\n at completeValue (/dev/node_modules/graphql/execution/execute.js:643:12)\n at /dev/node_modules/graphql/execution/execute.js:617:14\n at process._tickCallback (internal/process/next_tick.js:68:7)",
"path": [
"viewer",
"inventory",
0
]
}
}
How can I solve the error?
My method works when I put values in new Farm () but not when I run it through postman in JSON which is also displayed below. I do not think I am parsing the JSON incorrectly. Any suggestions would be appreciated ?
export interface IDataFlowService {
handle(request: IDataFlowRequest): Promise<IDataFlowResponse>;
}
export class DataFlowService implements IDataFlowService {
current_env = process.env.NODE_ENV;
async handle(request: IDataFlowRequest): Promise<IDataFlowResponse> {
let response: IDataFlowResponse;
try {
switch (request.requestType) {
case "SaveFarms":
response = await this.SaveFarms(request);
break;
default:
winston.error(`Request failed for request type: ${request.requestType}`);
break;
}
return response;
} catch (e) {
winston.error(`handle method failed for request: ${request}`, e);
response = {
success: false,
error: {
'message': e.message,
}
};
return response;
}
}
private async SaveFarms(request: IDataFlowRequest): Promise<IDataFlowResponse> {
const response: IDataFlowResponse = {
success: true ,
farmIds: [],
names: []
};
for (const farm of request.farms) {
const newFarm: IFarmModel = new Farm();
Promise.all([newFarm.save()]);
response.farmIds.push(newFarm.farmId) ;
response.names.push(newFarm.name) ;
}
return response;
}
}
here is post: http://localhost:5000/api/dataflow
{
"requestType":"SaveFarms",
"farms": [
{
"name" : "Bronx"
}
]
}
as you can see I get a response but the names field is coming back null/empty:
{
"success": true,
"farmIds": [
"fH1WjllXR"
],
"names": [
null
]
}
You forget set name for newFarm object:
const newFarm: IFarmModel = new Farm();
newFarm.name = farm.name; // I think so
I wish to update a property per object in array of objects, but if some of the objects doesn't exists, insert the object instead.
Currently I used "upsert", which creates a new document when no document matches the query, unfortunately it is replacing a single item with my entire list.
Worth to mention that I am using mongoist to perform an async requests.
My code:
this.tokenArray = [
{ token: "654364543" },
{ token: "765478656" },
{ token: "876584432" },
{ token: "125452346" },
{ token: "874698557" },
{ token: "654364543" }
]
database.upsertDatebaseItem(this.tokenArray.map(x => { return x.token }), { valid : true }, 'Tokens');
async upsertDatebaseItem(itemKey, itemValue, collectionName) {
try {
await this.database[collectionName].update({ token : { $in: itemKey}}, { $set: itemValue }, {upsert : true} , {multi : true});
} catch (error) {
console.log(`An error occurred while attempting to update ${itemType} to the database: ${error}`);
return false;
}
}
Found the way to do it:
const bulkUpdate = this.tokenArray.map((x) => {
return {
"updateOne": {
"filter": { "token": x.token },
"update": { "$set": { "valid": true } },
"upsert": true
}
};
});
and:
this.database[collectionName].bulkWrite(bulkUpdate);
To upsert with mongoist, use the following:
var bulk = db.collection.initializeOrderedBulkOp()
for(var doc of docs) bulk.find( { _id: doc._id } ).upsert().updateOne(doc); // or use replaceOne()
await bulk.execute();
Converted to your case that would be
var bulk = db.collectionName.initializeOrderedBulkOp()
for(var tokenItem of tokenArray) bulk.find( { token : tokenItem.token } ).upsert().updateOne(tokenItem); // or use replaceOne()
await bulk.execute();