@twin.org/entity 0.0.4-next.5 → 0.0.4-next.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,18 +13,8 @@ export function entity(options) {
13
13
  return (target) => {
14
14
  const entitySchema = DecoratorHelper.getSchema(target);
15
15
  entitySchema.type = target.name;
16
- if (options !== undefined) {
17
- // version is hoisted to the top-level schema field (single canonical location).
18
- // The stored options bag therefore never carries version — keeping it consistent
19
- // with how other IEntitySchemaOptions fields (e.g. description) are handled.
20
- const { version, ...optionsWithoutVersion } = options;
21
- if (version !== undefined) {
22
- entitySchema.version = version;
23
- }
24
- if (Object.keys(optionsWithoutVersion).length > 0) {
25
- entitySchema.options = optionsWithoutVersion;
26
- }
27
- }
16
+ entitySchema.description = options?.description;
17
+ entitySchema.version = options?.version;
28
18
  DecoratorHelper.setSchema(target, entitySchema);
29
19
  };
30
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"entityDecorator.js","sourceRoot":"","sources":["../../../src/decorators/entityDecorator.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,uDAAuD;AACvD,OAAO,kBAAkB,CAAC;AAC1B,OAAO,OAAO,CAAC;AAEf,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,OAA8B;IACpD,OAAO,CAAC,MAAW,EAAE,EAAE;QACtB,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvD,YAAY,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QAChC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC3B,gFAAgF;YAChF,iFAAiF;YACjF,6EAA6E;YAC7E,MAAM,EAAE,OAAO,EAAE,GAAG,qBAAqB,EAAE,GAAG,OAAO,CAAC;YACtD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC3B,YAAY,CAAC,OAAO,GAAG,OAAO,CAAC;YAChC,CAAC;YACD,IAAI,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnD,YAAY,CAAC,OAAO,GAAG,qBAAqB,CAAC;YAC9C,CAAC;QACF,CAAC;QACD,eAAe,CAAC,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjD,CAAC,CAAC;AACH,CAAC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport \"reflect-metadata\";\nimport \"tslib\";\nimport type { IEntitySchemaOptions } from \"../models/IEntitySchemaOptions.js\";\nimport { DecoratorHelper } from \"../utils/decoratorHelper.js\";\n\n/**\n * Decorator to produce schema data for entity.\n * @param options The options for the entity.\n * @returns The class decorator.\n */\nexport function entity(options?: IEntitySchemaOptions): any {\n\treturn (target: any) => {\n\t\tconst entitySchema = DecoratorHelper.getSchema(target);\n\t\tentitySchema.type = target.name;\n\t\tif (options !== undefined) {\n\t\t\t// version is hoisted to the top-level schema field (single canonical location).\n\t\t\t// The stored options bag therefore never carries version — keeping it consistent\n\t\t\t// with how other IEntitySchemaOptions fields (e.g. description) are handled.\n\t\t\tconst { version, ...optionsWithoutVersion } = options;\n\t\t\tif (version !== undefined) {\n\t\t\t\tentitySchema.version = version;\n\t\t\t}\n\t\t\tif (Object.keys(optionsWithoutVersion).length > 0) {\n\t\t\t\tentitySchema.options = optionsWithoutVersion;\n\t\t\t}\n\t\t}\n\t\tDecoratorHelper.setSchema(target, entitySchema);\n\t};\n}\n"]}
1
+ {"version":3,"file":"entityDecorator.js","sourceRoot":"","sources":["../../../src/decorators/entityDecorator.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,uDAAuD;AACvD,OAAO,kBAAkB,CAAC;AAC1B,OAAO,OAAO,CAAC;AAEf,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,OAA8B;IACpD,OAAO,CAAC,MAAW,EAAE,EAAE;QACtB,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvD,YAAY,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QAChC,YAAY,CAAC,WAAW,GAAG,OAAO,EAAE,WAAW,CAAC;QAChD,YAAY,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,CAAC;QAExC,eAAe,CAAC,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjD,CAAC,CAAC;AACH,CAAC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport \"reflect-metadata\";\nimport \"tslib\";\nimport type { IEntitySchemaOptions } from \"../models/IEntitySchemaOptions.js\";\nimport { DecoratorHelper } from \"../utils/decoratorHelper.js\";\n\n/**\n * Decorator to produce schema data for entity.\n * @param options The options for the entity.\n * @returns The class decorator.\n */\nexport function entity(options?: IEntitySchemaOptions): any {\n\treturn (target: any) => {\n\t\tconst entitySchema = DecoratorHelper.getSchema(target);\n\t\tentitySchema.type = target.name;\n\t\tentitySchema.description = options?.description;\n\t\tentitySchema.version = options?.version;\n\n\t\tDecoratorHelper.setSchema(target, entitySchema);\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"IEntitySchema.js","sourceRoot":"","sources":["../../../src/models/IEntitySchema.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IEntitySchemaOptions } from \"./IEntitySchemaOptions.js\";\nimport type { IEntitySchemaProperty } from \"./IEntitySchemaProperty.js\";\n\n/**\n * Definition for an entity schema.\n */\nexport interface IEntitySchema<T = unknown> {\n\t/**\n\t * The type of the entity.\n\t */\n\ttype: string | undefined;\n\n\t/**\n\t * The options for the entity.\n\t */\n\toptions?: IEntitySchemaOptions;\n\n\t/**\n\t * The schema version. Used to drive ordered migrations. Absent is treated as version 1.\n\t */\n\tversion?: number;\n\n\t/**\n\t * The properties of the entity.\n\t */\n\tproperties?: IEntitySchemaProperty<T>[];\n}\n"]}
1
+ {"version":3,"file":"IEntitySchema.js","sourceRoot":"","sources":["../../../src/models/IEntitySchema.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IEntitySchemaOptions } from \"./IEntitySchemaOptions.js\";\nimport type { IEntitySchemaProperty } from \"./IEntitySchemaProperty.js\";\n\n/**\n * Definition for an entity schema.\n */\nexport interface IEntitySchema<T = unknown> extends IEntitySchemaOptions {\n\t/**\n\t * The type of the entity.\n\t */\n\ttype: string | undefined;\n\n\t/**\n\t * The properties of the entity.\n\t */\n\tproperties?: IEntitySchemaProperty<T>[];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"IEntitySchemaProperty.js","sourceRoot":"","sources":["../../../src/models/IEntitySchemaProperty.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { EntitySchemaPropertyFormat } from \"./entitySchemaPropertyFormat.js\";\nimport type { EntitySchemaPropertyType } from \"./entitySchemaPropertyType.js\";\nimport type { SortDirection } from \"./sortDirection.js\";\n\n/**\n * Definition for an entity schema property.\n */\nexport interface IEntitySchemaProperty<T = unknown> {\n\t/**\n\t * The property name from the entity.\n\t */\n\tproperty: keyof T;\n\n\t/**\n\t * The type of the property.\n\t */\n\ttype: EntitySchemaPropertyType;\n\n\t/**\n\t * The format of the property.\n\t */\n\tformat?: EntitySchemaPropertyFormat;\n\n\t/**\n\t * Is this the primary index property.\n\t */\n\tisPrimary?: boolean;\n\n\t/**\n\t * Is this a secondary index property.\n\t */\n\tisSecondary?: boolean;\n\n\t/**\n\t * Default sort direction for this field, leave empty if not sortable.\n\t */\n\tsortDirection?: SortDirection;\n\n\t/**\n\t * Is the property optional.\n\t */\n\toptional?: boolean;\n\n\t/**\n\t * The type of the item (only applies when type is `array`).\n\t */\n\titemType?: EntitySchemaPropertyType;\n\n\t/**\n\t * The type ref of the item (only applies when type is either `array` or `object`).\n\t */\n\titemTypeRef?: string;\n\n\t/**\n\t * Description of the object.\n\t */\n\tdescription?: string;\n\n\t/**\n\t * Examples of the property values.\n\t */\n\texamples?: unknown[];\n}\n"]}
1
+ {"version":3,"file":"IEntitySchemaProperty.js","sourceRoot":"","sources":["../../../src/models/IEntitySchemaProperty.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { EntitySchemaPropertyFormat } from \"./entitySchemaPropertyFormat.js\";\nimport type { EntitySchemaPropertyType } from \"./entitySchemaPropertyType.js\";\nimport type { SortDirection } from \"./sortDirection.js\";\n\n/**\n * Definition for an entity schema property.\n */\nexport interface IEntitySchemaProperty<T = unknown> {\n\t/**\n\t * The property name from the entity.\n\t */\n\tproperty: keyof T;\n\n\t/**\n\t * The type of the property.\n\t */\n\ttype: EntitySchemaPropertyType;\n\n\t/**\n\t * The format of the property.\n\t */\n\tformat?: EntitySchemaPropertyFormat;\n\n\t/**\n\t * Is this the primary index property.\n\t */\n\tisPrimary?: boolean;\n\n\t/**\n\t * Is this a secondary index property.\n\t */\n\tisSecondary?: boolean;\n\n\t/**\n\t * Default sort direction for this field, leave empty if not sortable.\n\t */\n\tsortDirection?: SortDirection;\n\n\t/**\n\t * Is the property optional.\n\t */\n\toptional?: boolean;\n\n\t/**\n\t * The type of the item (only applies when type is `array`).\n\t */\n\titemType?: EntitySchemaPropertyType;\n\n\t/**\n\t * The type ref of the item (only applies when type is either `array` or `object`).\n\t */\n\titemTypeRef?: string;\n\n\t/**\n\t * Description of the object.\n\t */\n\tdescription?: string;\n\n\t/**\n\t * Examples of the property values.\n\t */\n\texamples?: unknown[];\n\n\t/**\n\t * A default value which can be used in migrations when the property value is not provided.\n\t */\n\tdefaultValue?: unknown;\n}\n"]}
@@ -20,25 +20,25 @@ export class EntitySchemaHelper {
20
20
  return DecoratorHelper.getSchema(target);
21
21
  }
22
22
  /**
23
- * Get the version of the entity schema, defaulting to 1 when absent.
24
- * This is the single source of truth for the "absent version = v1" convention.
25
- * When a version is present it must be a positive integer >= 1.
23
+ * Get the version of the entity schema, defaulting to 0 when absent.
24
+ * This is the single source of truth for the "absent version = v0" convention.
25
+ * When a version is present it must be a non-negative integer >= 0.
26
26
  * @param entitySchema The entity schema to read the version from.
27
- * @returns The declared version, or 1 if no version was set.
27
+ * @returns The declared version, or 0 if no version was set.
28
28
  * @throws GuardError if entitySchema is undefined or version is not an integer.
29
- * @throws GeneralError if version is present but less than 1.
29
+ * @throws GeneralError if version is present but less than 0.
30
30
  */
31
31
  static getVersion(entitySchema) {
32
32
  Guards.object(EntitySchemaHelper.CLASS_NAME, "entitySchema", entitySchema);
33
- if (entitySchema.version !== undefined) {
34
- Guards.integer(EntitySchemaHelper.CLASS_NAME, "entitySchema.version", entitySchema.version);
35
- if (entitySchema.version < 1) {
36
- throw new GeneralError(EntitySchemaHelper.CLASS_NAME, "versionMustBePositive", {
33
+ if (!Is.empty(entitySchema?.version)) {
34
+ Guards.integer(EntitySchemaHelper.CLASS_NAME, "entitySchema.version", entitySchema?.version);
35
+ if (entitySchema.version < 0) {
36
+ throw new GeneralError(EntitySchemaHelper.CLASS_NAME, "versionMustBeGreaterThanOrEqualZero", {
37
37
  version: entitySchema.version
38
38
  });
39
39
  }
40
40
  }
41
- return entitySchema.version ?? 1;
41
+ return entitySchema.version ?? 0;
42
42
  }
43
43
  /**
44
44
  * Get the primary key from the entity schema.
@@ -1 +1 @@
1
- {"version":3,"file":"entitySchemaHelper.js","sourceRoot":"","sources":["../../../src/utils/entitySchemaHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { GeneralError, Guards, Is } from \"@twin.org/core\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { DecoratorHelper } from \"./decoratorHelper.js\";\nimport type { IEntitySchema } from \"../models/IEntitySchema.js\";\nimport type { IEntitySchemaProperty } from \"../models/IEntitySchemaProperty.js\";\nimport type { IEntitySort } from \"../models/IEntitySort.js\";\nimport type { SortDirection } from \"../models/sortDirection.js\";\n\n/**\n * Class to help with entity schema operations.\n */\nexport class EntitySchemaHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<EntitySchemaHelper>();\n\n\t/**\n\t * Get the schema for the specified object.\n\t * @param target The object to get the schema data for.\n\t * @returns The schema for the object if it can be found.\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic static getSchema<T = unknown>(target: any): IEntitySchema<T> {\n\t\treturn DecoratorHelper.getSchema<T>(target);\n\t}\n\n\t/**\n\t * Get the version of the entity schema, defaulting to 1 when absent.\n\t * This is the single source of truth for the \"absent version = v1\" convention.\n\t * When a version is present it must be a positive integer >= 1.\n\t * @param entitySchema The entity schema to read the version from.\n\t * @returns The declared version, or 1 if no version was set.\n\t * @throws GuardError if entitySchema is undefined or version is not an integer.\n\t * @throws GeneralError if version is present but less than 1.\n\t */\n\tpublic static getVersion(entitySchema: IEntitySchema): number {\n\t\tGuards.object<IEntitySchema>(EntitySchemaHelper.CLASS_NAME, nameof(entitySchema), entitySchema);\n\t\tif (entitySchema.version !== undefined) {\n\t\t\tGuards.integer(\n\t\t\t\tEntitySchemaHelper.CLASS_NAME,\n\t\t\t\tnameof(entitySchema.version),\n\t\t\t\tentitySchema.version\n\t\t\t);\n\t\t\tif (entitySchema.version < 1) {\n\t\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"versionMustBePositive\", {\n\t\t\t\t\tversion: entitySchema.version\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn entitySchema.version ?? 1;\n\t}\n\n\t/**\n\t * Get the primary key from the entity schema.\n\t * @param entitySchema The entity schema to find the primary key from.\n\t * @returns The key if only one was found.\n\t * @throws If no primary key was found, or more than one.\n\t */\n\tpublic static getPrimaryKey<T>(entitySchema: IEntitySchema<T>): IEntitySchemaProperty<T> {\n\t\tGuards.object<IEntitySchema<T>>(\n\t\t\tEntitySchemaHelper.CLASS_NAME,\n\t\t\tnameof(entitySchema),\n\t\t\tentitySchema\n\t\t);\n\n\t\tconst primaryKeys = (entitySchema.properties ?? [])?.filter(p => p.isPrimary);\n\t\tif (primaryKeys.length === 0) {\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"noIsPrimary\");\n\t\t}\n\t\tif (primaryKeys.length > 1) {\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"multipleIsPrimary\");\n\t\t}\n\t\treturn primaryKeys[0];\n\t}\n\n\t/**\n\t * Get the sort properties from the schema.\n\t * @param entitySchema The entity schema to find the primary key from.\n\t * @returns The sort keys from the schema or undefined if there are none.\n\t */\n\tpublic static getSortProperties<T>(entitySchema: IEntitySchema<T>): IEntitySort<T>[] | undefined {\n\t\tGuards.object<IEntitySchema<T>>(\n\t\t\tEntitySchemaHelper.CLASS_NAME,\n\t\t\tnameof(entitySchema),\n\t\t\tentitySchema\n\t\t);\n\n\t\tconst sortFields = (entitySchema.properties ?? []).filter(p => !Is.undefined(p.sortDirection));\n\n\t\treturn sortFields.length > 0\n\t\t\t? sortFields.map(\n\t\t\t\t\tp =>\n\t\t\t\t\t\t({\n\t\t\t\t\t\t\tproperty: p.property,\n\t\t\t\t\t\t\ttype: p.type,\n\t\t\t\t\t\t\tsortDirection: p.sortDirection\n\t\t\t\t\t\t}) as IEntitySort<T>\n\t\t\t\t)\n\t\t\t: undefined;\n\t}\n\n\t/**\n\t * Build sort properties from the schema and override if necessary.\n\t * @param entitySchema The entity schema to retrieve the default sort keys.\n\t * @param overrideSortKeys The override sort keys.\n\t * @returns The finalised sort keys.\n\t */\n\tpublic static buildSortProperties<T>(\n\t\tentitySchema: IEntitySchema<T>,\n\t\toverrideSortKeys?: {\n\t\t\tproperty: keyof T;\n\t\t\tsortDirection: SortDirection;\n\t\t}[]\n\t): IEntitySort<T>[] | undefined {\n\t\tGuards.object(EntitySchemaHelper.CLASS_NAME, nameof(entitySchema), entitySchema);\n\n\t\tlet finalSortKeys: IEntitySort<T>[] | undefined;\n\n\t\tif (Is.arrayValue(overrideSortKeys)) {\n\t\t\tfinalSortKeys = [];\n\n\t\t\tfor (const sortKey of overrideSortKeys) {\n\t\t\t\tconst property = (entitySchema.properties ?? []).find(p => p.property === sortKey.property);\n\t\t\t\tif (property) {\n\t\t\t\t\tfinalSortKeys.push({\n\t\t\t\t\t\tproperty: sortKey.property,\n\t\t\t\t\t\tsortDirection: sortKey.sortDirection,\n\t\t\t\t\t\ttype: property.type\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfinalSortKeys = EntitySchemaHelper.getSortProperties(entitySchema);\n\t\t}\n\n\t\treturn finalSortKeys;\n\t}\n\n\t/**\n\t * Validate the entity against the schema.\n\t * @param entity The entity to validate.\n\t * @param entitySchema The schema to validate against.\n\t * @throws If the entity is invalid.\n\t */\n\tpublic static validateEntity<T>(entity: T, entitySchema: IEntitySchema<T>): void {\n\t\tGuards.object(EntitySchemaHelper.CLASS_NAME, nameof(entity), entity);\n\t\tGuards.object<IEntitySchema<T>>(\n\t\t\tEntitySchemaHelper.CLASS_NAME,\n\t\t\tnameof(entitySchema),\n\t\t\tentitySchema\n\t\t);\n\n\t\tconst properties = entitySchema.properties ?? [];\n\t\tif (properties.length === 0 && Is.objectValue(entity)) {\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"invalidEntityProperties\");\n\t\t}\n\n\t\tconst allKeys = Object.keys(entity);\n\n\t\tfor (const prop of properties) {\n\t\t\tconst idx = allKeys.indexOf(prop.property as string);\n\t\t\tif (idx !== -1) {\n\t\t\t\tallKeys.splice(idx, 1);\n\t\t\t}\n\n\t\t\tconst value = entity[prop.property];\n\n\t\t\tif (Is.empty(value)) {\n\t\t\t\t// If the value is empty but the property is not optional, then it's invalid\n\t\t\t\tif (!prop.optional) {\n\t\t\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"invalidOptional\", {\n\t\t\t\t\t\tproperty: prop.property,\n\t\t\t\t\t\ttype: prop.type\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (prop.type === \"integer\" && Is.integer(value)) {\n\t\t\t\t// If the schema expects an integer and the value is an integer, then it's valid\n\t\t\t} else if (\n\t\t\t\tprop.type === \"object\" &&\n\t\t\t\t(Is.object(value) ||\n\t\t\t\t\tIs.array(value) ||\n\t\t\t\t\tIs.string(value) ||\n\t\t\t\t\tIs.number(value) ||\n\t\t\t\t\tIs.boolean(value) ||\n\t\t\t\t\tIs.null(value))\n\t\t\t) {\n\t\t\t\t// If the schema expects an object and the value is anything that can be JSON serialised, then it's valid\n\t\t\t} else if (prop.type === \"array\" && Is.array(value)) {\n\t\t\t\t// If the schema expects an array and the value is an array, then it's valid\n\t\t\t} else if (prop.type !== typeof value) {\n\t\t\t\t// The schema type does not match the value type\n\t\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"invalidEntityProperty\", {\n\t\t\t\t\tvalue,\n\t\t\t\t\tproperty: prop.property,\n\t\t\t\t\ttype: prop.type\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (allKeys.length > 0) {\n\t\t\t// There are keys in the entity that are not in the schema\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"invalidEntityKeys\", {\n\t\t\t\tkeys: allKeys.join(\", \")\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"entitySchemaHelper.js","sourceRoot":"","sources":["../../../src/utils/entitySchemaHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { GeneralError, Guards, Is } from \"@twin.org/core\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { DecoratorHelper } from \"./decoratorHelper.js\";\nimport type { IEntitySchema } from \"../models/IEntitySchema.js\";\nimport type { IEntitySchemaProperty } from \"../models/IEntitySchemaProperty.js\";\nimport type { IEntitySort } from \"../models/IEntitySort.js\";\nimport type { SortDirection } from \"../models/sortDirection.js\";\n\n/**\n * Class to help with entity schema operations.\n */\nexport class EntitySchemaHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<EntitySchemaHelper>();\n\n\t/**\n\t * Get the schema for the specified object.\n\t * @param target The object to get the schema data for.\n\t * @returns The schema for the object if it can be found.\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic static getSchema<T = unknown>(target: any): IEntitySchema<T> {\n\t\treturn DecoratorHelper.getSchema<T>(target);\n\t}\n\n\t/**\n\t * Get the version of the entity schema, defaulting to 0 when absent.\n\t * This is the single source of truth for the \"absent version = v0\" convention.\n\t * When a version is present it must be a non-negative integer >= 0.\n\t * @param entitySchema The entity schema to read the version from.\n\t * @returns The declared version, or 0 if no version was set.\n\t * @throws GuardError if entitySchema is undefined or version is not an integer.\n\t * @throws GeneralError if version is present but less than 0.\n\t */\n\tpublic static getVersion(entitySchema: IEntitySchema): number {\n\t\tGuards.object<IEntitySchema>(EntitySchemaHelper.CLASS_NAME, nameof(entitySchema), entitySchema);\n\n\t\tif (!Is.empty(entitySchema?.version)) {\n\t\t\tGuards.integer(\n\t\t\t\tEntitySchemaHelper.CLASS_NAME,\n\t\t\t\tnameof(entitySchema?.version),\n\t\t\t\tentitySchema?.version\n\t\t\t);\n\t\t\tif (entitySchema.version < 0) {\n\t\t\t\tthrow new GeneralError(\n\t\t\t\t\tEntitySchemaHelper.CLASS_NAME,\n\t\t\t\t\t\"versionMustBeGreaterThanOrEqualZero\",\n\t\t\t\t\t{\n\t\t\t\t\t\tversion: entitySchema.version\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn entitySchema.version ?? 0;\n\t}\n\n\t/**\n\t * Get the primary key from the entity schema.\n\t * @param entitySchema The entity schema to find the primary key from.\n\t * @returns The key if only one was found.\n\t * @throws If no primary key was found, or more than one.\n\t */\n\tpublic static getPrimaryKey<T>(entitySchema: IEntitySchema<T>): IEntitySchemaProperty<T> {\n\t\tGuards.object<IEntitySchema<T>>(\n\t\t\tEntitySchemaHelper.CLASS_NAME,\n\t\t\tnameof(entitySchema),\n\t\t\tentitySchema\n\t\t);\n\n\t\tconst primaryKeys = (entitySchema.properties ?? [])?.filter(p => p.isPrimary);\n\t\tif (primaryKeys.length === 0) {\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"noIsPrimary\");\n\t\t}\n\t\tif (primaryKeys.length > 1) {\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"multipleIsPrimary\");\n\t\t}\n\t\treturn primaryKeys[0];\n\t}\n\n\t/**\n\t * Get the sort properties from the schema.\n\t * @param entitySchema The entity schema to find the primary key from.\n\t * @returns The sort keys from the schema or undefined if there are none.\n\t */\n\tpublic static getSortProperties<T>(entitySchema: IEntitySchema<T>): IEntitySort<T>[] | undefined {\n\t\tGuards.object<IEntitySchema<T>>(\n\t\t\tEntitySchemaHelper.CLASS_NAME,\n\t\t\tnameof(entitySchema),\n\t\t\tentitySchema\n\t\t);\n\n\t\tconst sortFields = (entitySchema.properties ?? []).filter(p => !Is.undefined(p.sortDirection));\n\n\t\treturn sortFields.length > 0\n\t\t\t? sortFields.map(\n\t\t\t\t\tp =>\n\t\t\t\t\t\t({\n\t\t\t\t\t\t\tproperty: p.property,\n\t\t\t\t\t\t\ttype: p.type,\n\t\t\t\t\t\t\tsortDirection: p.sortDirection\n\t\t\t\t\t\t}) as IEntitySort<T>\n\t\t\t\t)\n\t\t\t: undefined;\n\t}\n\n\t/**\n\t * Build sort properties from the schema and override if necessary.\n\t * @param entitySchema The entity schema to retrieve the default sort keys.\n\t * @param overrideSortKeys The override sort keys.\n\t * @returns The finalised sort keys.\n\t */\n\tpublic static buildSortProperties<T>(\n\t\tentitySchema: IEntitySchema<T>,\n\t\toverrideSortKeys?: {\n\t\t\tproperty: keyof T;\n\t\t\tsortDirection: SortDirection;\n\t\t}[]\n\t): IEntitySort<T>[] | undefined {\n\t\tGuards.object(EntitySchemaHelper.CLASS_NAME, nameof(entitySchema), entitySchema);\n\n\t\tlet finalSortKeys: IEntitySort<T>[] | undefined;\n\n\t\tif (Is.arrayValue(overrideSortKeys)) {\n\t\t\tfinalSortKeys = [];\n\n\t\t\tfor (const sortKey of overrideSortKeys) {\n\t\t\t\tconst property = (entitySchema.properties ?? []).find(p => p.property === sortKey.property);\n\t\t\t\tif (property) {\n\t\t\t\t\tfinalSortKeys.push({\n\t\t\t\t\t\tproperty: sortKey.property,\n\t\t\t\t\t\tsortDirection: sortKey.sortDirection,\n\t\t\t\t\t\ttype: property.type\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfinalSortKeys = EntitySchemaHelper.getSortProperties(entitySchema);\n\t\t}\n\n\t\treturn finalSortKeys;\n\t}\n\n\t/**\n\t * Validate the entity against the schema.\n\t * @param entity The entity to validate.\n\t * @param entitySchema The schema to validate against.\n\t * @throws If the entity is invalid.\n\t */\n\tpublic static validateEntity<T>(entity: T, entitySchema: IEntitySchema<T>): void {\n\t\tGuards.object(EntitySchemaHelper.CLASS_NAME, nameof(entity), entity);\n\t\tGuards.object<IEntitySchema<T>>(\n\t\t\tEntitySchemaHelper.CLASS_NAME,\n\t\t\tnameof(entitySchema),\n\t\t\tentitySchema\n\t\t);\n\n\t\tconst properties = entitySchema.properties ?? [];\n\t\tif (properties.length === 0 && Is.objectValue(entity)) {\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"invalidEntityProperties\");\n\t\t}\n\n\t\tconst allKeys = Object.keys(entity);\n\n\t\tfor (const prop of properties) {\n\t\t\tconst idx = allKeys.indexOf(prop.property as string);\n\t\t\tif (idx !== -1) {\n\t\t\t\tallKeys.splice(idx, 1);\n\t\t\t}\n\n\t\t\tconst value = entity[prop.property];\n\n\t\t\tif (Is.empty(value)) {\n\t\t\t\t// If the value is empty but the property is not optional, then it's invalid\n\t\t\t\tif (!prop.optional) {\n\t\t\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"invalidOptional\", {\n\t\t\t\t\t\tproperty: prop.property,\n\t\t\t\t\t\ttype: prop.type\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (prop.type === \"integer\" && Is.integer(value)) {\n\t\t\t\t// If the schema expects an integer and the value is an integer, then it's valid\n\t\t\t} else if (\n\t\t\t\tprop.type === \"object\" &&\n\t\t\t\t(Is.object(value) ||\n\t\t\t\t\tIs.array(value) ||\n\t\t\t\t\tIs.string(value) ||\n\t\t\t\t\tIs.number(value) ||\n\t\t\t\t\tIs.boolean(value) ||\n\t\t\t\t\tIs.null(value))\n\t\t\t) {\n\t\t\t\t// If the schema expects an object and the value is anything that can be JSON serialised, then it's valid\n\t\t\t} else if (prop.type === \"array\" && Is.array(value)) {\n\t\t\t\t// If the schema expects an array and the value is an array, then it's valid\n\t\t\t} else if (prop.type !== typeof value) {\n\t\t\t\t// The schema type does not match the value type\n\t\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"invalidEntityProperty\", {\n\t\t\t\t\tvalue,\n\t\t\t\t\tproperty: prop.property,\n\t\t\t\t\ttype: prop.type\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (allKeys.length > 0) {\n\t\t\t// There are keys in the entity that are not in the schema\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"invalidEntityKeys\", {\n\t\t\t\tkeys: allKeys.join(\", \")\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
@@ -3,19 +3,11 @@ import type { IEntitySchemaProperty } from "./IEntitySchemaProperty.js";
3
3
  /**
4
4
  * Definition for an entity schema.
5
5
  */
6
- export interface IEntitySchema<T = unknown> {
6
+ export interface IEntitySchema<T = unknown> extends IEntitySchemaOptions {
7
7
  /**
8
8
  * The type of the entity.
9
9
  */
10
10
  type: string | undefined;
11
- /**
12
- * The options for the entity.
13
- */
14
- options?: IEntitySchemaOptions;
15
- /**
16
- * The schema version. Used to drive ordered migrations. Absent is treated as version 1.
17
- */
18
- version?: number;
19
11
  /**
20
12
  * The properties of the entity.
21
13
  */
@@ -49,4 +49,8 @@ export interface IEntitySchemaProperty<T = unknown> {
49
49
  * Examples of the property values.
50
50
  */
51
51
  examples?: unknown[];
52
+ /**
53
+ * A default value which can be used in migrations when the property value is not provided.
54
+ */
55
+ defaultValue?: unknown;
52
56
  }
@@ -17,13 +17,13 @@ export declare class EntitySchemaHelper {
17
17
  */
18
18
  static getSchema<T = unknown>(target: any): IEntitySchema<T>;
19
19
  /**
20
- * Get the version of the entity schema, defaulting to 1 when absent.
21
- * This is the single source of truth for the "absent version = v1" convention.
22
- * When a version is present it must be a positive integer >= 1.
20
+ * Get the version of the entity schema, defaulting to 0 when absent.
21
+ * This is the single source of truth for the "absent version = v0" convention.
22
+ * When a version is present it must be a non-negative integer >= 0.
23
23
  * @param entitySchema The entity schema to read the version from.
24
- * @returns The declared version, or 1 if no version was set.
24
+ * @returns The declared version, or 0 if no version was set.
25
25
  * @throws GuardError if entitySchema is undefined or version is not an integer.
26
- * @throws GeneralError if version is present but less than 1.
26
+ * @throws GeneralError if version is present but less than 0.
27
27
  */
28
28
  static getVersion(entitySchema: IEntitySchema): number;
29
29
  /**
package/docs/changelog.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.4-next.6](https://github.com/iotaledger/twin-framework/compare/entity-v0.0.4-next.5...entity-v0.0.4-next.6) (2026-06-05)
4
+
5
+
6
+ ### Features
7
+
8
+ * entity schema decorators default value ([33397c2](https://github.com/iotaledger/twin-framework/commit/33397c2e24978a91257371a4c63ce7f6a7125d0c))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/nameof bumped from 0.0.4-next.5 to 0.0.4-next.6
16
+ * @twin.org/core bumped from 0.0.4-next.5 to 0.0.4-next.6
17
+ * devDependencies
18
+ * @twin.org/nameof-transformer bumped from 0.0.4-next.5 to 0.0.4-next.6
19
+ * @twin.org/nameof-vitest-plugin bumped from 0.0.4-next.5 to 0.0.4-next.6
20
+ * @twin.org/validate-locales bumped from 0.0.4-next.5 to 0.0.4-next.6
21
+
3
22
  ## [0.0.4-next.5](https://github.com/iotaledger/twin-framework/compare/entity-v0.0.4-next.4...entity-v0.0.4-next.5) (2026-06-04)
4
23
 
5
24
 
@@ -54,9 +54,9 @@ The schema for the object if it can be found.
54
54
 
55
55
  > `static` **getVersion**(`entitySchema`): `number`
56
56
 
57
- Get the version of the entity schema, defaulting to 1 when absent.
58
- This is the single source of truth for the "absent version = v1" convention.
59
- When a version is present it must be a positive integer >= 1.
57
+ Get the version of the entity schema, defaulting to 0 when absent.
58
+ This is the single source of truth for the "absent version = v0" convention.
59
+ When a version is present it must be a non-negative integer >= 0.
60
60
 
61
61
  #### Parameters
62
62
 
@@ -70,7 +70,7 @@ The entity schema to read the version from.
70
70
 
71
71
  `number`
72
72
 
73
- The declared version, or 1 if no version was set.
73
+ The declared version, or 0 if no version was set.
74
74
 
75
75
  #### Throws
76
76
 
@@ -78,7 +78,7 @@ GuardError if entitySchema is undefined or version is not an integer.
78
78
 
79
79
  #### Throws
80
80
 
81
- GeneralError if version is present but less than 1.
81
+ GeneralError if version is present but less than 0.
82
82
 
83
83
  ***
84
84
 
@@ -2,6 +2,10 @@
2
2
 
3
3
  Definition for an entity schema.
4
4
 
5
+ ## Extends
6
+
7
+ - [`IEntitySchemaOptions`](IEntitySchemaOptions.md)
8
+
5
9
  ## Type Parameters
6
10
 
7
11
  ### T
@@ -18,24 +22,32 @@ The type of the entity.
18
22
 
19
23
  ***
20
24
 
21
- ### options? {#options}
25
+ ### properties? {#properties}
22
26
 
23
- > `optional` **options?**: [`IEntitySchemaOptions`](IEntitySchemaOptions.md)
27
+ > `optional` **properties?**: [`IEntitySchemaProperty`](IEntitySchemaProperty.md)\<`T`\>[]
24
28
 
25
- The options for the entity.
29
+ The properties of the entity.
26
30
 
27
31
  ***
28
32
 
29
- ### version? {#version}
33
+ ### description? {#description}
30
34
 
31
- > `optional` **version?**: `number`
35
+ > `optional` **description?**: `string`
32
36
 
33
- The schema version. Used to drive ordered migrations. Absent is treated as version 1.
37
+ Description of the object.
38
+
39
+ #### Inherited from
40
+
41
+ [`IEntitySchemaOptions`](IEntitySchemaOptions.md).[`description`](IEntitySchemaOptions.md#description)
34
42
 
35
43
  ***
36
44
 
37
- ### properties? {#properties}
45
+ ### version? {#version}
38
46
 
39
- > `optional` **properties?**: [`IEntitySchemaProperty`](IEntitySchemaProperty.md)\<`T`\>[]
47
+ > `optional` **version?**: `number`
40
48
 
41
- The properties of the entity.
49
+ The schema version. Used to drive ordered migrations. Absent is treated as version 1.
50
+
51
+ #### Inherited from
52
+
53
+ [`IEntitySchemaOptions`](IEntitySchemaOptions.md).[`version`](IEntitySchemaOptions.md#version)
@@ -2,6 +2,10 @@
2
2
 
3
3
  Definition for an entity schema options.
4
4
 
5
+ ## Extended by
6
+
7
+ - [`IEntitySchema`](IEntitySchema.md)
8
+
5
9
  ## Properties
6
10
 
7
11
  ### description? {#description}
@@ -95,3 +95,11 @@ Description of the object.
95
95
  > `optional` **examples?**: `unknown`[]
96
96
 
97
97
  Examples of the property values.
98
+
99
+ ***
100
+
101
+ ### defaultValue? {#defaultvalue}
102
+
103
+ > `optional` **defaultValue?**: `unknown`
104
+
105
+ A default value which can be used in migrations when the property value is not provided.
package/locales/en.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "invalidEntityProperty": "The entity value of \"{value}\" does not match the type \"{type}\" for property \"{property}\"",
12
12
  "invalidOptional": "The entity property \"{property}\" of type \"{type}\" is not optional, but no value has been provided",
13
13
  "invalidEntityKeys": "The entity had additional properties that are not in the schema, \"{keys}\"",
14
- "versionMustBePositive": "Property \"entitySchema.version\" must be a positive integer >= 1, but got {version}"
14
+ "versionMustBeGreaterThanOrEqualZero": "Property \"entitySchema.version\" must be an integer >= 0, but got {version}"
15
15
  }
16
16
  }
17
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/entity",
3
- "version": "0.0.4-next.5",
3
+ "version": "0.0.4-next.6",
4
4
  "description": "Helpers for defining and working with entities",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,8 +14,8 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/core": "0.0.4-next.5",
18
- "@twin.org/nameof": "0.0.4-next.5",
17
+ "@twin.org/core": "0.0.4-next.6",
18
+ "@twin.org/nameof": "0.0.4-next.6",
19
19
  "reflect-metadata": "0.2.2",
20
20
  "tslib": "2.8.1"
21
21
  },