Fix operations output being undefined (#17181)

* fix operation output being undefined

* run linter

* map arrays deep too

* run linter

* rename to mapValuesDeep
This commit is contained in:
Nitwel
2023-01-18 21:00:35 +01:00
committed by GitHub
parent 025bb7c053
commit 7e43b08e53
3 changed files with 59 additions and 1 deletions

View File

@@ -29,6 +29,7 @@ import { EventHandler } from './types';
import { constructFlowTree } from './utils/construct-flow-tree';
import { getSchema } from './utils/get-schema';
import { JobQueue } from './utils/job-queue';
import { mapValuesDeep } from './utils/map-values-deep';
let flowManager: FlowManager | undefined;
@@ -390,7 +391,7 @@ class FlowManager {
const options = applyOptionsData(operation.options, keyedData);
try {
const result = await handler(options, {
let result = await handler(options, {
services,
exceptions: { ...exceptions, ...sharedExceptions },
env,
@@ -402,6 +403,12 @@ class FlowManager {
...context,
});
// JSON structures don't allow for undefined values, so we need to replace them with null
// Otherwise the applyOptionsData function will not work correctly on the next operation
if (typeof result === 'object' && result !== null) {
result = mapValuesDeep(result, (_, value) => (value === undefined ? null : value));
}
return { successor: operation.resolve, status: 'resolve', data: result ?? null, options };
} catch (error: unknown) {
return { successor: operation.reject, status: 'reject', data: error ?? null, options };

View File

@@ -0,0 +1,26 @@
import { test, expect } from 'vitest';
import { mapValuesDeep } from './map-values-deep';
test('Replace all undefined values with null', () => {
const obj = { a: { b: { c: undefined } }, b: 'test' };
const result = mapValuesDeep(obj, (_, value) => (value === undefined ? null : value));
expect(result).toEqual({ a: { b: { c: null } }, b: 'test' });
});
test('Set all values to "Hi" with a key of "b.c"', () => {
const obj = { a: { b: { c: undefined } }, b: { a: 'test', c: 'test' }, 'b.c': 'test' };
const result = mapValuesDeep(obj, (key, value) => (key === 'b.c' ? 'Hi' : value));
expect(result).toEqual({ a: { b: { c: undefined } }, b: { a: 'test', c: 'Hi' }, 'b.c': 'Hi' });
});
test('Make sure arrays are propperly mapped', () => {
const obj = { a: [undefined, 'test'] };
const result = mapValuesDeep(obj, (_, value) => (value === undefined ? null : value));
expect(result).toEqual({ a: [null, 'test'] });
});
test('Set all 2nd indices of arrays to "Hi"', () => {
const obj = { a: [undefined, 'test', { a: ['hello', 'world'] }], b: ['test'] };
const result = mapValuesDeep(obj, (key, value) => (key.endsWith('a[1]') ? 'Hi' : value));
expect(result).toEqual({ a: [undefined, 'Hi', { a: ['hello', 'Hi'] }], b: ['test'] });
});

View File

@@ -0,0 +1,25 @@
export function mapValuesDeep(obj: Record<string, any>, fn: (key: string, value: any) => any): Record<string, any> {
return recurse(obj);
function recurse(obj: Record<string, any>, prefix = ''): Record<string, any> {
if (Array.isArray(obj)) {
return obj.map((value, index) => {
if (typeof value === 'object' && value !== null) {
return recurse(value, prefix + `[${index}]`);
} else {
return fn(prefix + `[${index}]`, value);
}
});
} else {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => {
if (typeof value === 'object' && value !== null) {
return [key, recurse(value, prefix + (prefix ? '.' : '') + key)];
} else {
return [key, fn(prefix + (prefix ? '.' : '') + key, value)];
}
})
);
}
}
}