diff --git a/src/app/core/basic-datatypes/array/array.datatype.spec.ts b/src/app/core/basic-datatypes/array/array.datatype.spec.ts index 95f2ee8677..eb27c686af 100644 --- a/src/app/core/basic-datatypes/array/array.datatype.spec.ts +++ b/src/app/core/basic-datatypes/array/array.datatype.spec.ts @@ -8,7 +8,6 @@ import { ConfigurableEnumService } from "../configurable-enum/configurable-enum. describe("Schema data type: array", () => { const schema: EntitySchemaField = { - id: null, dataType: "array", innerDataType: "configurable-enum", additional: "test", diff --git a/src/app/core/basic-datatypes/configurable-enum/configurable-enum-datatype/configurable-enum.datatype.spec.ts b/src/app/core/basic-datatypes/configurable-enum/configurable-enum-datatype/configurable-enum.datatype.spec.ts index fdd1d6e993..302041dd51 100644 --- a/src/app/core/basic-datatypes/configurable-enum/configurable-enum-datatype/configurable-enum.datatype.spec.ts +++ b/src/app/core/basic-datatypes/configurable-enum/configurable-enum-datatype/configurable-enum.datatype.spec.ts @@ -145,7 +145,6 @@ describe("Schema data type: configurable-enum", () => { const actualMapped = dataType.importMapFunction( input, { - id: null, dataType: "configurable-enum", additional: "genders", }, diff --git a/src/app/core/basic-datatypes/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts b/src/app/core/basic-datatypes/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts index 8eaa842cff..ee6b6a2cd5 100644 --- a/src/app/core/basic-datatypes/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts +++ b/src/app/core/basic-datatypes/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts @@ -43,11 +43,11 @@ describe("EditConfigurableEnumComponent", () => { expect(component.multi).toBeTrue(); }); - function initWithSchema(schema: Omit) { + function initWithSchema(schema: EntitySchemaField) { const fromGroup = new FormGroup({ test: new FormControl() }); component.formControl = fromGroup.get("test") as FormControl; component.formFieldConfig = { id: "test" }; - component.propertySchema = { id: "test", ...schema }; + component.propertySchema = schema; component.entity = new Entity(); component.ngOnInit(); } diff --git a/src/app/core/common-components/entity-form/entity-form.service.spec.ts b/src/app/core/common-components/entity-form/entity-form.service.spec.ts index 1bc8d000c4..d945c641d4 100644 --- a/src/app/core/common-components/entity-form/entity-form.service.spec.ts +++ b/src/app/core/common-components/entity-form/entity-form.service.spec.ts @@ -165,7 +165,7 @@ describe("EntityFormService", () => { }); it("should assign default values", () => { - const schema: EntitySchemaField = { id: "test", defaultValue: 1 }; + const schema: EntitySchemaField = { defaultValue: 1 }; Entity.schema.set("test", schema); let form = service.createFormGroup([{ id: "test" }], new Entity()); @@ -191,7 +191,7 @@ describe("EntityFormService", () => { }); it("should not assign default values to existing entities", () => { - Entity.schema.set("test", { id: "test", defaultValue: 1 }); + Entity.schema.set("test", { defaultValue: 1 }); const entity = new Entity(); entity._rev = "1-existing_entity"; @@ -202,7 +202,7 @@ describe("EntityFormService", () => { }); it("should not overwrite existing values with default value", () => { - Entity.schema.set("test", { id: "test", defaultValue: 1 }); + Entity.schema.set("test", { defaultValue: 1 }); const entity = new Entity(); entity["test"] = 2; diff --git a/src/app/core/entity/database-field.decorator.spec.ts b/src/app/core/entity/database-field.decorator.spec.ts index 752d97d8ec..c2058a9834 100644 --- a/src/app/core/entity/database-field.decorator.spec.ts +++ b/src/app/core/entity/database-field.decorator.spec.ts @@ -17,6 +17,7 @@ import { Entity } from "./model/entity"; import { DatabaseField } from "./database-field.decorator"; +import { EntitySchemaField } from "./schema/entity-schema-field"; class TestClass extends Entity { @DatabaseField() @@ -39,13 +40,10 @@ describe("@DatabaseField Decorator", () => { it("results in full schema", async () => { expect(TestClass.schema).toEqual( - new Map([ - ["fieldUndefined", { id: "fieldUndefined", dataType: "string" }], - ["fieldWithDefault", { id: "fieldWithDefault", dataType: "string" }], - [ - "fieldDate", - { id: "fieldDate", dataType: "date", generateIndex: true }, - ], + new Map([ + ["fieldUndefined", { dataType: "string" }], + ["fieldWithDefault", { dataType: "string" }], + ["fieldDate", { dataType: "date", generateIndex: true }], ]), ); }); diff --git a/src/app/core/entity/database-field.decorator.ts b/src/app/core/entity/database-field.decorator.ts index c266685e1d..0d3b935557 100644 --- a/src/app/core/entity/database-field.decorator.ts +++ b/src/app/core/entity/database-field.decorator.ts @@ -8,34 +8,32 @@ import { EntitySchemaField } from "./schema/entity-schema-field"; * * @param propertySchema (optional) SchemaField definition that configures additional options regarding this field */ -export function DatabaseField( - propertySchema: Omit = {}, -) { +export function DatabaseField(propertySchema: EntitySchemaField = {}) { return (target, propertyName: string) => { - const schemaField: EntitySchemaField = { - id: propertyName, - ...propertySchema, - }; // Retrieve datatype from TypeScript type definition - if (schemaField.dataType === undefined) { + if (propertySchema.dataType === undefined) { const type = Reflect.getMetadata("design:type", target, propertyName); const typeName = type.DATA_TYPE ?? type.name.toLowerCase(); // 'object' type is ignored if (typeName !== "object") { - schemaField.dataType = typeName; + propertySchema.dataType = typeName; } } - addPropertySchema(target, schemaField); + addPropertySchema(target, propertyName, propertySchema); }; } -export function addPropertySchema(target, propertySchema: EntitySchemaField) { - target[propertySchema.id] = undefined; // This ensures that the field is not read only +export function addPropertySchema( + target, + propertyName: string, + propertySchema: EntitySchemaField, +) { + target[propertyName] = undefined; // This ensures that the field is not read only if (Object.getOwnPropertyDescriptor(target.constructor, "schema") == null) { target.constructor.schema = new Map(); } - target.constructor.schema.set(propertySchema.id, propertySchema); + target.constructor.schema.set(propertyName, propertySchema); return target; } diff --git a/src/app/core/entity/default-datatype/edit-component.spec.ts b/src/app/core/entity/default-datatype/edit-component.spec.ts index 3f5aea5c6c..891c3f098e 100644 --- a/src/app/core/entity/default-datatype/edit-component.spec.ts +++ b/src/app/core/entity/default-datatype/edit-component.spec.ts @@ -16,7 +16,7 @@ export function setupEditComponent( fromGroupConfig[propertyName] = formControl; const formGroup = new UntypedFormGroup(fromGroupConfig); component.formControl = formControl; - component.propertySchema = { id: propertyName }; + component.propertySchema = {}; component.formFieldConfig = { id: propertyName }; component.entity = new Entity(); return formGroup; diff --git a/src/app/core/entity/entity-config.service.spec.ts b/src/app/core/entity/entity-config.service.spec.ts index cf31f2cd97..d4d6a4b572 100644 --- a/src/app/core/entity/entity-config.service.spec.ts +++ b/src/app/core/entity/entity-config.service.spec.ts @@ -113,7 +113,6 @@ describe("EntityConfigService", () => { it("should create a new subclass with the schema of the extended", () => { const schema: EntitySchemaField = { - id: "dynamicProperty", dataType: "string", label: "Dynamic Property", }; @@ -122,8 +121,8 @@ describe("EntityConfigService", () => { _id: "entity:DynamicTest", label: "Dynamic Test Entity", extends: "Test", - attributes: [schema], - }, + attributes: { dynamicProperty: schema }, + } as EntityConfig, ]); service.setupEntitiesFromConfig(); diff --git a/src/app/core/entity/entity-config.service.ts b/src/app/core/entity/entity-config.service.ts index eef6664d87..0f79e82100 100644 --- a/src/app/core/entity/entity-config.service.ts +++ b/src/app/core/entity/entity-config.service.ts @@ -71,7 +71,7 @@ export class EntityConfigService { ) { const entityConfig = configAttributes || this.getEntityConfig(entityType); for (const [key, value] of Object.entries(entityConfig?.attributes ?? {})) { - addPropertySchema(entityType.prototype, { id: key, ...value }); + addPropertySchema(entityType.prototype, key, value); } // TODO: shall we just assign all properties that are present in the config object? diff --git a/src/app/core/entity/entity-config.ts b/src/app/core/entity/entity-config.ts index 09133d3843..e9529cb05e 100644 --- a/src/app/core/entity/entity-config.ts +++ b/src/app/core/entity/entity-config.ts @@ -1,4 +1,4 @@ -import { FieldConfig } from "./schema/entity-schema-field"; +import { EntitySchemaField } from "./schema/entity-schema-field"; /** * Dynamic configuration for a entity. @@ -8,7 +8,7 @@ export interface EntityConfig { /** * A list of attributes that will be dynamically added/overwritten to the entity. */ - attributes?: { [key: string]: FieldConfig }; + attributes?: { [key: string]: EntitySchemaField }; /** * A list of attributes which should be shown when calling the `.toString()` method of this entity. diff --git a/src/app/core/entity/schema/entity-schema-field.ts b/src/app/core/entity/schema/entity-schema-field.ts index 63d37b743b..c6c5f210b0 100644 --- a/src/app/core/entity/schema/entity-schema-field.ts +++ b/src/app/core/entity/schema/entity-schema-field.ts @@ -26,13 +26,6 @@ import { EntityReferenceRole } from "../../basic-datatypes/entity/entity-referen * `@DatabaseField(fieldConfig: EntitySchemaField)` */ export interface EntitySchemaField { - /** - * The key (property name) on the entity object for this field. - * - * Do not change after initial field creation! - */ - readonly id: string; - /** * The datatype of this field. This will trigger to matching datatype transformer when saving/loading the entity. * @@ -134,9 +127,6 @@ export interface EntitySchemaField { anonymize?: "retain" | "retain-anonymized"; } -// TODO: align FormFieldConfig and EntitySchemaField, so that they can directly overwrite each other + allow a simplified config version where id is not explicitly set -export type FieldConfig = Omit; - /** * Available placeholder variables that can be used to configure a dynamic default value. * (e.g. "$now" to set to current date) diff --git a/src/app/core/entity/schema/entity-schema.service.spec.ts b/src/app/core/entity/schema/entity-schema.service.spec.ts index 949bcc6262..f4d7ec9ff0 100644 --- a/src/app/core/entity/schema/entity-schema.service.spec.ts +++ b/src/app/core/entity/schema/entity-schema.service.spec.ts @@ -122,7 +122,6 @@ describe("EntitySchemaService", () => { it("should return correct inner data type", () => { const enumArraySchema: EntitySchemaField = { - id: null, dataType: "array", innerDataType: "configurable-enum", }; @@ -131,7 +130,6 @@ describe("EntitySchemaService", () => { ); const entityArraySchema: EntitySchemaField = { - id: null, dataType: "entity-array", }; expect(service.getInnermostDatatype(entityArraySchema)).toBeInstanceOf( diff --git a/src/app/core/filter/filter-generator/filter-generator.service.ts b/src/app/core/filter/filter-generator/filter-generator.service.ts index d42519f7c0..a07e83e514 100644 --- a/src/app/core/filter/filter-generator/filter-generator.service.ts +++ b/src/app/core/filter/filter-generator/filter-generator.service.ts @@ -49,9 +49,7 @@ export class FilterGeneratorService { ): Promise[]> { const filters: Filter[] = []; for (const filterConfig of filterConfigs) { - const schema = entityConstructor.schema.get(filterConfig.id) || { - id: filterConfig.id, - }; + const schema = entityConstructor.schema.get(filterConfig.id) || {}; let filter: Filter; const type = filterConfig.type ?? schema.dataType; if ( diff --git a/src/app/features/config-setup/config-import-parser.service.spec.ts b/src/app/features/config-setup/config-import-parser.service.spec.ts index c30de20195..71ea8cfdee 100644 --- a/src/app/features/config-setup/config-import-parser.service.spec.ts +++ b/src/app/features/config-setup/config-import-parser.service.spec.ts @@ -7,7 +7,7 @@ import { ConfigFieldRaw } from "./config-field.raw"; import { EntityListConfig } from "../../core/entity-list/EntityListConfig"; import { EntityDetailsConfig } from "../../core/entity-details/EntityDetailsConfig"; import { ViewConfig } from "../../core/config/dynamic-routing/view-config.interface"; -import { FieldConfig } from "../../core/entity/schema/entity-schema-field"; +import { EntitySchemaField } from "../../core/entity/schema/entity-schema-field"; describe("ConfigImportParserService", () => { let service: ConfigImportParserService; @@ -26,7 +26,7 @@ describe("ConfigImportParserService", () => { function expectToBeParsedIntoEntityConfig( inputs: ConfigFieldRaw[], - expectedOutputs: { [key: string]: FieldConfig }, + expectedOutputs: { [key: string]: EntitySchemaField }, ) { const entityName = "test"; const result = service.parseImportDefinition(inputs, entityName, false); diff --git a/src/app/features/config-setup/config-import-parser.service.ts b/src/app/features/config-setup/config-import-parser.service.ts index 3dbe6c8225..3069ffe0b1 100644 --- a/src/app/features/config-setup/config-import-parser.service.ts +++ b/src/app/features/config-setup/config-import-parser.service.ts @@ -71,9 +71,8 @@ export class ConfigImportParserService { if (!f?.dataType) { continue; } - const field = this.parseFieldDefinition(f, entityName); - entity.attributes[field.id] = field; - delete entity.attributes[field.id]["id"]; // do not save redundant id + const parsedField = this.parseFieldDefinition(f, entityName); + entity.attributes[parsedField.id] = parsedField.schema; } const generatedConfig: GeneratedConfig = {}; @@ -101,13 +100,12 @@ export class ConfigImportParserService { private parseFieldDefinition( fieldDef: ConfigFieldRaw, entityType: string, - ): EntitySchemaField { + ): { id: string; schema: EntitySchemaField } { const fieldId = fieldDef.id ?? ConfigImportParserService.generateIdFromLabel(fieldDef.label); const schema: EntitySchemaField = { - id: fieldId, dataType: fieldDef.dataType, label: fieldDef.label, description: fieldDef.description, @@ -148,7 +146,7 @@ export class ConfigImportParserService { this.generateOrUpdateDetailsViewConfig(fieldDef, entityType, fieldId); deleteEmptyProperties(schema); - return schema; + return { id: fieldId, schema: schema }; } /** diff --git a/src/app/features/file/couchdb-file.service.spec.ts b/src/app/features/file/couchdb-file.service.spec.ts index 10b3e0262b..3b0358b561 100644 --- a/src/app/features/file/couchdb-file.service.spec.ts +++ b/src/app/features/file/couchdb-file.service.spec.ts @@ -48,7 +48,6 @@ describe("CouchdbFileService", () => { dismiss = jasmine.createSpy(); mockSnackbar.openFromComponent.and.returnValue({ dismiss } as any); Entity.schema.set("testProp", { - id: "testProp", dataType: FileDatatype.dataType, }); diff --git a/src/app/features/location/map/map-properties-popup/map-properties-popup.component.spec.ts b/src/app/features/location/map/map-properties-popup/map-properties-popup.component.spec.ts index 29680dd3e5..2aeaf6ba23 100644 --- a/src/app/features/location/map/map-properties-popup/map-properties-popup.component.spec.ts +++ b/src/app/features/location/map/map-properties-popup/map-properties-popup.component.spec.ts @@ -22,18 +22,15 @@ describe("MapPropertiesPopupComponent", () => { beforeEach(async () => { Child.schema.set("address", { - id: "address", label: "Address", dataType: "location", }); Child.schema.set("otherAddress", { - id: "otherAddress", label: "Other address", dataType: "location", }); properties[Child.ENTITY_TYPE] = ["address"]; School.schema.set("address", { - id: "address", label: "School address", dataType: "location", }); diff --git a/src/app/features/location/map/map.component.spec.ts b/src/app/features/location/map/map.component.spec.ts index 5f4fbeed6c..85e0001fba 100644 --- a/src/app/features/location/map/map.component.spec.ts +++ b/src/app/features/location/map/map.component.spec.ts @@ -76,7 +76,7 @@ describe("MapComponent", () => { }); it("should create markers for entities and emit entity when marker is clicked", (done) => { - Child.schema.set("address", { id: "address", dataType: "location" }); + Child.schema.set("address", { dataType: "location" }); const child = new Child(); child["address"] = { lat: 1, lon: 1 }; component.entities = [child]; @@ -111,9 +111,8 @@ describe("MapComponent", () => { it("should open a popup that allows to change the properties displayed in the map", () => { const emitSpy = spyOn(component.displayedPropertiesChange, "emit"); - Child.schema.set("address", { id: "address", dataType: "location" }); + Child.schema.set("address", { dataType: "location" }); Child.schema.set("otherAddress", { - id: "otherAddress", dataType: "location", }); const child = new Child(); diff --git a/src/app/features/matching-entities/matching-entities/matching-entities.component.spec.ts b/src/app/features/matching-entities/matching-entities/matching-entities.component.spec.ts index 38092322c0..6ccd9a12ed 100644 --- a/src/app/features/matching-entities/matching-entities/matching-entities.component.spec.ts +++ b/src/app/features/matching-entities/matching-entities/matching-entities.component.spec.ts @@ -262,7 +262,7 @@ describe("MatchingEntitiesComponent", () => { })); it("should create distance column and publish updates", fakeAsync(() => { - Child.schema.set("address", { id: "address", dataType: "location" }); + Child.schema.set("address", { dataType: "location" }); component.entity = new Child(); component.columns = [[undefined, "distance"]]; component.leftSide = { entityType: Child }; @@ -330,12 +330,11 @@ describe("MatchingEntitiesComponent", () => { it("should update the distance calculation when the selected map properties change", fakeAsync(() => { Object.assign(component, testConfig); - Child.schema.set("address", { id: "address", dataType: "location" }); + Child.schema.set("address", { dataType: "location" }); Child.schema.set("otherAddress", { - id: "otherAddress", dataType: "location", }); - School.schema.set("address", { id: "address", dataType: "location" }); + School.schema.set("address", { dataType: "location" }); const leftEntity = new Child(); leftEntity["address"] = { lat: 52, lon: 14 }; leftEntity["otherAddress"] = { lat: 53, lon: 14 }; @@ -466,7 +465,7 @@ describe("MatchingEntitiesComponent", () => { expect(component.mapVisible).toBeFalse(); - Child.schema.set("address", { id: "address", dataType: "location" }); + Child.schema.set("address", { dataType: "location" }); component.ngOnInit(); tick(); @@ -486,8 +485,8 @@ describe("MatchingEntitiesComponent", () => { leftSide: { entityType: "Child", columns: ["name", "distance"] }, onMatch: testConfig.onMatch, }; - Child.schema.set("address", { id: "address", dataType: "location" }); - School.schema.set("address", { id: "address", dataType: "location" }); + Child.schema.set("address", { dataType: "location" }); + School.schema.set("address", { dataType: "location" }); const configCopy = JSON.parse(JSON.stringify(config)); routeData.next({ config: configCopy }); diff --git a/src/app/features/matching-entities/matching-entities/matching-entities.stories.ts b/src/app/features/matching-entities/matching-entities/matching-entities.stories.ts index 3213a807a3..f9e7e67e07 100644 --- a/src/app/features/matching-entities/matching-entities/matching-entities.stories.ts +++ b/src/app/features/matching-entities/matching-entities/matching-entities.stories.ts @@ -10,7 +10,6 @@ import { EntitySchemaField } from "../../../core/entity/schema/entity-schema-fie import { importProvidersFrom } from "@angular/core"; const addressSchema: EntitySchemaField = { - id: "address", label: "Address", dataType: "location", };