diff --git a/README.md b/README.md index f9dc607..d683979 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@

- Version 3.2.1 + Version 3.2.2

## Introduction diff --git a/package.json b/package.json index ba55fcf..23a9cdc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sharkitek/core", - "version": "3.2.1", + "version": "3.2.2", "description": "TypeScript library for well-designed model architectures.", "keywords": [ "deserialization", diff --git a/src/Model/Model.ts b/src/Model/Model.ts index dc7d63c..36b4daa 100644 --- a/src/Model/Model.ts +++ b/src/Model/Model.ts @@ -243,7 +243,7 @@ export function model { // For each property, set its original value to its current property value. - this._originalProperties[propertyName] = (this as PropertiesModel)[propertyName]; + this._originalProperties[propertyName] = structuredClone(this as PropertiesModel)[propertyName]; propertyDefinition.type.resetDiff((this as PropertiesModel)[propertyName]); }); } diff --git a/src/Model/Types/ArrayType.ts b/src/Model/Types/ArrayType.ts index cd1d738..ee0bd71 100644 --- a/src/Model/Types/ArrayType.ts +++ b/src/Model/Types/ArrayType.ts @@ -54,6 +54,40 @@ export class ArrayType extends Type this.valueDefinition.type.resetDiff(value)); } + + propertyHasChanged(originalValue: SharkitekValueType[]|null|undefined, currentValue: SharkitekValueType[]|null|undefined): boolean + { + // If any array length is different, arrays are different. + if (originalValue?.length != currentValue?.length) return true; + // If length is undefined, values are probably not arrays. + if (originalValue?.length == undefined) return false; + + for (const key of originalValue.keys()) + { // Check for any change for each value in the array. + if (this.valueDefinition.type.propertyHasChanged(originalValue[key], currentValue[key])) + // The value has changed, the array is different. + return true; + } + + return false; // No change detected. + } + + serializedPropertyHasChanged(originalValue: SerializedValueType[] | null | undefined, currentValue: SerializedValueType[] | null | undefined): boolean + { + // If any array length is different, arrays are different. + if (originalValue?.length != currentValue?.length) return true; + // If length is undefined, values are probably not arrays. + if (originalValue?.length == undefined) return false; + + for (const key of originalValue.keys()) + { // Check for any change for each value in the array. + if (this.valueDefinition.type.serializedPropertyHasChanged(originalValue[key], currentValue[key])) + // The value has changed, the array is different. + return true; + } + + return false; // No change detected. + } } /** diff --git a/src/Model/Types/ModelType.ts b/src/Model/Types/ModelType.ts index b1641f6..9cfe1ba 100644 --- a/src/Model/Types/ModelType.ts +++ b/src/Model/Types/ModelType.ts @@ -48,6 +48,15 @@ export class ModelType extends Type|null|undefined, currentValue: Model|null|undefined): boolean + { + if (originalValue === undefined) return currentValue !== undefined; + if (originalValue === null) return currentValue !== null; + + // If the current value is dirty, property has changed. + return currentValue.isDirty(); + } } /** diff --git a/src/Model/Types/ObjectType.ts b/src/Model/Types/ObjectType.ts index b2af673..a036b17 100644 --- a/src/Model/Types/ObjectType.ts +++ b/src/Model/Types/ObjectType.ts @@ -66,6 +66,46 @@ export class ObjectType extends Type|null|undefined, currentValue: PropertiesModel|null|undefined): boolean + { + // Get keys arrays. + const originalKeys = Object.keys(originalValue) as (keyof Shape)[]; + const currentKeys = Object.keys(currentValue) as (keyof Shape)[]; + + if (originalKeys.join(",") != currentKeys.join(",")) + // Keys have changed, objects are different. + return true; + + for (const key of originalKeys) + { // Check for any change for each value in the object. + if (this.shape[key].type.propertyHasChanged(originalValue[key], currentValue[key])) + // The value has changed, the object is different. + return true; + } + + return false; // No change detected. + } + + serializedPropertyHasChanged(originalValue: SerializedModel|null|undefined, currentValue: SerializedModel|null|undefined): boolean + { + // Get keys arrays. + const originalKeys = Object.keys(originalValue) as (keyof Shape)[]; + const currentKeys = Object.keys(currentValue) as (keyof Shape)[]; + + if (originalKeys.join(",") != currentKeys.join(",")) + // Keys have changed, objects are different. + return true; + + for (const key of originalKeys) + { // Check for any change for each value in the object. + if (this.shape[key].type.serializedPropertyHasChanged(originalValue[key], currentValue[key])) + // The value has changed, the object is different. + return true; + } + + return false; // No change detected. + } } /** diff --git a/tests/Model.test.ts b/tests/Model.test.ts index 36aa9b9..03ecc63 100644 --- a/tests/Model.test.ts +++ b/tests/Model.test.ts @@ -142,23 +142,21 @@ it("save with modified submodels", () => { title: "this is a test", authors: [ { name: "DOE", firstName: "John", email: "test@test.test", createdAt: (new Date()).toISOString(), active: true, }, - { name: "TEST", firstName: "Another", email: "another@test.test", createdAt: (new Date()).toISOString(), active: false, }, + { name: "TEST", firstName: "Another", email: "another@test.test", createdAt: (new Date("1997-09-09")).toISOString(), active: false, }, ], text: "this is a long test.", evaluation: "25.23", tags: [ {name: "test"}, {name: "foo"} ], }); - article.authors = article.authors.map((author) => { - author.name = "TEST"; - return author; - }); + article.authors[0].name = "TEST"; + article.authors[1].createdAt.setMonth(9); expect(article.save()).toStrictEqual({ id: 1, authors: [ - { name: "TEST", }, - {}, //{ name: "TEST", firstName: "Another", email: "another@test.test" }, + { name: "TEST" }, + { createdAt: (new Date("1997-10-09")).toISOString() }, //{ name: "TEST", firstName: "Another", email: "another@test.test" }, ], }); });