From 8f8dafed5b91022e7883d5d1f4f7dd25bddfa2c1 Mon Sep 17 00:00:00 2001
From: Madeorsk
Date: Sat, 5 Oct 2024 16:55:09 +0200
Subject: [PATCH] Objects, arrays and models changes deep checks when checking
if a model is dirty.
---
README.md | 2 +-
package.json | 2 +-
src/Model/Model.ts | 2 +-
src/Model/Types/ArrayType.ts | 34 +++++++++++++++++++++++++++++
src/Model/Types/ModelType.ts | 9 ++++++++
src/Model/Types/ObjectType.ts | 40 +++++++++++++++++++++++++++++++++++
tests/Model.test.ts | 12 +++++------
7 files changed, 91 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index f9dc607..d683979 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@
-
+
## 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" },
],
});
});