From: Ardis Lu Date: Tue, 25 Feb 2025 09:32:49 +0000 (-0800) Subject: Refactor extra arguments into options object X-Git-Tag: v0.1.0~40 X-Git-Url: https://git.ardis.lu/?a=commitdiff_plain;h=4e973073ad40d7356088031507e15113be5e1ff3;p=csvio Refactor extra arguments into options object --- diff --git a/src/errorStrategies.js b/src/errorStrategies.js index a136b41..4c9d08a 100644 --- a/src/errorStrategies.js +++ b/src/errorStrategies.js @@ -31,17 +31,23 @@ function placeholder(value) { } } +/** + * @typedef {Object} RetryOptions + * @property {string} [value] If provided, a placeholder value to set if the function still errors after the final iteration. + * If `value` is unset, the final error thrown by the function is re-thrown. + */ + /** * Create a `TransformationErrorFunction` that handles errors by immediately retrying it `iterations` number of times. * * @param {number} iterations The number of times to retry the function. - * @param {string} [value] If provided, a placeholder value to set if the function still errors after the final iteration. - * If `value` is unset, the final error thrown by the function is re-thrown. + * @param {RetryOptions} [options] Extra configuration options for the retry. * @returns {TransformationErrorFunction} A `TransformationErrorFunction` that may be passed to a `CSVTransformer`'s * `onError` option. * @throws If `value` is unset and the function throws an error after the final iteration, the error is re-thrown. */ -function retry(iterations, value) { +function retry(iterations, options = {}) { + let { value } = options; return async (row, e, fn) => { while (iterations--) { try { return await fn(row); } @@ -54,24 +60,28 @@ function retry(iterations, value) { } } +/** + * @typedef {Object} BackoffOptions + * @property {number} [maxExponent] If provided, the maximum exponent used to calculate the retry duration. In other words, + * the `iterations` number at which the retry duration stops increasing. If `maxExponent` is unset, the retry duration + * is unbounded and will increase after each retry. + * @property {string} [value] If provided, a placeholder value to set if the function still errors after the final iteration. + * If `value` is unset, the final error thrown by the function is re-thrown. + */ + /** * Create a `TransformationErrorFunction` that handles errors by retrying it an `iterations` number of times, with an * exponentially increasing duration in between each retry (i.e., an exponential backoff). * * @param {number} iterations The number of times to retry the function. - * @param {number} [maxExponent] If provided, the maximum exponent used to calculate the retry duration. In other words, - * the `iterations` number at which the retry duration stops increasing. If `maxExponent` is unset, the retry duration - * is unbounded and will increase after each retry. - * @param {string} [value] If provided, a placeholder value to set if the function still errors after the final iteration. - * If `value` is unset, the final error thrown by the function is re-thrown. + * @param {BackoffOptions} [options] Extra configuration options for the backoff. * @returns {TransformationErrorFunction} A `TransformationErrorFunction` that may be passed to a `CSVTransformer`'s * `onError` option. * @throws If `value` is unset and the function throws an error after the final iteration, the error is re-thrown. */ -function backoff(iterations, maxExponent, value) { - if (maxExponent === undefined) { - maxExponent = Infinity; - } +function backoff(iterations, options = {}) { + let { maxExponent, value } = options; + maxExponent ??= Infinity; return async (row, e, fn) => { for (let n = 0; n < iterations; n++) { const exponent = n > maxExponent ? maxExponent : n; diff --git a/test/errorStrategies.test.js b/test/errorStrategies.test.js index 57dd6a3..2f275a1 100644 --- a/test/errorStrategies.test.js +++ b/test/errorStrategies.test.js @@ -139,7 +139,7 @@ suite('ErrorStrategies.retry', { concurrency: true }, () => { ['header'], ['0'] ]) - .pipeThrough(new CSVTransformer(fn, { onError: retry(1, 'n/a') })) + .pipeThrough(new CSVTransformer(fn, { onError: retry(1, { value: 'n/a' }) })) .pipeTo(csvStreamEqualWritable([ ['header'], ['n/a'] @@ -199,7 +199,7 @@ suite('ErrorStrategies.backoff', { concurrency: 1 }, () => { // TODO: These test ['header'], ['0'] ]) - .pipeThrough(new CSVTransformer(fn, { onError: backoff(10, 0) })) + .pipeThrough(new CSVTransformer(fn, { onError: backoff(10, { maxExponent: 0 }) })) .pipeTo(csvStreamEqualWritable([ ['header'], [11] @@ -214,7 +214,7 @@ suite('ErrorStrategies.backoff', { concurrency: 1 }, () => { // TODO: These test ['header'], ['0'] ]) - .pipeThrough(new CSVTransformer(fn, { onError: backoff(7, 4) })) + .pipeThrough(new CSVTransformer(fn, { onError: backoff(7, { maxExponent: 4 }) })) .pipeTo(csvStreamEqualWritable([ ['header'], [8] @@ -228,7 +228,7 @@ suite('ErrorStrategies.backoff', { concurrency: 1 }, () => { // TODO: These test ['header'], ['0'] ]) - .pipeThrough(new CSVTransformer(fn, { onError: backoff(3, Infinity, 'n/a') })) + .pipeThrough(new CSVTransformer(fn, { onError: backoff(3, { value: 'n/a' }) })) .pipeTo(csvStreamEqualWritable([ ['header'], ['n/a']