Moving all possible fields from mappings to schemas in the Spaces SO type (#155541)

## Summary

To prepare for SO `mappings` that don't allow fields to be removed
(closes [#153838](https://github.com/elastic/kibana/issues/153838)) all
possible fields should be moved to `schemas`

## Testing

After moving all fields, but `name`, I was able to create and list
spaces.
This commit is contained in:
Kurt 2023-04-25 17:54:52 -04:00 committed by GitHub
parent 90d3006678
commit 9e925e25eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 149 additions and 21 deletions

View file

@ -135,7 +135,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"siem-ui-timeline-note": "13c9d4c142f96624a93a623c6d7cba7e1ae9b5a6",
"siem-ui-timeline-pinned-event": "96a43d59b9e2fc11f12255a0cb47ef0a3d83af4c",
"slo": "aefffabdb35d15a6c388634af2cee1fa59ede83c",
"space": "7fc578a1f9f7708cb07479f03953d664ad9f1dae",
"space": "168a35eab6fc40eceacc4731c8b8d8af114e27c4",
"spaces-usage-stats": "084bd0f080f94fb5735d7f3cf12f13ec92f36bad",
"synthetics-monitor": "fa988678e5d6791c75515fa1acdbbb3b2d1f916d",
"synthetics-param": "9776c9b571d35f0d0397e8915e035ea1dc026db7",

View file

@ -19,24 +19,6 @@ export const SpacesSavedObjectMappings = deepFreeze({
},
},
},
description: {
type: 'text',
},
initials: {
type: 'keyword',
},
color: {
type: 'keyword',
},
disabledFeatures: {
type: 'keyword',
},
// This field isn't included in the mappings since it doesn't need to be indexed or searched, but it will still
// appear in the `_source` field of the `space` document.
// imageUrl: { type: 'text' },
_reserved: {
type: 'boolean',
},
},
} as const);

View file

@ -13,7 +13,7 @@ import { SpacesSavedObjectsService } from './saved_objects_service';
describe('SpacesSavedObjectsService', () => {
describe('#setup', () => {
it('registers the "space" saved object type with appropriate mappings and migrations', () => {
it('registers the "space" saved object type with appropriate mappings, migrations, and schemas', () => {
const core = coreMock.createSetup();
const spacesService = spacesServiceMock.createStartContract();
@ -23,7 +23,11 @@ describe('SpacesSavedObjectsService', () => {
expect(core.savedObjects.registerType).toHaveBeenCalledTimes(2);
expect(core.savedObjects.registerType).toHaveBeenNthCalledWith(
1,
expect.objectContaining({ name: 'space' })
expect.objectContaining({
name: 'space',
mappings: expect.any(Object),
schemas: { '8.8.0': expect.any(Object) },
})
);
expect(core.savedObjects.registerType).toHaveBeenNthCalledWith(
2,

View file

@ -12,6 +12,7 @@ import { SPACES_USAGE_STATS_TYPE } from '../usage_stats';
import { SpacesSavedObjectMappings, UsageStatsMappings } from './mappings';
import { spaceMigrations, usageStatsMigrations } from './migrations';
import { SavedObjectsSpacesExtension } from './saved_objects_spaces_extension';
import { SpacesSavedObjectSchemas } from './schemas';
interface SetupDeps {
core: Pick<CoreSetup, 'savedObjects' | 'getStartServices'>;
@ -25,6 +26,7 @@ export class SpacesSavedObjectsService {
hidden: true,
namespaceType: 'agnostic',
mappings: SpacesSavedObjectMappings,
schemas: SpacesSavedObjectSchemas,
migrations: {
'6.6.0': spaceMigrations.migrateTo660,
},

View file

@ -0,0 +1,121 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { SpacesSavedObjectSchemas } from './schemas';
describe('8.8.0', () => {
describe('only `name` is required', () => {
it('should not throw an error because no schema fields are currently required', () => {
expect(() => SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo' })).not.toThrowError();
});
});
describe('name', () => {
it('should be a string', () => {
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 1 })
).toThrowErrorMatchingInlineSnapshot(
`"[name]: expected value of type [string] but got [number]"`
);
expect(() => SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo' })).not.toThrowError();
});
it('should be minimum length of 1', () => {
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: '' })
).toThrowErrorMatchingInlineSnapshot(
`"[name]: value has length [0] but it must have a minimum length of [1]."`
);
expect(() => SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo' })).not.toThrowError();
});
});
describe('description', () => {
it('should be a string', () => {
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', description: 1 })
).toThrowErrorMatchingInlineSnapshot(
`"[description]: expected value of type [string] but got [number]"`
);
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', description: 'a' })
).not.toThrowError();
});
});
describe('initials', () => {
it('should be a string', () => {
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', initials: 1 })
).toThrowErrorMatchingInlineSnapshot(
`"[initials]: expected value of type [string] but got [number]"`
);
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', initials: 'a' })
).not.toThrowError();
});
});
describe('color', () => {
it('should be a string', () => {
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', color: 1 })
).toThrowErrorMatchingInlineSnapshot(
`"[color]: expected value of type [string] but got [number]"`
);
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', color: 'a' })
).not.toThrowError();
});
});
describe('disabledFeatures', () => {
it('should be a string', () => {
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', disabledFeatures: 1 })
).toThrowErrorMatchingInlineSnapshot(
`"[disabledFeatures]: expected value of type [array] but got [number]"`
);
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', disabledFeatures: ['a'] })
).not.toThrowError();
});
});
describe('imageUrl', () => {
it('should be a string', () => {
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', imageUrl: 1 })
).toThrowErrorMatchingInlineSnapshot(
`"[imageUrl]: expected value of type [string] but got [number]"`
);
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', imageUrl: 'a' })
).not.toThrowError();
});
});
describe('_reserved', () => {
it('should be a boolean', () => {
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', _reserved: 1 })
).toThrowErrorMatchingInlineSnapshot(
`"[_reserved]: expected value of type [boolean] but got [number]"`
);
expect(() =>
SpacesSavedObjectSchemas['8.8.0'].validate({ name: 'foo', _reserved: true })
).not.toThrowError();
});
});
});

View file

@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { schema } from '@kbn/config-schema';
// These fields are not searched or aggregated on
export const SpacesSavedObjectSchemas = {
'8.8.0': schema.object({
name: schema.string({ minLength: 1 }),
description: schema.maybe(schema.string()),
initials: schema.maybe(schema.string()),
color: schema.maybe(schema.string()),
disabledFeatures: schema.maybe(schema.arrayOf(schema.string())),
imageUrl: schema.maybe(schema.string()),
_reserved: schema.maybe(schema.boolean()),
}),
};