@twin.org/entity 0.0.2-next.8 → 0.0.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.
Files changed (60) hide show
  1. package/dist/es/decorators/entityDecorator.js +19 -0
  2. package/dist/es/decorators/entityDecorator.js.map +1 -0
  3. package/dist/es/decorators/propertyDecorator.js +31 -0
  4. package/dist/es/decorators/propertyDecorator.js.map +1 -0
  5. package/dist/es/factories/entitySchemaFactory.js +9 -0
  6. package/dist/es/factories/entitySchemaFactory.js.map +1 -0
  7. package/dist/es/index.js +22 -0
  8. package/dist/es/index.js.map +1 -0
  9. package/dist/es/models/IComparator.js +2 -0
  10. package/dist/es/models/IComparator.js.map +1 -0
  11. package/dist/es/models/IComparatorGroup.js +2 -0
  12. package/dist/es/models/IComparatorGroup.js.map +1 -0
  13. package/dist/es/models/IEntitySchema.js +2 -0
  14. package/dist/es/models/IEntitySchema.js.map +1 -0
  15. package/dist/es/models/IEntitySchemaOptions.js +4 -0
  16. package/dist/es/models/IEntitySchemaOptions.js.map +1 -0
  17. package/dist/es/models/IEntitySchemaProperty.js +2 -0
  18. package/dist/es/models/IEntitySchemaProperty.js.map +1 -0
  19. package/dist/es/models/IEntitySort.js +2 -0
  20. package/dist/es/models/IEntitySort.js.map +1 -0
  21. package/dist/es/models/comparisonOperator.js +52 -0
  22. package/dist/es/models/comparisonOperator.js.map +1 -0
  23. package/dist/es/models/entityCondition.js +2 -0
  24. package/dist/es/models/entityCondition.js.map +1 -0
  25. package/dist/es/models/entitySchemaPropertyFormat.js +77 -0
  26. package/dist/es/models/entitySchemaPropertyFormat.js.map +1 -0
  27. package/dist/es/models/entitySchemaPropertyType.js +33 -0
  28. package/dist/es/models/entitySchemaPropertyType.js.map +1 -0
  29. package/dist/es/models/logicalOperator.js +17 -0
  30. package/dist/es/models/logicalOperator.js.map +1 -0
  31. package/dist/es/models/sortDirection.js +17 -0
  32. package/dist/es/models/sortDirection.js.map +1 -0
  33. package/dist/es/utils/decoratorHelper.js +29 -0
  34. package/dist/es/utils/decoratorHelper.js.map +1 -0
  35. package/dist/es/utils/entityConditions.js +175 -0
  36. package/dist/es/utils/entityConditions.js.map +1 -0
  37. package/dist/es/utils/entitySchemaHelper.js +143 -0
  38. package/dist/es/utils/entitySchemaHelper.js.map +1 -0
  39. package/dist/es/utils/entitySorter.js +72 -0
  40. package/dist/es/utils/entitySorter.js.map +1 -0
  41. package/dist/types/decorators/entityDecorator.d.ts +1 -1
  42. package/dist/types/decorators/propertyDecorator.d.ts +1 -1
  43. package/dist/types/factories/entitySchemaFactory.d.ts +1 -1
  44. package/dist/types/index.d.ts +19 -19
  45. package/dist/types/models/IComparator.d.ts +1 -1
  46. package/dist/types/models/IComparatorGroup.d.ts +2 -2
  47. package/dist/types/models/IEntitySchema.d.ts +2 -2
  48. package/dist/types/models/IEntitySchemaProperty.d.ts +3 -3
  49. package/dist/types/models/IEntitySort.d.ts +2 -2
  50. package/dist/types/models/entityCondition.d.ts +2 -2
  51. package/dist/types/utils/decoratorHelper.d.ts +1 -1
  52. package/dist/types/utils/entityConditions.d.ts +2 -2
  53. package/dist/types/utils/entitySchemaHelper.d.ts +8 -4
  54. package/dist/types/utils/entitySorter.d.ts +3 -3
  55. package/docs/changelog.md +280 -0
  56. package/docs/reference/classes/EntitySchemaHelper.md +12 -4
  57. package/docs/reference/interfaces/IEntitySchema.md +1 -1
  58. package/package.json +19 -10
  59. package/dist/cjs/index.cjs +0 -673
  60. package/dist/esm/index.mjs +0 -660
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityConditions.js","sourceRoot":"","sources":["../../../src/utils/entityConditions.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ArrayHelper, Is, ObjectHelper } from \"@twin.org/core\";\nimport { ComparisonOperator } from \"../models/comparisonOperator.js\";\nimport type { EntityCondition } from \"../models/entityCondition.js\";\nimport type { IComparator } from \"../models/IComparator.js\";\nimport { LogicalOperator } from \"../models/logicalOperator.js\";\n\n/**\n * Class to perform condition checks.\n */\nexport class EntityConditions {\n\t/**\n\t * See if the entity matches the conditions.\n\t * @param entity The entity to test.\n\t * @param condition The conditions to test.\n\t * @returns True if the entity matches.\n\t */\n\tpublic static check<T>(entity: T, condition?: EntityCondition<T>): boolean {\n\t\t// If no conditions are defined then it's a match\n\t\tif (Is.undefined(condition)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (\"conditions\" in condition) {\n\t\t\t// It's a group of comparisons, so check the individual items and combine with the logical operator\n\t\t\tconst results: boolean[] = condition.conditions.map(c => EntityConditions.check(entity, c));\n\t\t\tif ((condition.logicalOperator ?? LogicalOperator.And) === LogicalOperator.And) {\n\t\t\t\treturn results.every(Boolean);\n\t\t\t}\n\t\t\treturn results.some(Boolean);\n\t\t}\n\n\t\tif (condition.property.includes(\".\")) {\n\t\t\t// It's a child property comparison, so evaluate the child property\n\t\t\t// and then compare it to the conditions\n\t\t\tconst path = condition.property.split(\".\");\n\n\t\t\tconst child = ObjectHelper.propertyGet(entity, path[0]);\n\n\t\t\t// If the child is an array then check each item\n\t\t\tif (Is.array(child)) {\n\t\t\t\tfor (const c of child) {\n\t\t\t\t\tconst check = EntityConditions.check(c, {\n\t\t\t\t\t\t...condition,\n\t\t\t\t\t\tproperty: path.slice(1).join(\".\")\n\t\t\t\t\t});\n\t\t\t\t\tif (check) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// It's a single value so just check the condition\n\t\treturn EntityConditions.compare(entity, condition);\n\t}\n\n\t/**\n\t * See if the entity matches the conditions.\n\t * @param entity The entity to test.\n\t * @param comparator The condition to test.\n\t * @returns True if the entity matches.\n\t */\n\tpublic static compare<T>(entity: T, comparator: IComparator): boolean {\n\t\tconst val = ObjectHelper.propertyGet(entity, comparator.property);\n\t\tconst conditionValue = comparator.value;\n\n\t\tif (Is.undefined(conditionValue)) {\n\t\t\tconst valUndefined = Is.undefined(val);\n\t\t\tif (valUndefined && comparator.comparison === ComparisonOperator.Equals) {\n\t\t\t\treturn true;\n\t\t\t} else if (!valUndefined && comparator.comparison === ComparisonOperator.NotEquals) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t} else if (Is.string(val)) {\n\t\t\tif (Is.string(conditionValue)) {\n\t\t\t\tif (\n\t\t\t\t\t!(\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.Equals && val === conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.NotEquals && val !== conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.GreaterThan && val > conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.LessThan && val < conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.GreaterThanOrEqual &&\n\t\t\t\t\t\t\tval >= conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.LessThanOrEqual &&\n\t\t\t\t\t\t\tval <= conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.Includes &&\n\t\t\t\t\t\t\tval.includes(conditionValue)) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.NotIncludes &&\n\t\t\t\t\t\t\t!val.includes(conditionValue))\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t} else if (Is.array(conditionValue)) {\n\t\t\t\tif (!(comparator.comparison === ComparisonOperator.In && conditionValue.includes(val))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t} else if (Is.number(val)) {\n\t\t\tif (Is.number(conditionValue)) {\n\t\t\t\tif (\n\t\t\t\t\t!(\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.Equals && val === conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.NotEquals && val !== conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.GreaterThan && val > conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.LessThan && val < conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.GreaterThanOrEqual &&\n\t\t\t\t\t\t\tval >= conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.LessThanOrEqual && val <= conditionValue)\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t} else if (Is.array(conditionValue)) {\n\t\t\t\tif (!(comparator.comparison === ComparisonOperator.In && conditionValue.includes(val))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t} else if (Is.boolean(val)) {\n\t\t\tif (Is.boolean(conditionValue)) {\n\t\t\t\tif (\n\t\t\t\t\t!(\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.Equals && val === conditionValue) ||\n\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.NotEquals && val !== conditionValue)\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t} else if (Is.array(val)) {\n\t\t\tif (Is.array(conditionValue)) {\n\t\t\t\tif (\n\t\t\t\t\tcomparator.comparison === ComparisonOperator.Equals ||\n\t\t\t\t\tcomparator.comparison === ComparisonOperator.NotEquals\n\t\t\t\t) {\n\t\t\t\t\tconst matches = ArrayHelper.matches(val, conditionValue);\n\t\t\t\t\tif (\n\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.Equals && matches) ||\n\t\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.NotEquals && !matches)\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t} else if (Is.number(conditionValue) || Is.string(conditionValue)) {\n\t\t\t\tif (\n\t\t\t\t\tcomparator.comparison === ComparisonOperator.Includes ||\n\t\t\t\t\tcomparator.comparison === ComparisonOperator.NotIncludes ||\n\t\t\t\t\tcomparator.comparison === ComparisonOperator.In\n\t\t\t\t) {\n\t\t\t\t\tconst includes = val.includes(conditionValue);\n\t\t\t\t\tif (\n\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.Includes && includes) ||\n\t\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.NotIncludes && !includes) ||\n\t\t\t\t\t\t\t(comparator.comparison === ComparisonOperator.In && includes)\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t} else if (Is.object(conditionValue)) {\n\t\t\t\tif (comparator.comparison === ComparisonOperator.Includes) {\n\t\t\t\t\tfor (const v of val) {\n\t\t\t\t\t\tif (ObjectHelper.equal(v, conditionValue)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (comparator.comparison === ComparisonOperator.NotIncludes) {\n\t\t\t\t\tfor (const v of val) {\n\t\t\t\t\t\tif (!ObjectHelper.equal(v, conditionValue)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n"]}
@@ -0,0 +1,143 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { GeneralError, Guards, Is } from "@twin.org/core";
4
+ import { DecoratorHelper } from "./decoratorHelper.js";
5
+ /**
6
+ * Class to help with entity schema operations.
7
+ */
8
+ export class EntitySchemaHelper {
9
+ /**
10
+ * Runtime name for the class.
11
+ */
12
+ static CLASS_NAME = "EntitySchemaHelper";
13
+ /**
14
+ * Get the schema for the specified object.
15
+ * @param target The object to get the schema data for.
16
+ * @returns The schema for the object if it can be found.
17
+ */
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ static getSchema(target) {
20
+ return DecoratorHelper.getSchema(target);
21
+ }
22
+ /**
23
+ * Get the primary key from the entity schema.
24
+ * @param entitySchema The entity schema to find the primary key from.
25
+ * @returns The key if only one was found.
26
+ * @throws If no primary key was found, or more than one.
27
+ */
28
+ static getPrimaryKey(entitySchema) {
29
+ Guards.object(EntitySchemaHelper.CLASS_NAME, "entitySchema", entitySchema);
30
+ const primaryKeys = (entitySchema.properties ?? [])?.filter(p => p.isPrimary);
31
+ if (primaryKeys.length === 0) {
32
+ throw new GeneralError(EntitySchemaHelper.CLASS_NAME, "noIsPrimary");
33
+ }
34
+ if (primaryKeys.length > 1) {
35
+ throw new GeneralError(EntitySchemaHelper.CLASS_NAME, "multipleIsPrimary");
36
+ }
37
+ return primaryKeys[0];
38
+ }
39
+ /**
40
+ * Get the sort properties from the schema.
41
+ * @param entitySchema The entity schema to find the primary key from.
42
+ * @returns The sort keys from the schema or undefined if there are none.
43
+ */
44
+ static getSortProperties(entitySchema) {
45
+ Guards.object(EntitySchemaHelper.CLASS_NAME, "entitySchema", entitySchema);
46
+ const sortFields = (entitySchema.properties ?? []).filter(p => !Is.undefined(p.sortDirection));
47
+ return sortFields.length > 0
48
+ ? sortFields.map(p => ({
49
+ property: p.property,
50
+ type: p.type,
51
+ sortDirection: p.sortDirection
52
+ }))
53
+ : undefined;
54
+ }
55
+ /**
56
+ * Build sort properties from the schema and override if necessary.
57
+ * @param entitySchema The entity schema to retrieve the default sort keys.
58
+ * @param overrideSortKeys The override sort keys.
59
+ * @returns The finalised sort keys.
60
+ */
61
+ static buildSortProperties(entitySchema, overrideSortKeys) {
62
+ Guards.object(EntitySchemaHelper.CLASS_NAME, "entitySchema", entitySchema);
63
+ let finalSortKeys;
64
+ if (Is.arrayValue(overrideSortKeys)) {
65
+ finalSortKeys = [];
66
+ for (const sortKey of overrideSortKeys) {
67
+ const property = (entitySchema.properties ?? []).find(p => p.property === sortKey.property);
68
+ if (property) {
69
+ finalSortKeys.push({
70
+ property: sortKey.property,
71
+ sortDirection: sortKey.sortDirection,
72
+ type: property.type
73
+ });
74
+ }
75
+ }
76
+ }
77
+ else {
78
+ finalSortKeys = EntitySchemaHelper.getSortProperties(entitySchema);
79
+ }
80
+ return finalSortKeys;
81
+ }
82
+ /**
83
+ * Validate the entity against the schema.
84
+ * @param entity The entity to validate.
85
+ * @param entitySchema The schema to validate against.
86
+ * @throws If the entity is invalid.
87
+ */
88
+ static validateEntity(entity, entitySchema) {
89
+ Guards.object(EntitySchemaHelper.CLASS_NAME, "entity", entity);
90
+ Guards.object(EntitySchemaHelper.CLASS_NAME, "entitySchema", entitySchema);
91
+ const properties = entitySchema.properties ?? [];
92
+ if (properties.length === 0 && Is.objectValue(entity)) {
93
+ throw new GeneralError(EntitySchemaHelper.CLASS_NAME, "invalidEntityProperties");
94
+ }
95
+ const allKeys = Object.keys(entity);
96
+ for (const prop of properties) {
97
+ const idx = allKeys.indexOf(prop.property);
98
+ if (idx !== -1) {
99
+ allKeys.splice(idx, 1);
100
+ }
101
+ const value = entity[prop.property];
102
+ if (Is.empty(value)) {
103
+ // If the value is empty but the property is not optional, then it's invalid
104
+ if (!prop.optional) {
105
+ throw new GeneralError(EntitySchemaHelper.CLASS_NAME, "invalidOptional", {
106
+ property: prop.property,
107
+ type: prop.type
108
+ });
109
+ }
110
+ }
111
+ else if (prop.type === "integer" && Is.integer(value)) {
112
+ // If the schema expects an integer and the value is an integer, then it's valid
113
+ }
114
+ else if (prop.type === "object" &&
115
+ (Is.object(value) ||
116
+ Is.array(value) ||
117
+ Is.string(value) ||
118
+ Is.number(value) ||
119
+ Is.boolean(value) ||
120
+ Is.null(value))) {
121
+ // If the schema expects an object and the value is anything that can be JSON serialised, then it's valid
122
+ }
123
+ else if (prop.type === "array" && Is.array(value)) {
124
+ // If the schema expects an array and the value is an array, then it's valid
125
+ }
126
+ else if (prop.type !== typeof value) {
127
+ // The schema type does not match the value type
128
+ throw new GeneralError(EntitySchemaHelper.CLASS_NAME, "invalidEntityProperty", {
129
+ value,
130
+ property: prop.property,
131
+ type: prop.type
132
+ });
133
+ }
134
+ }
135
+ if (allKeys.length > 0) {
136
+ // There are keys in the entity that are not in the schema
137
+ throw new GeneralError(EntitySchemaHelper.CLASS_NAME, "invalidEntityKeys", {
138
+ keys: allKeys.join(", ")
139
+ });
140
+ }
141
+ }
142
+ }
143
+ //# sourceMappingURL=entitySchemaHelper.js.map
@@ -0,0 +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 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"]}
@@ -0,0 +1,72 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { Is } from "@twin.org/core";
4
+ import { SortDirection } from "../models/sortDirection.js";
5
+ /**
6
+ * Class to perform sort operations on entities.
7
+ */
8
+ export class EntitySorter {
9
+ /**
10
+ * Sort a list of entities using multiple keys and direction.
11
+ * @param entities The list of entities.
12
+ * @param entitySorters The sort keys to use.
13
+ * @returns The sorted list.
14
+ */
15
+ static sort(entities, entitySorters) {
16
+ if (!Is.arrayValue(entities) || Is.empty(entitySorters)) {
17
+ return entities;
18
+ }
19
+ return entities.sort((a, b) => {
20
+ for (const entitySorter of entitySorters) {
21
+ const compareResult = EntitySorter.compare(a, b, entitySorter.property, entitySorter.type, entitySorter.sortDirection);
22
+ if (compareResult !== 0) {
23
+ return compareResult;
24
+ }
25
+ }
26
+ return 0;
27
+ });
28
+ }
29
+ /**
30
+ * Compare two properties.
31
+ * @param entity1 The first entity.
32
+ * @param entity2 The second entity.
33
+ * @param prop The property to compare.
34
+ * @param type The type of the property.
35
+ * @param direction The direction of the sort.
36
+ * @returns The result of the comparison.
37
+ */
38
+ static compare(entity1, entity2, prop, type, direction = SortDirection.Ascending) {
39
+ let res = 0;
40
+ const hasProp1 = !Is.empty(entity1[prop]);
41
+ const hasProp2 = !Is.empty(entity2[prop]);
42
+ if (hasProp1 && hasProp2) {
43
+ if (type === "number" || type === "integer") {
44
+ res = entity1[prop] - entity2[prop];
45
+ }
46
+ else if (type === "boolean") {
47
+ const b1 = entity1[prop];
48
+ const b2 = entity2[prop];
49
+ if (b1 === b2) {
50
+ res = 0;
51
+ }
52
+ else if (b1) {
53
+ res = -1;
54
+ }
55
+ else {
56
+ res = 1;
57
+ }
58
+ }
59
+ else if (type === "string") {
60
+ res = entity1[prop].localeCompare(entity2[prop]);
61
+ }
62
+ }
63
+ else if (hasProp1) {
64
+ res = -1;
65
+ }
66
+ else {
67
+ res = 1;
68
+ }
69
+ return direction === SortDirection.Ascending ? res : res * -1;
70
+ }
71
+ }
72
+ //# sourceMappingURL=entitySorter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitySorter.js","sourceRoot":"","sources":["../../../src/utils/entitySorter.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAGpC,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE3D;;GAEG;AACH,MAAM,OAAO,YAAY;IACxB;;;;;OAKG;IACI,MAAM,CAAC,IAAI,CAAI,QAAa,EAAE,aAAgC;QACpE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;YACzD,OAAO,QAAQ,CAAC;QACjB,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC7B,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;gBAC1C,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,CACzC,CAAC,EACD,CAAC,EACD,YAAY,CAAC,QAAQ,EACrB,YAAY,CAAC,IAAI,EACjB,YAAY,CAAC,aAAa,CAC1B,CAAC;gBACF,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;oBACzB,OAAO,aAAa,CAAC;gBACtB,CAAC;YACF,CAAC;YACD,OAAO,CAAC,CAAC;QACV,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,OAAO,CACpB,OAAU,EACV,OAAU,EACV,IAAa,EACb,IAA8B,EAC9B,YAA2B,aAAa,CAAC,SAAS;QAElD,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,MAAM,QAAQ,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAE1C,IAAI,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC7C,GAAG,GAAI,OAAO,CAAC,IAAI,CAAuB,GAAI,OAAO,CAAC,IAAI,CAAuB,CAAC;YACnF,CAAC;iBAAM,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC/B,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAuB,CAAC;gBAC/C,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAuB,CAAC;gBAC/C,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;oBACf,GAAG,GAAG,CAAC,CAAC;gBACT,CAAC;qBAAM,IAAI,EAAE,EAAE,CAAC;oBACf,GAAG,GAAG,CAAC,CAAC,CAAC;gBACV,CAAC;qBAAM,CAAC;oBACP,GAAG,GAAG,CAAC,CAAC;gBACT,CAAC;YACF,CAAC;iBAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC9B,GAAG,GAAI,OAAO,CAAC,IAAI,CAAuB,CAAC,aAAa,CACvD,OAAO,CAAC,IAAI,CAAsB,CAClC,CAAC;YACH,CAAC;QACF,CAAC;aAAM,IAAI,QAAQ,EAAE,CAAC;YACrB,GAAG,GAAG,CAAC,CAAC,CAAC;QACV,CAAC;aAAM,CAAC;YACP,GAAG,GAAG,CAAC,CAAC;QACT,CAAC;QAED,OAAO,SAAS,KAAK,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;CACD","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is } from \"@twin.org/core\";\nimport type { EntitySchemaPropertyType } from \"../models/entitySchemaPropertyType.js\";\nimport type { IEntitySort } from \"../models/IEntitySort.js\";\nimport { SortDirection } from \"../models/sortDirection.js\";\n\n/**\n * Class to perform sort operations on entities.\n */\nexport class EntitySorter {\n\t/**\n\t * Sort a list of entities using multiple keys and direction.\n\t * @param entities The list of entities.\n\t * @param entitySorters The sort keys to use.\n\t * @returns The sorted list.\n\t */\n\tpublic static sort<T>(entities: T[], entitySorters?: IEntitySort<T>[]): T[] {\n\t\tif (!Is.arrayValue(entities) || Is.empty(entitySorters)) {\n\t\t\treturn entities;\n\t\t}\n\n\t\treturn entities.sort((a, b) => {\n\t\t\tfor (const entitySorter of entitySorters) {\n\t\t\t\tconst compareResult = EntitySorter.compare(\n\t\t\t\t\ta,\n\t\t\t\t\tb,\n\t\t\t\t\tentitySorter.property,\n\t\t\t\t\tentitySorter.type,\n\t\t\t\t\tentitySorter.sortDirection\n\t\t\t\t);\n\t\t\t\tif (compareResult !== 0) {\n\t\t\t\t\treturn compareResult;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 0;\n\t\t});\n\t}\n\n\t/**\n\t * Compare two properties.\n\t * @param entity1 The first entity.\n\t * @param entity2 The second entity.\n\t * @param prop The property to compare.\n\t * @param type The type of the property.\n\t * @param direction The direction of the sort.\n\t * @returns The result of the comparison.\n\t */\n\tpublic static compare<T>(\n\t\tentity1: T,\n\t\tentity2: T,\n\t\tprop: keyof T,\n\t\ttype: EntitySchemaPropertyType,\n\t\tdirection: SortDirection = SortDirection.Ascending\n\t): number {\n\t\tlet res = 0;\n\t\tconst hasProp1 = !Is.empty(entity1[prop]);\n\t\tconst hasProp2 = !Is.empty(entity2[prop]);\n\n\t\tif (hasProp1 && hasProp2) {\n\t\t\tif (type === \"number\" || type === \"integer\") {\n\t\t\t\tres = (entity1[prop] as unknown as number) - (entity2[prop] as unknown as number);\n\t\t\t} else if (type === \"boolean\") {\n\t\t\t\tconst b1 = entity1[prop] as unknown as boolean;\n\t\t\t\tconst b2 = entity2[prop] as unknown as boolean;\n\t\t\t\tif (b1 === b2) {\n\t\t\t\t\tres = 0;\n\t\t\t\t} else if (b1) {\n\t\t\t\t\tres = -1;\n\t\t\t\t} else {\n\t\t\t\t\tres = 1;\n\t\t\t\t}\n\t\t\t} else if (type === \"string\") {\n\t\t\t\tres = (entity1[prop] as unknown as string).localeCompare(\n\t\t\t\t\tentity2[prop] as unknown as string\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (hasProp1) {\n\t\t\tres = -1;\n\t\t} else {\n\t\t\tres = 1;\n\t\t}\n\n\t\treturn direction === SortDirection.Ascending ? res : res * -1;\n\t}\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import "reflect-metadata";
2
- import type { IEntitySchemaOptions } from "../models/IEntitySchemaOptions";
2
+ import type { IEntitySchemaOptions } from "../models/IEntitySchemaOptions.js";
3
3
  /**
4
4
  * Decorator to produce schema data for entity.
5
5
  * @param options The options for the entity.
@@ -1,5 +1,5 @@
1
1
  import "reflect-metadata";
2
- import type { IEntitySchemaProperty } from "../models/IEntitySchemaProperty";
2
+ import type { IEntitySchemaProperty } from "../models/IEntitySchemaProperty.js";
3
3
  /**
4
4
  * Decorator to produce schema property data for entities.
5
5
  * @param options The options for the property.
@@ -1,5 +1,5 @@
1
1
  import { Factory } from "@twin.org/core";
2
- import type { IEntitySchema } from "../models/IEntitySchema";
2
+ import type { IEntitySchema } from "../models/IEntitySchema.js";
3
3
  /**
4
4
  * Factory for creating entity schemas.
5
5
  */
@@ -1,19 +1,19 @@
1
- export * from "./decorators/entityDecorator";
2
- export * from "./decorators/propertyDecorator";
3
- export * from "./factories/entitySchemaFactory";
4
- export * from "./models/comparisonOperator";
5
- export * from "./models/entityCondition";
6
- export * from "./models/entitySchemaPropertyFormat";
7
- export * from "./models/entitySchemaPropertyType";
8
- export * from "./models/IComparator";
9
- export * from "./models/IComparatorGroup";
10
- export * from "./models/IEntitySchema";
11
- export * from "./models/IEntitySchemaOptions";
12
- export * from "./models/IEntitySchemaProperty";
13
- export * from "./models/IEntitySort";
14
- export * from "./models/logicalOperator";
15
- export * from "./models/sortDirection";
16
- export * from "./utils/decoratorHelper";
17
- export * from "./utils/entityConditions";
18
- export * from "./utils/entitySchemaHelper";
19
- export * from "./utils/entitySorter";
1
+ export * from "./decorators/entityDecorator.js";
2
+ export * from "./decorators/propertyDecorator.js";
3
+ export * from "./factories/entitySchemaFactory.js";
4
+ export * from "./models/comparisonOperator.js";
5
+ export * from "./models/entityCondition.js";
6
+ export * from "./models/entitySchemaPropertyFormat.js";
7
+ export * from "./models/entitySchemaPropertyType.js";
8
+ export * from "./models/IComparator.js";
9
+ export * from "./models/IComparatorGroup.js";
10
+ export * from "./models/IEntitySchema.js";
11
+ export * from "./models/IEntitySchemaOptions.js";
12
+ export * from "./models/IEntitySchemaProperty.js";
13
+ export * from "./models/IEntitySort.js";
14
+ export * from "./models/logicalOperator.js";
15
+ export * from "./models/sortDirection.js";
16
+ export * from "./utils/decoratorHelper.js";
17
+ export * from "./utils/entityConditions.js";
18
+ export * from "./utils/entitySchemaHelper.js";
19
+ export * from "./utils/entitySorter.js";
@@ -1,4 +1,4 @@
1
- import type { ComparisonOperator } from "./comparisonOperator";
1
+ import type { ComparisonOperator } from "./comparisonOperator.js";
2
2
  /**
3
3
  * Interface defining comparator operator.
4
4
  */
@@ -1,5 +1,5 @@
1
- import type { EntityCondition } from "./entityCondition";
2
- import type { LogicalOperator } from "./logicalOperator";
1
+ import type { EntityCondition } from "./entityCondition.js";
2
+ import type { LogicalOperator } from "./logicalOperator.js";
3
3
  /**
4
4
  * Interface defining condition group operator.
5
5
  */
@@ -1,5 +1,5 @@
1
- import type { IEntitySchemaOptions } from "./IEntitySchemaOptions";
2
- import type { IEntitySchemaProperty } from "./IEntitySchemaProperty";
1
+ import type { IEntitySchemaOptions } from "./IEntitySchemaOptions.js";
2
+ import type { IEntitySchemaProperty } from "./IEntitySchemaProperty.js";
3
3
  /**
4
4
  * Definition for an entity schema.
5
5
  */
@@ -1,6 +1,6 @@
1
- import type { EntitySchemaPropertyFormat } from "./entitySchemaPropertyFormat";
2
- import type { EntitySchemaPropertyType } from "./entitySchemaPropertyType";
3
- import type { SortDirection } from "./sortDirection";
1
+ import type { EntitySchemaPropertyFormat } from "./entitySchemaPropertyFormat.js";
2
+ import type { EntitySchemaPropertyType } from "./entitySchemaPropertyType.js";
3
+ import type { SortDirection } from "./sortDirection.js";
4
4
  /**
5
5
  * Definition for an entity schema property.
6
6
  */
@@ -1,5 +1,5 @@
1
- import type { EntitySchemaPropertyType } from "./entitySchemaPropertyType";
2
- import type { SortDirection } from "./sortDirection";
1
+ import type { EntitySchemaPropertyType } from "./entitySchemaPropertyType.js";
2
+ import type { SortDirection } from "./sortDirection.js";
3
3
  /**
4
4
  * Definition of an entity property sort details.
5
5
  */
@@ -1,5 +1,5 @@
1
- import type { IComparator } from "./IComparator";
2
- import type { IComparatorGroup } from "./IComparatorGroup";
1
+ import type { IComparator } from "./IComparator.js";
2
+ import type { IComparatorGroup } from "./IComparatorGroup.js";
3
3
  /**
4
4
  * Type defining condition for entities filtering.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  import "reflect-metadata";
2
- import type { IEntitySchema } from "../models/IEntitySchema";
2
+ import type { IEntitySchema } from "../models/IEntitySchema.js";
3
3
  /**
4
4
  * Class to help with decorators.
5
5
  */
@@ -1,5 +1,5 @@
1
- import type { EntityCondition } from "../models/entityCondition";
2
- import type { IComparator } from "../models/IComparator";
1
+ import type { EntityCondition } from "../models/entityCondition.js";
2
+ import type { IComparator } from "../models/IComparator.js";
3
3
  /**
4
4
  * Class to perform condition checks.
5
5
  */
@@ -1,11 +1,15 @@
1
- import type { IEntitySchema } from "../models/IEntitySchema";
2
- import type { IEntitySchemaProperty } from "../models/IEntitySchemaProperty";
3
- import type { IEntitySort } from "../models/IEntitySort";
4
- import type { SortDirection } from "../models/sortDirection";
1
+ import type { IEntitySchema } from "../models/IEntitySchema.js";
2
+ import type { IEntitySchemaProperty } from "../models/IEntitySchemaProperty.js";
3
+ import type { IEntitySort } from "../models/IEntitySort.js";
4
+ import type { SortDirection } from "../models/sortDirection.js";
5
5
  /**
6
6
  * Class to help with entity schema operations.
7
7
  */
8
8
  export declare class EntitySchemaHelper {
9
+ /**
10
+ * Runtime name for the class.
11
+ */
12
+ static readonly CLASS_NAME: string;
9
13
  /**
10
14
  * Get the schema for the specified object.
11
15
  * @param target The object to get the schema data for.
@@ -1,6 +1,6 @@
1
- import type { EntitySchemaPropertyType } from "../models/entitySchemaPropertyType";
2
- import type { IEntitySort } from "../models/IEntitySort";
3
- import { SortDirection } from "../models/sortDirection";
1
+ import type { EntitySchemaPropertyType } from "../models/entitySchemaPropertyType.js";
2
+ import type { IEntitySort } from "../models/IEntitySort.js";
3
+ import { SortDirection } from "../models/sortDirection.js";
4
4
  /**
5
5
  * Class to perform sort operations on entities.
6
6
  */