Разрешить массив обещаний node.js

Я новичок в обещаниях, я пытаюсь использовать обещания RSVP в Node.js с PostgreSQL, и я делаю это неправильно, скорее всего. Любые предложения о том, как это исправить или как улучшить код, приветствуются.

Я пытаюсь достичь: после получения данных - обработать данные для создания запросов на обновление SQL, а когда они будут готовы - выполнить их. Данные здесь представляют собой массив идентификаторов пользователей.

Что не работает: я получаю массив массивов обещаний, которые не разрешаются, я попытался разрешить массив следующим образом:

var promise4all = RSVP.all(
  updateQueries.map((innerPromiseArray) => {
    return RSVP.all(innerPromiseArray);
  })
);

promise4all.then((promiseGroupResult) => {
     // doesn't get here
});

Но это не сработало.

Код:

1) Функция "обновление", которая получает данные и вызывает функцию "обещание запроса" для обработки данных:

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) Функция "обещание запроса" обрабатывает данные (сравнивает полученные данные и данные в БД, чтобы обновить БД новыми данными):

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) Эта функция "populateUpdateArray" заполняет массив пользовательских идентификаторов, которые необходимо обновить (в основном полученные идентификаторы пользователей должны заменять идентификаторы в БД - для этого мы проверяем, какие идентификаторы, которые мы получили, не находятся в БД, а какие идентификаторы в БД отсутствуют. полученные идентификаторы):

const populateUpdateArray = (array_0, array_1, updateArray) => {
   array_0.forEach((item) => {
      if (array_1.indexOf(item) === -1) {
        updateArray.push(item);
     }
  });
};

4) Эта функция 'populateUpdateQuery' возвращает запросы обновления sql:

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);      
  });
};

Спасибо!

РЕДАКТИРОВАТЬ: я изменил код, чтобы иметь только одно соединение дБ, и я немного упростил код. Я не получаю никаких ошибок, но запросы не выполняются. Я думаю, что мне здесь не хватает чего-то простого:

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));
   });
};

1 ответ

Решение

Спасибо Виталию за помощь. Это сработало для меня:

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));
   });
};
Другие вопросы по тегам