@twin.org/entity 0.0.1-next.44 → 0.0.1-next.45

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.
@@ -533,6 +533,54 @@ class EntitySchemaHelper {
533
533
  }
534
534
  return finalSortKeys;
535
535
  }
536
+ /**
537
+ * Validate the entity against the schema.
538
+ * @param entity The entity to validate.
539
+ * @param entitySchema The schema to validate against.
540
+ * @throws If the entity is invalid.
541
+ */
542
+ static validateEntity(entity, entitySchema) {
543
+ core.Guards.object(EntitySchemaHelper._CLASS_NAME, "entity", entity);
544
+ core.Guards.object(EntitySchemaHelper._CLASS_NAME, "entitySchema", entitySchema);
545
+ const properties = entitySchema.properties ?? [];
546
+ if (properties.length === 0 && core.Is.objectValue(entity)) {
547
+ throw new core.GeneralError(EntitySchemaHelper._CLASS_NAME, "invalidEntityProperties");
548
+ }
549
+ const allKeys = Object.keys(entity);
550
+ for (const prop of properties) {
551
+ const idx = allKeys.indexOf(prop.property);
552
+ if (idx !== -1) {
553
+ allKeys.splice(idx, 1);
554
+ }
555
+ const value = entity[prop.property];
556
+ if (core.Is.empty(value)) {
557
+ // If the value is empty but the property is not optional, then it's invalid
558
+ if (!prop.optional) {
559
+ throw new core.GeneralError(EntitySchemaHelper._CLASS_NAME, "invalidOptional", {
560
+ property: prop.property,
561
+ type: prop.type
562
+ });
563
+ }
564
+ }
565
+ else if (prop.type === "integer" && core.Is.integer(value)) ;
566
+ else if (prop.type === "object" && core.Is.object(value)) ;
567
+ else if (prop.type === "array" && core.Is.array(value)) ;
568
+ else if (prop.type !== typeof value) {
569
+ // The schema type does not match the value type
570
+ throw new core.GeneralError(EntitySchemaHelper._CLASS_NAME, "invalidEntity", {
571
+ value,
572
+ property: prop.property,
573
+ type: prop.type
574
+ });
575
+ }
576
+ }
577
+ if (allKeys.length > 0) {
578
+ // There are keys in the entity that are not in the schema
579
+ throw new core.GeneralError(EntitySchemaHelper._CLASS_NAME, "invalidEntityKeys", {
580
+ keys: allKeys.join(", ")
581
+ });
582
+ }
583
+ }
536
584
  }
537
585
 
538
586
  // Copyright 2024 IOTA Stiftung.
@@ -531,6 +531,54 @@ class EntitySchemaHelper {
531
531
  }
532
532
  return finalSortKeys;
533
533
  }
534
+ /**
535
+ * Validate the entity against the schema.
536
+ * @param entity The entity to validate.
537
+ * @param entitySchema The schema to validate against.
538
+ * @throws If the entity is invalid.
539
+ */
540
+ static validateEntity(entity, entitySchema) {
541
+ Guards.object(EntitySchemaHelper._CLASS_NAME, "entity", entity);
542
+ Guards.object(EntitySchemaHelper._CLASS_NAME, "entitySchema", entitySchema);
543
+ const properties = entitySchema.properties ?? [];
544
+ if (properties.length === 0 && Is.objectValue(entity)) {
545
+ throw new GeneralError(EntitySchemaHelper._CLASS_NAME, "invalidEntityProperties");
546
+ }
547
+ const allKeys = Object.keys(entity);
548
+ for (const prop of properties) {
549
+ const idx = allKeys.indexOf(prop.property);
550
+ if (idx !== -1) {
551
+ allKeys.splice(idx, 1);
552
+ }
553
+ const value = entity[prop.property];
554
+ if (Is.empty(value)) {
555
+ // If the value is empty but the property is not optional, then it's invalid
556
+ if (!prop.optional) {
557
+ throw new GeneralError(EntitySchemaHelper._CLASS_NAME, "invalidOptional", {
558
+ property: prop.property,
559
+ type: prop.type
560
+ });
561
+ }
562
+ }
563
+ else if (prop.type === "integer" && Is.integer(value)) ;
564
+ else if (prop.type === "object" && Is.object(value)) ;
565
+ else if (prop.type === "array" && Is.array(value)) ;
566
+ else if (prop.type !== typeof value) {
567
+ // The schema type does not match the value type
568
+ throw new GeneralError(EntitySchemaHelper._CLASS_NAME, "invalidEntity", {
569
+ value,
570
+ property: prop.property,
571
+ type: prop.type
572
+ });
573
+ }
574
+ }
575
+ if (allKeys.length > 0) {
576
+ // There are keys in the entity that are not in the schema
577
+ throw new GeneralError(EntitySchemaHelper._CLASS_NAME, "invalidEntityKeys", {
578
+ keys: allKeys.join(", ")
579
+ });
580
+ }
581
+ }
534
582
  }
535
583
 
536
584
  // Copyright 2024 IOTA Stiftung.
@@ -35,4 +35,11 @@ export declare class EntitySchemaHelper {
35
35
  property: keyof T;
36
36
  sortDirection: SortDirection;
37
37
  }[]): IEntitySort<T>[] | undefined;
38
+ /**
39
+ * Validate the entity against the schema.
40
+ * @param entity The entity to validate.
41
+ * @param entitySchema The schema to validate against.
42
+ * @throws If the entity is invalid.
43
+ */
44
+ static validateEntity<T>(entity: T, entitySchema: IEntitySchema<T>): void;
38
45
  }
package/docs/changelog.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # @twin.org/entity - Changelog
2
2
 
3
- ## 0.0.1-next.44
3
+ ## 0.0.1-next.45
4
4
 
5
5
  - Initial Release
@@ -125,3 +125,37 @@ The override sort keys.
125
125
  `undefined` \| [`IEntitySort`](../interfaces/IEntitySort.md)\<`T`\>[]
126
126
 
127
127
  The finalised sort keys.
128
+
129
+ ***
130
+
131
+ ### validateEntity()
132
+
133
+ > `static` **validateEntity**\<`T`\>(`entity`, `entitySchema`): `void`
134
+
135
+ Validate the entity against the schema.
136
+
137
+ #### Type Parameters
138
+
139
+ • **T**
140
+
141
+ #### Parameters
142
+
143
+ ##### entity
144
+
145
+ `T`
146
+
147
+ The entity to validate.
148
+
149
+ ##### entitySchema
150
+
151
+ [`IEntitySchema`](../interfaces/IEntitySchema.md)\<`T`\>
152
+
153
+ The schema to validate against.
154
+
155
+ #### Returns
156
+
157
+ `void`
158
+
159
+ #### Throws
160
+
161
+ If the entity is invalid.
package/locales/en.json CHANGED
@@ -2,7 +2,11 @@
2
2
  "error": {
3
3
  "entitySchemaHelper": {
4
4
  "noIsPrimary": "Property \"entitySchema.properties\" must contain a value with isPrimary set",
5
- "multipleIsPrimary": "Property \"entitySchema.properties\" contains more than one property with isPrimary set"
5
+ "multipleIsPrimary": "Property \"entitySchema.properties\" contains more than one property with isPrimary set",
6
+ "invalidEntityProperties": "The schema has no properties defined, but the entity has properties",
7
+ "invalidEntity": "The entity value of \"{value}\" does not match the type \"{type}\" for property \"{property}\"",
8
+ "invalidOptional": "The entity property \"{property}\" of type \"{type}\" is not optional, but no value has been provided",
9
+ "invalidEntityKeys": "The entity had additional properties that are not in the schema, \"{keys}\""
6
10
  }
7
11
  }
8
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/entity",
3
- "version": "0.0.1-next.44",
3
+ "version": "0.0.1-next.45",
4
4
  "description": "Helpers for defining and working with entities",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,7 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/core": "0.0.1-next.44",
17
+ "@twin.org/core": "0.0.1-next.45",
18
18
  "@twin.org/nameof": "next",
19
19
  "reflect-metadata": "0.2.2"
20
20
  },