Monday, 17 April 2017

Node.js: How to get a value from a promise within a recursion

English is not my native language, I'm sorry for the grammar. I dont have much experience in javascript, nodejs, promises or recursion but I'm learning fast.

I'm working with Nodejs and Box SDK, I need to get data on all the files and folders inside a directory, so I'm checking every folder for child folders and files, saving the data in an array, and then call the function again if there were any child folders.

The problem is that I cant get the array with all the data from within the recursive calls, I cant figure out where to return or resolve my function checkChilds, nor handle the promises.

What I need is a promise that will resolve once the for loop finishes and all the stacks are completed so arrayIds will have all the data. When everything is done.

The folder structure in my main directory is divided in Preview and Production, so I'm also checking where it belongs in the array.

This is my code:

var boxUtil = require('../utils/boxUtils')
var dbUtils = require('../utils/dbUtils')
var boxInstance = boxUtil.getBOXInstance()
// var dbInstance = dbUtils.getDBInstance()

exports.script = function (request, response) {
  var accessToken = request.headers.authorization
  var folderId = request.body.folderId
  var userId = request.body.user

  var arrayIds = [
    {
      'Preview': []
    },
    {
      'Production': []
    }
  ]

  boxInstance = boxUtil.getBOXInstance()
  if (boxInstance == null) {
    console.log('box Instance null')
    boxUtil.initBOXInstance(userId, function (error, res) {
      if (error) {
        response.status(500)
        return response.send(error.message)
      }
      boxInstance = res
      var box = boxInstance.getBasicClient(accessToken)

      process.on('unhandledRejection', r => console.log(r)) // MAGIC LINE TO TRACE UNHANDLED ERRORS


      var func = getFolderInfo(folderId, arrayIds, box)
      .then(checkIfPreviewOrProduction)
      .then(insertInPreviewOrProduction)
      .then(iAmRecursive)
      .then(stringLogMe)
      .then(null, console.log)
    })
  } else {
    console.log('RESTART SERVER AND TRY AGAIN PLEASE')
  }
}

// ////// FUNCTIONS ///////////
function stringLogMe (stringifyMe) {
  var text = console.log(JSON.stringify(stringifyMe, null, 2))
  return text
}

function getFolderInfo (folderId, arrayIds, boxInstance) {
  return new Promise(function (resolve, reject) {
    var query = {fields: 'id,name,item_collection,path_collection'}
    boxInstance.folders.get(folderId, query, function (err, resp) {
      if (err) {
        reject(err)
      } else {
        resolve([resp, arrayIds, boxInstance])
      }
    })
  })
}

function checkIfPreviewOrProduction ([resp, arrayIds, boxInstance]) {
  return new Promise(function (resolve, reject) {
    for (var i in resp.path_collection.entries) {
      if (resp.path_collection.entries[i].name === 'Preview' || resp.name === 'Preview') {
        console.log('Preview')
        resolve([resp, 'Preview', arrayIds, boxInstance])
        break
      } else if (resp.path_collection.entries[i].name === 'Production' || resp.name === 'Production') {
        console.log('Production')
        resolve([resp, 'Production', arrayIds, boxInstance])
        break
      } else if (resp.item_collection !== undefined && resp.item_collection.entries[0] !== undefined) {
        if (resp.item_collection.entries[0].name === 'Preview' || resp.item_collection.entries[0].name === 'Production') {
          console.log('Content Set')
          resolve([resp, 'Content Set', arrayIds, boxInstance])
        }
      } else if (i === resp.path_collection.entries.length - 1) {
        reject('This box folder cannot be processed. Please check folder ID.')
        break
      }
    }
  })
}

function getMetadata ([resp, prevOrProd, arrayIds, boxInstance]) {
  return new Promise(function (resolve, reject) {
    var fileId = resp.id
    boxInstance.files.getAllMetadata(fileId, function (err, response) {
      if (err) {
        reject(err)
      } else {
        response.name = resp.name
        response.type = resp.type
        resolve([response, prevOrProd, arrayIds, boxInstance])
      }
    })
  })
}

function insertInPreviewOrProduction ([resp, prevOrProd, arrayIds, boxInstance]) {
  return new Promise(function (resolve, reject) {
    console.log('prevOrProd: ' + prevOrProd)
    if (resp.type === 'file') {
      var newObject = {
        'id': resp.id,
        'name': resp.name,
        'type': resp.type,
        'entries': resp.entries
      }
    } else if (resp.type === 'folder') {
      var newObject = {
        id: resp.id,
        name: resp.name,
        type: resp.type
      }
    }
    if (prevOrProd === 'Preview') {
      arrayIds[0].Preview.push(newObject)
      resolve([resp, arrayIds, boxInstance])
    } else if (prevOrProd === 'Production') {
      arrayIds[1].Production.push(newObject)
      resolve([resp, arrayIds, boxInstance])
    } else {
      console.log('not Preview, not Production')
      arrayIds.push(newObject)
      resolve([resp, arrayIds, boxInstance])
    }
  })
}

function iAmRecursive ([resp, arrayIds, boxInstance]) {
  return new Promise(function (resolve, reject) {
    function checkChilds ([resp, arrayIds, boxInstance]) {
      if (resp.item_collection.total_count > 0) {
        for (var j = 0; j < resp.item_collection.entries.length; j++) {
          if (resp.item_collection.entries[j].type === 'folder') {
            getFolderInfo(resp.item_collection.entries[j].id, arrayIds, boxInstance)
              .then(checkIfPreviewOrProduction)
              .then(insertInPreviewOrProduction)
              .then(checkChilds)
              .then(null, console.log)
          }
          if (resp.item_collection.entries[j].type === 'file') {
            console.log('ifFile')
            ifFileChild([resp.item_collection.entries[j], arrayIds, boxInstance])
          }
        }
      } else {
        console.log('no childs were found')
      }
    }
    checkChilds([resp, arrayIds, boxInstance])
  })
}

function ifFileChild ([resp, arrayIds, boxInstance]) {
  return new Promise(function (resolve, reject) {
    checkIfPreviewOrProduction([resp, arrayIds, boxInstance])
      .then(getMetadata)
      .then(insertInPreviewOrProduction)
      .then(null, console.log)
  })
}

my function iAmRecursive is the one supposed to resolve with the full array in the promise chain.

I've read several similar questions but I couldnt make anything work with my recursive calls.

Please let me know if you need more clarification on the problem. And thank you in advance.



via Nahuel

No comments:

Post a Comment