Skip to content

Commit

Permalink
[APM] Improve router types (#83620)
Browse files Browse the repository at this point in the history
* [APM] Improve router types

* Pass processorEvent param to useDynamicIndexPattern
  • Loading branch information
dgieselaar authored Nov 18, 2020
1 parent 02dfc47 commit 2a365ff
Show file tree
Hide file tree
Showing 84 changed files with 1,044 additions and 623 deletions.
71 changes: 71 additions & 0 deletions x-pack/plugins/apm/common/runtime_types/merge/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as t from 'io-ts';
import { isLeft } from 'fp-ts/lib/Either';
import { merge } from './';
import { jsonRt } from '../json_rt';

describe('merge', () => {
it('fails on one or more errors', () => {
const type = merge([t.type({ foo: t.string }), t.type({ bar: t.number })]);

const result = type.decode({ foo: '' });

expect(isLeft(result)).toBe(true);
});

it('merges left to right', () => {
const typeBoolean = merge([
t.type({ foo: t.string }),
t.type({ foo: jsonRt.pipe(t.boolean) }),
]);

const resultBoolean = typeBoolean.decode({
foo: 'true',
});

// @ts-expect-error
expect(resultBoolean.right).toEqual({
foo: true,
});

const typeString = merge([
t.type({ foo: jsonRt.pipe(t.boolean) }),
t.type({ foo: t.string }),
]);

const resultString = typeString.decode({
foo: 'true',
});

// @ts-expect-error
expect(resultString.right).toEqual({
foo: 'true',
});
});

it('deeply merges values', () => {
const type = merge([
t.type({ foo: t.type({ baz: t.string }) }),
t.type({ foo: t.type({ bar: t.string }) }),
]);

const result = type.decode({
foo: {
bar: '',
baz: '',
},
});

// @ts-expect-error
expect(result.right).toEqual({
foo: {
bar: '',
baz: '',
},
});
});
});
68 changes: 68 additions & 0 deletions x-pack/plugins/apm/common/runtime_types/merge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as t from 'io-ts';
import { merge as lodashMerge } from 'lodash';
import { isLeft } from 'fp-ts/lib/Either';
import { ValuesType } from 'utility-types';

export type MergeType<
T extends t.Any[],
U extends ValuesType<T> = ValuesType<T>
> = t.Type<U['_A'], U['_O'], U['_I']> & {
_tag: 'MergeType';
types: T;
};

// this is similar to t.intersection, but does a deep merge
// instead of a shallow merge

export function merge<A extends t.Mixed, B extends t.Mixed>(
types: [A, B]
): MergeType<[A, B]>;

export function merge(types: t.Any[]) {
const mergeType = new t.Type(
'merge',
(u): u is unknown => {
return types.every((type) => type.is(u));
},
(input, context) => {
const errors: t.Errors = [];

const successes: unknown[] = [];

const results = types.map((type, index) =>
type.validate(
input,
context.concat({
key: String(index),
type,
actual: input,
})
)
);

results.forEach((result) => {
if (isLeft(result)) {
errors.push(...result.left);
} else {
successes.push(result.right);
}
});

const mergedValues = lodashMerge({}, ...successes);

return errors.length > 0 ? t.failures(errors) : t.success(mergedValues);
},
(a) => types.reduce((val, type) => type.encode(val), a)
);

return {
...mergeType,
_tag: 'MergeType',
types,
};
}
106 changes: 106 additions & 0 deletions x-pack/plugins/apm/common/runtime_types/strict_keys_rt/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as t from 'io-ts';
import { isRight, isLeft } from 'fp-ts/lib/Either';
import { strictKeysRt } from './';
import { jsonRt } from '../json_rt';

describe('strictKeysRt', () => {
it('correctly and deeply validates object keys', () => {
const checks: Array<{ type: t.Type<any>; passes: any[]; fails: any[] }> = [
{
type: t.intersection([
t.type({ foo: t.string }),
t.partial({ bar: t.string }),
]),
passes: [{ foo: '' }, { foo: '', bar: '' }],
fails: [
{ foo: '', unknownKey: '' },
{ foo: '', bar: '', unknownKey: '' },
],
},
{
type: t.type({
path: t.union([
t.type({ serviceName: t.string }),
t.type({ transactionType: t.string }),
]),
}),
passes: [
{ path: { serviceName: '' } },
{ path: { transactionType: '' } },
],
fails: [
{ path: { serviceName: '', unknownKey: '' } },
{ path: { transactionType: '', unknownKey: '' } },
{ path: { serviceName: '', transactionType: '' } },
{ path: { serviceName: '' }, unknownKey: '' },
],
},
{
type: t.intersection([
t.type({ query: t.type({ bar: t.string }) }),
t.partial({ query: t.partial({ _debug: t.boolean }) }),
]),
passes: [{ query: { bar: '', _debug: true } }],
fails: [{ query: { _debug: true } }],
},
];

checks.forEach((check) => {
const { type, passes, fails } = check;

const strictType = strictKeysRt(type);

passes.forEach((value) => {
const result = strictType.decode(value);

if (!isRight(result)) {
throw new Error(
`Expected ${JSON.stringify(
value
)} to be allowed, but validation failed with ${
result.left[0].message
}`
);
}
});

fails.forEach((value) => {
const result = strictType.decode(value);

if (!isLeft(result)) {
throw new Error(
`Expected ${JSON.stringify(
value
)} to be disallowed, but validation succeeded`
);
}
});
});
});

it('does not support piped types', () => {
const typeA = t.type({
query: t.type({ filterNames: jsonRt.pipe(t.array(t.string)) }),
} as Record<string, any>);

const typeB = t.partial({
query: t.partial({ _debug: jsonRt.pipe(t.boolean) }),
});

const value = {
query: {
_debug: 'true',
filterNames: JSON.stringify(['host', 'agentName']),
},
};

const pipedType = strictKeysRt(typeA.pipe(typeB));

expect(isLeft(pipedType.decode(value))).toBe(true);
});
});
Loading

0 comments on commit 2a365ff

Please sign in to comment.