Data Transform With Row Level Error Context

A record transformer that keeps row indices and source values in every error, so a failing batch traces back to the exact offending record.

JavascriptData Integrity

Code

export class TransformError extends Error {
  constructor(message, details) {
    super(message);
    this.name = "TransformError";
    this.index = details.index;
    this.key = details.key ?? null;
    this.raw = details.raw;
  }
}

export async function transformRecords(records, transform, options = {}) {
  const keyField = options.keyField ?? "id";
  if (!Array.isArray(records)) {
    throw new TypeError("records must be an array");
  }
  const out = [];
  for (let index = 0; index < records.length; index++) {
    const raw = records[index];
    if (!raw || typeof raw !== "object") {
      throw new TransformError("record at index " + index + " is not an object", {
        index,
        key: null,
        raw,
      });
    }
    let value;
    try {
      value = await transform(raw, index);
    } catch (err) {
      throw new TransformError(
        "transform failed at index " + index + ": " + String(err.message ?? err),
        { index, key: raw[keyField] ?? null, raw },
      );
    }
    if (value === undefined) {
      throw new TransformError("transform returned undefined at index " + index, {
        index,
        key: raw[keyField] ?? null,
        raw,
      });
    }
    out.push(value);
  }
  return out;
}