diff --git a/lib/init.lua b/lib/init.lua index 392f4e7..3b9c87b 100644 --- a/lib/init.lua +++ b/lib/init.lua @@ -439,6 +439,24 @@ function Promise.all(promises) return Promise._all(debug.traceback(nil, 2), promises) end +function Promise.fold(list, callback, initialValue) + assert(type(list) == "table", "Bad argument #1 to Promise.fold: must be a table") + assert(type(callback) == "function", "Bad argument #2 to Promise.fold: must be a function") + + local previousValue = initialValue + for i = 1, #list do + local element = list[i] + if Promise.is(previousValue) then + previousValue = previousValue:andThen(function(previousValueResolved) + return callback(previousValueResolved, element, i) + end) + else + previousValue = callback(previousValue, element, i) + end + end + return previousValue +end + function Promise.some(promises, amount) assert(type(amount) == "number", "Bad argument #2 to Promise.some: must be a number") diff --git a/lib/init.spec.lua b/lib/init.spec.lua index e2c611d..f4ea3bf 100644 --- a/lib/init.spec.lua +++ b/lib/init.spec.lua @@ -811,6 +811,51 @@ return function() end) end) + describe("Promise.fold", function() + it("should return the initial value when the list is empty", function() + local initialValue = {} + local result = Promise.fold({}, function() + error("should not be called") + end, initialValue) + expect(result).to.equal(initialValue) + end) + + it("should fold the list if the reducer never returns promises", function() + local sum = Promise.fold({1, 2, 3}, function(sum, element) + return sum + element + end, 0) + expect(sum).to.equal(6) + end) + + it("should fold the list into a promise if the reducer returns at least a promise", function() + local sum = Promise.fold({1, 2, 3}, function(sum, element, index) + if index == 2 then + return Promise.resolve(sum + element) + else + return sum + element + end + end, 0) + expect(Promise.is(sum)).to.equal(true) + expect(sum:getStatus()).to.equal(Promise.Status.Resolved) + expect(sum:expect()).to.equal(6) + end) + + it("should return the first rejected promise", function() + local errorMessage = "foo" + local sum = Promise.fold({1, 2, 3}, function(sum, element, index) + if index == 2 then + return Promise.reject(errorMessage) + else + return sum + element + end + end, 0) + expect(Promise.is(sum)).to.equal(true) + local status, rejection = sum:awaitStatus() + expect(status).to.equal(Promise.Status.Rejected) + expect(rejection).to.equal(errorMessage) + end) + end) + describe("Promise.race", function() it("should resolve with the first settled value", function() local promise = Promise.race({