Files
openstapps/packages/es-mapping-generator/src/generator/mapping-generator.ts

77 lines
2.3 KiB
TypeScript

import {GeneratorOptions} from './index.js';
import {JSONSchema7} from 'json-schema';
import {ElasticsearchOptionsDSL} from '../dsl/schema.js';
import {
IndicesPutTemplateRequest,
MappingProperty,
MappingTypeMapping,
SearchRequest,
} from '@elastic/elasticsearch/lib/api/types.js';
import {Context} from './context.js';
import deepmerge from 'deepmerge';
import {renderTemplate} from '../template.js';
/**
* Sanitize a type name
*/
export function sanitizeTypeName(typeName: string): string {
return typeName.replaceAll(' ', '_');
}
export class MappingGenerator {
readonly presets: Map<string, ElasticsearchOptionsDSL>;
readonly cache: Map<string, {mapping: MappingProperty; dependencies: Map<string, Set<string>>}>;
readonly searchMods: {mods: Partial<SearchRequest>} = {mods: {}};
readonly template: Partial<IndicesPutTemplateRequest>;
constructor(readonly project: JSONSchema7, options: GeneratorOptions) {
this.template = options.template ?? {};
this.presets = new Map(Object.entries(options.presets));
this.cache = new Map(
Object.entries(options.overrides).map(([name, mapping]) => [
name,
{
mapping,
dependencies: new Map(),
},
]),
);
}
buildTemplate(name: string): IndicesPutTemplateRequest {
const thingType = ((this.project.definitions![name] as JSONSchema7).properties!.type as JSONSchema7)
.const;
if (typeof thingType !== 'string') {
throw new TypeError(`${name} needs a valid thing type`);
}
const mappingContext = new Context(this, thingType, [name], [], new Map());
const mappings = mappingContext.resolveReference(name);
const request: IndicesPutTemplateRequest = deepmerge(
{mappings: mappings as MappingTypeMapping},
renderTemplate(this.template, [
['{name}', name],
['{type}', thingType],
['{_type}', sanitizeTypeName(thingType)],
]),
);
if (mappingContext.dependencies.size > 0) {
request.mappings!.dynamic_templates = [];
for (const [name, paths] of mappingContext.dependencies) {
request.mappings!.dynamic_templates.push({
[name]: {
path_match: paths.size > 1 ? [...paths] : paths.values().next().value,
mapping: mappingContext.resolveReference(name),
},
});
}
}
return request;
}
}