Reputation: 74
I am new to promises, I am trying to use RSVP promises in Node.js with PostgreSQL and I am doing it wrong, most probably. Any suggestions on how to fix that or how to improve the code are appreciated.
What I try to achieve is: after receiving data - process the data to create SQL update queries and when they are ready - execute them. Data here is array of user ids.
What does not work: I get array of array of promises that doesn't resolve, I tried to resolve the array like so:
var promise4all = RSVP.all(
updateQueries.map((innerPromiseArray) => {
return RSVP.all(innerPromiseArray);
})
);
promise4all.then((promiseGroupResult) => {
// doesn't get here
});
But it didn't work also.
The code:
1) The function 'update' that receives data and calls function 'promiseQuery' to process the data:
const RSVP = require('rsvp');
let db;
const update = (data) => {
let users = {
items: data.user, // data to be updated in db - array of user ids
item_type: 1,
id: data.department
}
let updateQueries = [];
// adding query promises to updateQueries
updateQueries.push(promiseQuery(users.id, users.item_type, users.items));
RSVP.all(updateQueries).then((results) => {
/* here 'results' looks like that:
[ [ { query: 'INSERT INTO link_to_department (item_type, department, item) VALUES ($item_type, $department, $item)',
values: [Object] },
{ query: 'DELETE FROM link_to_department WHERE department = $(department) AND item_type = $(item_type) AND item=$(item)',
values: [Object] } ] ]
db update below fails with '[Empty or undefined query.]'*/
db.tx((trx) => {
let sqlUpdates = [];
results.forEach((query) => {
sqlUpdates.push(trx.none(query.query, query.values))
})
return trx.batch(sqlUpdates);
}).then(() => {
res.sendStatus(204);
}).catch((err) => {
console.log('error', err.message);
// handle errors
});
});
};
2) The function 'promiseQuery' processes data (it compares received data and data in db to update db with the new data):
const promiseQuery = (department_id, item_type, items) => {
return new RSVP.Promise((resolve, reject) => {
db.query('SELECT item FROM link_to_department WHERE department=' + department_id + ' AND item_type=' + item_type)
.then((db_items) => {
let promises = [];
let itemsToBeRemoved = [];
let itemsToBeAdded = [];
/* here we have array of user ids we received: 'items'
and array of user ids from db: 'db_items' */
// populating 'itemsToBeAdded' and 'itemsToBeRemoved' with user ids that need to added or removed:
populateUpdateArray(items, db_items, itemsToBeAdded);
populateUpdateArray(db_items, items, itemsToBeRemoved);
let insert_query = 'INSERT INTO link_to_department (item_type, department, item) VALUES ($item_type, $department, $item)'
let delete_query = 'DELETE FROM link_to_department WHERE department = $(department) AND item_type = $(item_type) AND item=$(item)';
// creating update sql queries
populateUpdateQuery(insert_query, itemsToBeAdded, department_id, item_type, promises);
populateUpdateQuery(delete_query, itemsToBeRemoved, department_id, item_type, promises);
RSVP.all(promises).then((results) => {
/* here 'results' looks like this:
[ { query: 'INSERT INTO link_to_department (item_type, department, item) VALUES ($item_type, $department, $item)',
values: { item_type: 19, department: 1, item: '1' } },
{ query: 'DELETE FROM link_to_department WHERE department = $(department) AND item_type = $(item_type) AND item=$(item)',
values: { item_type: 19, department: 1, item: 1 } }] */
return resolve(results);
});
}).catch(() => {
reject();
})
});
};
3) That function 'populateUpdateArray' populates array of user ids that need to be updated (basically, received user ids should replace ids in the db - for that we check what ids we received are not in db and what ids in db are not in the received ids):
const populateUpdateArray = (array_0, array_1, updateArray) => {
array_0.forEach((item) => {
if (array_1.indexOf(item) === -1) {
updateArray.push(item);
}
});
};
4) That function 'populateUpdateQuery' returns sql update queries:
const populateUpdateQuery = (query, id_array, department_id, item_type, promises) => {
return new RSVP.Promise((resolve, reject) => {
id_array.forEach((item) => {
let values = {
item_type: item_type,
department: department_id,
item: item
};
promises.push({query, values});
});
resolve(promises);
});
};
Thank you!
EDIT: I changed the code to have only one db connection and I simplified the code a little. I do not get any errors, but queries are not executed, still. I think I am missing something basic here:
const update = (data) => {
let users = {
items: data.user,
item_type: 1,
id: data.department
}
db.tx((tx) => {
let updateQueries = [];
updateQueries.push(promiseQuery(department.id, users.item_type, users.items, tx));
RSVP.all(updateQueries).then((results) => {
// results is array of array, so i flatten it
let sqlUpdates = results.reduce((a, b) => { return a.concat(b); }, []);
/* sqlUpdates here:
[ Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined } ]
*/
return tx.batch(sqlUpdates);
});
}).then(() => {
res.sendStatus(204);
}).catch((err) => {
console.log('error', err.message);
});
};
const promiseQuery = (department_id, item_type, items, tx) => {
return new RSVP.Promise((resolve, reject) => {
tx.query('SELECT item FROM belongs_to_departments WHERE department=' + department_id + ' AND item_type=' + item_type)
.then((db_items)=> {
let queries = [];
let itemsToBeAdded = [];
let insert_query = 'INSERT INTO belongs_to_departments (item_type, department, item) VALUES ($(item_type), $(department), $(item))';
populateUpdateArray(items, db_items, itemsToBeAdded);
populateUpdateQuery(insert_query, itemsToBeAdded, department_id, item_type, queries, tx);
resolve(queries);
}).catch(() => {
reject();
});
});
};
const populateUpdateArray = (array_0, array_1, updateArray) => {
array_0.forEach((item) => {
if (array_1.indexOf(item) === -1) {
updateArray.push(item);
}
});
};
const populateUpdateQuery = (query, id_array, department_id, item_type, queries, tx) => {
id_array.forEach((item) => {
let values = {
item_type: item_type,
department: department_id,
item: item
};
queries.push(tx.none(query, values));
});
};
Upvotes: 1
Views: 596
Reputation: 74
Thanks to Vitaly for the help. That worked for me:
const update = data => {
const users = {
items: data.user,
item_type: 1,
id: data.department
}
db.tx(tx => {
const updateQueries = [];
updateQueries.push(promiseQuery(department.id, users.item_type, users.items, tx));
RSVP.all(updateQueries).then(results => {
// results is array of array, so i flatten it
const sqlUpdates = results.reduce((a, b) => { return a.concat(b); }, []);
return tx.batch(sqlUpdates);
});
}).then(() => {
res.sendStatus(204);
}).catch(err => {
console.log('error', err.message);
});
};
const promiseQuery = (department_id, item_type, items, tx) => {
return new RSVP.Promise((resolve, reject) => {
tx.query('SELECT item FROM belongs_to_departments WHERE department=' + department_id + ' AND item_type=' + item_type)
.then(db_items => {
const queries = [];
const itemsToBeAdded = [];
const insert_query = 'INSERT INTO belongs_to_departments (item_type, department, item) VALUES ($(item_type), $(department), $(item))';
populateUpdateArray(items, db_items, itemsToBeAdded);
populateUpdateQuery(insert_query, itemsToBeAdded, department_id, item_type, queries, tx);
resolve(queries);
}).catch(() => {
reject();
});
});
};
const populateUpdateArray = (array_0, array_1, updateArray) => {
array_0.forEach((item) => {
if (array_1.indexOf(item) === -1) {
updateArray.push(item);
}
});
};
const populateUpdateQuery = (query, id_array, department_id, item_type, queries, tx) => {
id_array.forEach(item => {
const values = {
item_type: item_type,
department: department_id,
item: item
};
queries.push(tx.none(query, values));
});
};
Upvotes: 0