Search code examples
javascriptasynchronouspromisedexie

Dexie JS Nested Collections Not Resolving in Promise Chain


I've been working with Dexie JS to manage an IndexDB data store and now want to sync the data store with a remote database. The issue that I am having is that I want to nest all relational/child records under their respective parent records in a collection and then send the whole group/list off to the remote server, using some AJAX.

In practice, what I am seeing is that the child records are not present at the time they are pushed to the remote server. However, I do see them in console.log(). I know that this is because console.log() gets the actual data at a much later time than when the data is pushed remotely. I also know that this is a common issue with promise chains, but am somehow unable to solve it.

Here's what I have so far.

function PushRemote(items, modelName) {

    console.log(items);

$.ajax({
   type: 'POST',
   url: '/' + modelName + '/AsyncSave',
   contentType: 'application/json; charset=utf-8',
   dataType: 'json',
   data: JSON.stringify(DataTransferItemList),
   success: function (response) {
       iDB.open().then(function () {
               return iDB.table(modelName).update(response, { isNotSynced: "false" });
       });
   },
   error: function (response) {
       console.error(response);
   }
});
}

function PushTableToRemote(modelName) {
  iDB.transaction('rw',
    iDB.Comments,
    iDB.CommentRatings,
    iDB.Posts,
    iDB.PostRatings,
    iDB.Reviews,
    () => {
        iDB.table(modelName).where({ isNotSynced: "true" }).toArray(items => {

            items.forEach(item => {

                if (modelName == 'Comments') {
                    iDB.CommentRatings.where({ CommentId: item.CommentId }).toArray(c => item.CommentRatings = c);
                }

                if (modelName == 'Posts') {
                    iDB.PostRatings.where({ PostId: item.PostId }).toArray(p => item.PostRatings = p);
                }

            })

            return items;
        })
        .then(items => {
            if (items && items.length > 0) {
                PushRemote(item, modelName);
            }
        });
    });
}

pushTableToRemote('Comments');

Solution

  • Alright, so it turns out if you can't go through the promise chain, then you go around the promise chain. ;)

    Ended up implementing spawn() and yield with a generator function, instead of a promise chain (https://dexie.org/docs/Simplify-with-yield.html). This was way more straight forward, for me at least. And worked like a charm. Your mileage may vary.

    function PushTableToRemote(modelName) {
    
    spawn(function* () {
    
        var items = yield iDB.table(modelName).where({ isNotSynced: "true" }).toArray();
    
        if (items && items.length > 0) {
    
            if (modelName == 'Comments') {
                for (var i = 0; i < items.length; i++) {
                    var CommentRatings = yield iDB.CommentRatings.where({ CommentId: items[i].CommentId }).toArray();
                    items[i].CommentRatings = CommentRatings;
                }
            }
    
            if (modelName == 'Posts') {
                for (var i = 0; i < items.length; i++) {
                    var PostRatings = yield iDB.PostRatings.where({ PostId: items[i].PostId }).toArray();
                    items[i].PostRatings = PostRatings;
                }
            }
    
            PushRemote(items, modelName);
        }
    });
    }