@twin.org/entity 0.9.2-next.9 → 0.9.3-next.1

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.
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
3
  import "reflect-metadata";
4
4
  import "tslib";
5
+ import { Is } from "@twin.org/core";
5
6
  const META_DATA_KEY = "EntitySchemaMetadata";
6
7
  /**
7
8
  * Class to help with decorators.
@@ -14,8 +15,7 @@ export class DecoratorHelper {
14
15
  */
15
16
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
17
  static getSchema(target) {
17
- return (Reflect.getMetadata(META_DATA_KEY, typeof target === "object" ? target : target.prototype) ??
18
- {});
18
+ return Reflect.getMetadata(META_DATA_KEY, Is.object(target) ? target : target.prototype) ?? {};
19
19
  }
20
20
  /**
21
21
  * Set the schema from the reflection metadata.
@@ -24,7 +24,7 @@ export class DecoratorHelper {
24
24
  */
25
25
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
26
  static setSchema(target, entitySchema) {
27
- Reflect.defineMetadata(META_DATA_KEY, entitySchema, typeof target === "object" ? target : target.prototype);
27
+ Reflect.defineMetadata(META_DATA_KEY, entitySchema, Is.object(target) ? target : target.prototype);
28
28
  }
29
29
  }
30
30
  //# sourceMappingURL=decoratorHelper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"decoratorHelper.js","sourceRoot":"","sources":["../../../src/utils/decoratorHelper.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,kBAAkB,CAAC;AAC1B,OAAO,OAAO,CAAC;AAGf,MAAM,aAAa,GAAG,sBAAsB,CAAC;AAE7C;;GAEG;AACH,MAAM,OAAO,eAAe;IAC3B;;;;OAIG;IACH,8DAA8D;IACvD,MAAM,CAAC,SAAS,CAAc,MAAW;QAC/C,OAAO,CACN,OAAO,CAAC,WAAW,CAAC,aAAa,EAAE,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;YAC1F,EAAE,CACF,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,8DAA8D;IACvD,MAAM,CAAC,SAAS,CAAc,MAAW,EAAE,YAA8B;QAC/E,OAAO,CAAC,cAAc,CACrB,aAAa,EACb,YAAY,EACZ,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CACtD,CAAC;IACH,CAAC;CACD","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport \"reflect-metadata\";\nimport \"tslib\";\nimport type { IEntitySchema } from \"../models/IEntitySchema.js\";\n\nconst META_DATA_KEY = \"EntitySchemaMetadata\";\n\n/**\n * Class to help with decorators.\n */\nexport class DecoratorHelper {\n\t/**\n\t * Get the schema from the reflection metadata.\n\t * @param target The object to get the schema data from.\n\t * @returns The schema from the metadata 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 (\n\t\t\tReflect.getMetadata(META_DATA_KEY, typeof target === \"object\" ? target : target.prototype) ??\n\t\t\t{}\n\t\t);\n\t}\n\n\t/**\n\t * Set the schema from the reflection metadata.\n\t * @param target The object to get the schema data from.\n\t * @param entitySchema The schema to set.\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic static setSchema<T = unknown>(target: any, entitySchema: IEntitySchema<T>): void {\n\t\tReflect.defineMetadata(\n\t\t\tMETA_DATA_KEY,\n\t\t\tentitySchema,\n\t\t\ttypeof target === \"object\" ? target : target.prototype\n\t\t);\n\t}\n}\n"]}
1
+ {"version":3,"file":"decoratorHelper.js","sourceRoot":"","sources":["../../../src/utils/decoratorHelper.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,kBAAkB,CAAC;AAC1B,OAAO,OAAO,CAAC;AACf,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAGpC,MAAM,aAAa,GAAG,sBAAsB,CAAC;AAE7C;;GAEG;AACH,MAAM,OAAO,eAAe;IAC3B;;;;OAIG;IACH,8DAA8D;IACvD,MAAM,CAAC,SAAS,CAAc,MAAW;QAC/C,OAAO,OAAO,CAAC,WAAW,CAAC,aAAa,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAChG,CAAC;IAED;;;;OAIG;IACH,8DAA8D;IACvD,MAAM,CAAC,SAAS,CAAc,MAAW,EAAE,YAA8B;QAC/E,OAAO,CAAC,cAAc,CACrB,aAAa,EACb,YAAY,EACZ,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAC7C,CAAC;IACH,CAAC;CACD","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport \"reflect-metadata\";\nimport \"tslib\";\nimport { Is } from \"@twin.org/core\";\nimport type { IEntitySchema } from \"../models/IEntitySchema.js\";\n\nconst META_DATA_KEY = \"EntitySchemaMetadata\";\n\n/**\n * Class to help with decorators.\n */\nexport class DecoratorHelper {\n\t/**\n\t * Get the schema from the reflection metadata.\n\t * @param target The object to get the schema data from.\n\t * @returns The schema from the metadata 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 Reflect.getMetadata(META_DATA_KEY, Is.object(target) ? target : target.prototype) ?? {};\n\t}\n\n\t/**\n\t * Set the schema from the reflection metadata.\n\t * @param target The object to get the schema data from.\n\t * @param entitySchema The schema to set.\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic static setSchema<T = unknown>(target: any, entitySchema: IEntitySchema<T>): void {\n\t\tReflect.defineMetadata(\n\t\t\tMETA_DATA_KEY,\n\t\t\tentitySchema,\n\t\t\tIs.object(target) ? target : target.prototype\n\t\t);\n\t}\n}\n"]}
@@ -121,6 +121,7 @@ export class EntitySchemaHelper {
121
121
  allKeys.splice(idx, 1);
122
122
  }
123
123
  const value = entity[prop.property];
124
+ const valueType = typeof value;
124
125
  if (Is.empty(value)) {
125
126
  // If the value is empty but the property is not optional, then it's invalid
126
127
  if (!prop.optional) {
@@ -145,7 +146,7 @@ export class EntitySchemaHelper {
145
146
  else if (prop.type === EntitySchemaPropertyType.Array && Is.array(value)) {
146
147
  // If the schema expects an array and the value is an array, then it's valid
147
148
  }
148
- else if (prop.type !== typeof value) {
149
+ else if (prop.type !== valueType) {
149
150
  // The schema type does not match the value type
150
151
  throw new GeneralError(EntitySchemaHelper.CLASS_NAME, "invalidEntityProperty", {
151
152
  value,
@@ -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 { EntitySchemaPropertyType } from \"../models/entitySchemaPropertyType.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 === EntitySchemaPropertyType.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 === EntitySchemaPropertyType.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 === EntitySchemaPropertyType.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\t/**\n\t * Find the property in the schema that is marked as the optimistic-lock version token.\n\t * @param schema The entity schema to search.\n\t * @returns The name of the version property, or undefined if none is declared.\n\t * @throws GeneralError if more than one property has isVersion set.\n\t * @throws GeneralError if the version property type is not integer.\n\t */\n\tpublic static findVersionProperty<T>(schema: IEntitySchema<T>): string | undefined {\n\t\tGuards.object(EntitySchemaHelper.CLASS_NAME, nameof(schema), schema);\n\n\t\tconst versionProperties = (schema.properties ?? []).filter(p => p.isVersion === true);\n\t\tif (versionProperties.length > 1) {\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"multipleVersionProperties\");\n\t\t}\n\t\tif (versionProperties.length === 1) {\n\t\t\tif (versionProperties[0].type !== EntitySchemaPropertyType.Integer) {\n\t\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"versionPropertyMustBeInteger\", {\n\t\t\t\t\tproperty: String(versionProperties[0].property),\n\t\t\t\t\ttype: versionProperties[0].type\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn versionProperties[0].property as string | undefined;\n\t\t}\n\t\treturn undefined;\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 { EntitySchemaPropertyType } from \"../models/entitySchemaPropertyType.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\t\t\tconst valueType = typeof value;\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 === EntitySchemaPropertyType.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 === EntitySchemaPropertyType.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 === EntitySchemaPropertyType.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 !== valueType) {\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\t/**\n\t * Find the property in the schema that is marked as the optimistic-lock version token.\n\t * @param schema The entity schema to search.\n\t * @returns The name of the version property, or undefined if none is declared.\n\t * @throws GeneralError if more than one property has isVersion set.\n\t * @throws GeneralError if the version property type is not integer.\n\t */\n\tpublic static findVersionProperty<T>(schema: IEntitySchema<T>): string | undefined {\n\t\tGuards.object(EntitySchemaHelper.CLASS_NAME, nameof(schema), schema);\n\n\t\tconst versionProperties = (schema.properties ?? []).filter(p => p.isVersion === true);\n\t\tif (versionProperties.length > 1) {\n\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"multipleVersionProperties\");\n\t\t}\n\t\tif (versionProperties.length === 1) {\n\t\t\tif (versionProperties[0].type !== EntitySchemaPropertyType.Integer) {\n\t\t\t\tthrow new GeneralError(EntitySchemaHelper.CLASS_NAME, \"versionPropertyMustBeInteger\", {\n\t\t\t\t\tproperty: String(versionProperties[0].property),\n\t\t\t\t\ttype: versionProperties[0].type\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn versionProperties[0].property as string | undefined;\n\t\t}\n\t\treturn undefined;\n\t}\n}\n"]}
package/docs/changelog.md CHANGED
@@ -1,5 +1,104 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.3-next.1](https://github.com/iotaledger/twin-framework/compare/entity-v0.9.3-next.0...entity-v0.9.3-next.1) (2026-08-26)
4
+
5
+
6
+ ### Features
7
+
8
+ * add context id features ([#206](https://github.com/iotaledger/twin-framework/issues/206)) ([ef0d4ee](https://github.com/iotaledger/twin-framework/commit/ef0d4ee11a4f5fc6cc6f52a4958ce905c04ee13b))
9
+ * add IEntitySchemaDiff and entitySchemaDiff utility ([#282](https://github.com/iotaledger/twin-framework/issues/282)) ([9d63e94](https://github.com/iotaledger/twin-framework/commit/9d63e94021ee2ffc138004ee68cf53d08a6b17f9))
10
+ * add support for null in EntityConditions.compare ([922c4ba](https://github.com/iotaledger/twin-framework/commit/922c4ba8af578b4e7eaaf21b3c37a9d788941487))
11
+ * add version field to IEntitySchema and EntitySchemaHelper.getVersion for migration support ([#346](https://github.com/iotaledger/twin-framework/issues/346)) ([e74557e](https://github.com/iotaledger/twin-framework/commit/e74557e4ccbda5b9971f4cfcd0852ba5957cead0))
12
+ * entity schema decorators default value ([33397c2](https://github.com/iotaledger/twin-framework/commit/33397c2e24978a91257371a4c63ce7f6a7125d0c))
13
+ * entity schema diff updates ([#294](https://github.com/iotaledger/twin-framework/issues/294)) ([7a7a94d](https://github.com/iotaledger/twin-framework/commit/7a7a94d14ea5e785dd68fd6de1c5a84941721d28))
14
+ * linting and dependency update ([676b4e9](https://github.com/iotaledger/twin-framework/commit/676b4e9d9bce158065200bbf875bb31da81d166d))
15
+ * locales validation ([#197](https://github.com/iotaledger/twin-framework/issues/197)) ([55fdadb](https://github.com/iotaledger/twin-framework/commit/55fdadb13595ce0047f787bd1d4135d429a99f12))
16
+ * optimistic locking version property for schemas ([#443](https://github.com/iotaledger/twin-framework/issues/443)) ([1b90987](https://github.com/iotaledger/twin-framework/commit/1b909875dc915a0ec133d8424d013ae7e4ddfb48))
17
+ * support for object comparisons in entity conditions ([edae91d](https://github.com/iotaledger/twin-framework/commit/edae91d3205524080188a35e0ab04da036fa4f39))
18
+ * typescript 6 update ([1d10f31](https://github.com/iotaledger/twin-framework/commit/1d10f31e6516ec622773f45e88af82fe749b384a))
19
+ * update dependencies ([4da77ab](https://github.com/iotaledger/twin-framework/commit/4da77ab30f499e52825ac5a76f51436ceb59c26e))
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * allow vacuous truth to match SQL semantics ([5bbc5e5](https://github.com/iotaledger/twin-framework/commit/5bbc5e53069f90bd39485a74a284eda9e5864e66))
25
+ * coerce and includes ([#429](https://github.com/iotaledger/twin-framework/issues/429)) ([98c9132](https://github.com/iotaledger/twin-framework/commit/98c9132316c0393ede9d6e634bbae9e5ece2d6b9))
26
+ * ensure __decorate is defined for decorators ([103a563](https://github.com/iotaledger/twin-framework/commit/103a563ce01ebdef6240d2e590e7b026e8692684))
27
+ * update copyright year ([#260](https://github.com/iotaledger/twin-framework/issues/260)) ([c4ad930](https://github.com/iotaledger/twin-framework/commit/c4ad930fcc84ba6b5447a8074574329870b4c3f5))
28
+ * vacuous entity condition ([#385](https://github.com/iotaledger/twin-framework/issues/385)) ([e1082bf](https://github.com/iotaledger/twin-framework/commit/e1082bff4a66ac270efc9c6654d974c19f889d2d))
29
+
30
+
31
+ ### Dependencies
32
+
33
+ * The following workspace dependencies were updated
34
+ * dependencies
35
+ * @twin.org/core bumped from 0.9.3-next.0 to 0.9.3-next.1
36
+ * @twin.org/nameof bumped from 0.9.3-next.0 to 0.9.3-next.1
37
+ * devDependencies
38
+ * @twin.org/nameof-transformer bumped from 0.9.3-next.0 to 0.9.3-next.1
39
+ * @twin.org/nameof-vitest-plugin bumped from 0.9.3-next.0 to 0.9.3-next.1
40
+ * @twin.org/validate-locales bumped from 0.9.3-next.0 to 0.9.3-next.1
41
+
42
+ ## [0.9.2](https://github.com/iotaledger/twin-framework/compare/entity-v0.9.2...entity-v0.9.2) (2026-08-24)
43
+
44
+
45
+ ### Features
46
+
47
+ * release to production ([b24cba1](https://github.com/iotaledger/twin-framework/commit/b24cba1b6a969278d638e632590602ec881e49fb))
48
+ * release to production ([787287d](https://github.com/iotaledger/twin-framework/commit/787287d06ea8319657401589d61fff369310c422))
49
+ * release to production ([53f4843](https://github.com/iotaledger/twin-framework/commit/53f484326b2851d7a506d2620db24c4a65cee7b3))
50
+ * release to production ([56cda4d](https://github.com/iotaledger/twin-framework/commit/56cda4da93e978c5be19ec7cfd421ae2a7fe4147))
51
+ * release to production ([f7c6586](https://github.com/iotaledger/twin-framework/commit/f7c6586f6976b903b647b4c5ac5ad9421e0c9051))
52
+ * release to production ([829d53d](https://github.com/iotaledger/twin-framework/commit/829d53d3953b1e1b40b0243c04cfdfd3842aac7b))
53
+ * release to production ([5cf3a76](https://github.com/iotaledger/twin-framework/commit/5cf3a76a09eff2e6414d0cba846c7c37400a11d6))
54
+ * release to production ([#330](https://github.com/iotaledger/twin-framework/issues/330)) ([d73f565](https://github.com/iotaledger/twin-framework/commit/d73f565588d156d23ef49b2a5718973756f7a696))
55
+ * release to production ([#382](https://github.com/iotaledger/twin-framework/issues/382)) ([bbed01a](https://github.com/iotaledger/twin-framework/commit/bbed01a605ee9724bda77a0f7feab249118c2d90))
56
+ * release to production ([#417](https://github.com/iotaledger/twin-framework/issues/417)) ([59727e7](https://github.com/iotaledger/twin-framework/commit/59727e73903a137310ca48fe469189cf29879cb9))
57
+ * release to production ([#459](https://github.com/iotaledger/twin-framework/issues/459)) ([e26e2d9](https://github.com/iotaledger/twin-framework/commit/e26e2d9a88767364c32494c45232033447b26e22))
58
+
59
+
60
+ ### Miscellaneous Chores
61
+
62
+ * release to production ([63cae24](https://github.com/iotaledger/twin-framework/commit/63cae2401f6c11f93b2a01260b665064e8bd28e0))
63
+
64
+ ## [0.9.2-next.11](https://github.com/iotaledger/twin-framework/compare/entity-v0.9.2-next.10...entity-v0.9.2-next.11) (2026-08-20)
65
+
66
+
67
+ ### Miscellaneous Chores
68
+
69
+ * **entity:** Synchronize repo versions
70
+
71
+
72
+ ### Dependencies
73
+
74
+ * The following workspace dependencies were updated
75
+ * dependencies
76
+ * @twin.org/core bumped from 0.9.2-next.10 to 0.9.2-next.11
77
+ * @twin.org/nameof bumped from 0.9.2-next.10 to 0.9.2-next.11
78
+ * devDependencies
79
+ * @twin.org/nameof-transformer bumped from 0.9.2-next.10 to 0.9.2-next.11
80
+ * @twin.org/nameof-vitest-plugin bumped from 0.9.2-next.10 to 0.9.2-next.11
81
+ * @twin.org/validate-locales bumped from 0.9.2-next.10 to 0.9.2-next.11
82
+
83
+ ## [0.9.2-next.10](https://github.com/iotaledger/twin-framework/compare/entity-v0.9.2-next.9...entity-v0.9.2-next.10) (2026-08-11)
84
+
85
+
86
+ ### Miscellaneous Chores
87
+
88
+ * **entity:** Synchronize repo versions
89
+
90
+
91
+ ### Dependencies
92
+
93
+ * The following workspace dependencies were updated
94
+ * dependencies
95
+ * @twin.org/core bumped from 0.9.2-next.9 to 0.9.2-next.10
96
+ * @twin.org/nameof bumped from 0.9.2-next.9 to 0.9.2-next.10
97
+ * devDependencies
98
+ * @twin.org/nameof-transformer bumped from 0.9.2-next.9 to 0.9.2-next.10
99
+ * @twin.org/nameof-vitest-plugin bumped from 0.9.2-next.9 to 0.9.2-next.10
100
+ * @twin.org/validate-locales bumped from 0.9.2-next.9 to 0.9.2-next.10
101
+
3
102
  ## [0.9.2-next.9](https://github.com/iotaledger/twin-framework/compare/entity-v0.9.2-next.8...entity-v0.9.2-next.9) (2026-08-10)
4
103
 
5
104
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/entity",
3
- "version": "0.9.2-next.9",
3
+ "version": "0.9.3-next.1",
4
4
  "description": "Helpers for defining and working with entities",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,8 +14,8 @@
14
14
  "node": ">=24.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/core": "0.9.2-next.9",
18
- "@twin.org/nameof": "0.9.2-next.9",
17
+ "@twin.org/core": "0.9.3-next.1",
18
+ "@twin.org/nameof": "0.9.3-next.1",
19
19
  "reflect-metadata": "0.2.2",
20
20
  "tslib": "2.8.1"
21
21
  },