[CM] Improve CRUD & RPC interfaces (#154150)

This commit is contained in:
Sébastien Loix 2023-04-04 16:20:11 +01:00 committed by GitHub
parent 5b250268e7
commit 56c28af1f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 672 additions and 372 deletions

View file

@ -88,7 +88,6 @@ const searchSchemas = getOptionalInOutSchemas({
in: schema.maybe(
schema.object(
{
query: schema.maybe(versionableObjectSchema),
options: schema.maybe(versionableObjectSchema),
},
{ unknowns: 'forbid' }

View file

@ -179,7 +179,6 @@ describe('CM services getTransforms()', () => {
...getVersionnableObjectTests('delete.in.options'),
...getVersionnableObjectTests('delete.out.result'),
...getVersionnableObjectTests('search.in.options'),
...getVersionnableObjectTests('search.in.query'),
...getVersionnableObjectTests('search.out.result'),
].forEach(({ definitions, expected, ref, error = 'Invalid services definition.' }: any) => {
test(`validate: ${ref}`, () => {
@ -239,7 +238,6 @@ describe('CM services getTransforms()', () => {
'update.out.result',
'delete.in.options',
'delete.out.result',
'search.in.query',
'search.in.options',
'search.out.result',
].sort()

View file

@ -32,7 +32,6 @@ const serviceObjectPaths = [
'update.out.result',
'delete.in.options',
'delete.out.result',
'search.in.query',
'search.in.options',
'search.out.result',
];
@ -171,7 +170,6 @@ const getDefaultServiceTransforms = (): ServiceTransforms => ({
search: {
in: {
options: getDefaultTransforms(),
query: getDefaultTransforms(),
},
out: {
result: getDefaultTransforms(),

View file

@ -11,53 +11,52 @@ import type { ObjectTransforms, Version, VersionableObject } from './types';
export interface ServicesDefinition {
get?: {
in?: {
options?: VersionableObject;
options?: VersionableObject<any, any, any, any>;
};
out?: {
result?: VersionableObject;
result?: VersionableObject<any, any, any, any>;
};
};
bulkGet?: {
in?: {
options?: VersionableObject;
options?: VersionableObject<any, any, any, any>;
};
out?: {
result?: VersionableObject;
result?: VersionableObject<any, any, any, any>;
};
};
create?: {
in?: {
data?: VersionableObject;
options?: VersionableObject;
data?: VersionableObject<any, any, any, any>;
options?: VersionableObject<any, any, any, any>;
};
out?: {
result?: VersionableObject;
result?: VersionableObject<any, any, any, any>;
};
};
update?: {
in?: {
data?: VersionableObject;
options?: VersionableObject;
data?: VersionableObject<any, any, any, any>;
options?: VersionableObject<any, any, any, any>;
};
out?: {
result?: VersionableObject;
result?: VersionableObject<any, any, any, any>;
};
};
delete?: {
in?: {
options?: VersionableObject;
options?: VersionableObject<any, any, any, any>;
};
out?: {
result?: VersionableObject;
result?: VersionableObject<any, any, any, any>;
};
};
search?: {
in?: {
query?: VersionableObject;
options?: VersionableObject;
options?: VersionableObject<any, any, any, any>;
};
out?: {
result?: VersionableObject;
result?: VersionableObject<any, any, any, any>;
};
};
}
@ -107,7 +106,6 @@ export interface ServiceTransforms {
};
search: {
in: {
query: ObjectTransforms;
options: ObjectTransforms;
};
out: {

View file

@ -25,7 +25,7 @@ const v1Tv2Transform = jest.fn((v1: FooV1): FooV2 => {
return { firstName, lastName };
});
const fooDefV1: VersionableObject = {
const fooDefV1: VersionableObject<any, any, any, any> = {
schema: schema.object({
fullName: schema.string({ minLength: 1 }),
}),
@ -43,7 +43,7 @@ const v2Tv1Transform = jest.fn((v2: FooV2): FooV1 => {
};
});
const fooDefV2: VersionableObject = {
const fooDefV2: VersionableObject<any, any, any, any> = {
schema: schema.object({
firstName: schema.string(),
lastName: schema.string(),
@ -56,8 +56,10 @@ const fooMigrationDef: ObjectMigrationDefinition = {
2: fooDefV2,
};
const setup = (browserVersion: Version): ObjectTransforms => {
const transformsFactory = initTransform(browserVersion);
const setup = <UpIn = unknown, UpOut = unknown, DownIn = unknown, DownOut = unknown>(
browserVersion: Version
): ObjectTransforms<UpIn, UpOut, DownIn, DownOut> => {
const transformsFactory = initTransform<UpIn, UpOut, DownIn, DownOut>(browserVersion);
return transformsFactory(fooMigrationDef);
};
@ -127,7 +129,12 @@ describe('object transform', () => {
describe('down()', () => {
test('it should down transform to a previous version', () => {
const fooTransforms = setup(1);
const fooTransforms = setup<
void,
void,
{ firstName: string; lastName: string },
{ fullName: string }
>(1);
const { value } = fooTransforms.down({ firstName: 'John', lastName: 'Snow' });
const expected = { fullName: 'John Snow' };
expect(value).toEqual(expected);

View file

@ -45,15 +45,15 @@ const getVersionsMeta = (migrationDefinition: ObjectMigrationDefinition) => {
* @param migrationDefinition The object migration definition
* @returns An array of transform functions
*/
const getTransformFns = (
const getTransformFns = <I = unknown, O = unknown>(
from: Version,
to: Version,
migrationDefinition: ObjectMigrationDefinition
): ObjectTransform[] => {
const fns: ObjectTransform[] = [];
): Array<ObjectTransform<I, O>> => {
const fns: Array<ObjectTransform<I, O>> = [];
let i = from;
let fn: ObjectTransform | undefined;
let fn: ObjectTransform<I, O> | undefined;
if (to > from) {
while (i <= to) {
fn = migrationDefinition[i].up;
@ -96,8 +96,10 @@ const getTransformFns = (
* @returns A handler to pass an object migration definition
*/
export const initTransform =
(requestVersion: Version) =>
(migrationDefinition: ObjectMigrationDefinition): ObjectTransforms => {
<UpIn = unknown, UpOut = unknown, DownIn = unknown, DownOut = unknown>(requestVersion: Version) =>
(
migrationDefinition: ObjectMigrationDefinition
): ObjectTransforms<UpIn, UpOut, DownIn, DownOut> => {
const { latestVersion } = getVersionsMeta(migrationDefinition);
const getVersion = (v: Version | 'latest'): Version => (v === 'latest' ? latestVersion : v);
@ -143,9 +145,17 @@ export const initTransform =
};
}
const fns = getTransformFns(requestVersion, targetVersion, migrationDefinition);
const fns = getTransformFns<UpIn, UpOut>(
requestVersion,
targetVersion,
migrationDefinition
);
const value = fns.reduce((acc, fn) => {
const res = fn(acc as unknown as UpIn);
return res;
}, obj as unknown as UpOut);
const value = fns.reduce((acc, fn) => fn(acc), obj);
return { value, error: null };
} catch (e) {
return {
@ -179,10 +189,18 @@ export const initTransform =
}
}
const fns = getTransformFns(fromVersion, requestVersion, migrationDefinition);
const value = fns.reduce((acc, fn) => fn(acc), obj);
const fns = getTransformFns<DownIn, DownOut>(
fromVersion,
requestVersion,
migrationDefinition
);
return { value, error: null };
const value = fns.reduce((acc, fn) => {
const res = fn(acc as unknown as DownIn);
return res;
}, obj as unknown as DownOut);
return { value: value as any, error: null };
} catch (e) {
return {
value: null,

View file

@ -9,19 +9,24 @@ import type { Type, ValidationError } from '@kbn/config-schema';
export type Version = number;
export type ObjectTransform<I extends object = any, O extends object = any> = (input: I) => O;
export type ObjectTransform<I = unknown, O = unknown> = (input: I) => O;
export interface VersionableObject<I extends object = any, O extends object = any> {
export interface VersionableObject<
UpIn = unknown,
UpOut = unknown,
DownIn = unknown,
DownOut = unknown
> {
schema?: Type<any>;
down?: ObjectTransform;
up?: ObjectTransform;
down?: ObjectTransform<DownIn, DownOut>;
up?: ObjectTransform<UpIn, UpOut>;
}
export interface ObjectMigrationDefinition {
[version: Version]: VersionableObject;
[version: Version]: VersionableObject<any, any, any, any>;
}
export type TransformReturn<T = object> =
export type TransformReturn<T = unknown> =
| {
value: T;
error: null;
@ -31,22 +36,27 @@ export type TransformReturn<T = object> =
error: ValidationError | Error;
};
export interface ObjectTransforms<Current = any, Previous = any, Next = any> {
export interface ObjectTransforms<
UpIn = unknown,
UpOut = unknown,
DownIn = unknown,
DownOut = unknown
> {
up: (
obj: Current,
obj: UpIn,
version?: Version | 'latest',
options?: {
/** Validate the object _before_ up transform */
validate?: boolean;
}
) => TransformReturn<Next>;
) => TransformReturn<UpOut>;
down: (
obj: Current,
obj: DownIn,
version?: Version | 'latest',
options?: {
/** Validate the object _before_ down transform */
validate?: boolean;
}
) => TransformReturn<Previous>;
) => TransformReturn<DownOut>;
validate: (obj: any, version?: Version) => ValidationError | null;
}