Compare commits

..

No commits in common. "main" and "v3.2.1" have entirely different histories.
main ... v3.2.1

7 changed files with 19 additions and 100 deletions

View file

@ -19,7 +19,7 @@
</p> </p>
<p align="center"> <p align="center">
<img alt="Version 3.3.0" src="https://img.shields.io/badge/version-3.3.0-blue" /> <img alt="Version 3.2.1" src="https://img.shields.io/badge/version-3.2.1-blue" />
</p> </p>
## Introduction ## Introduction
@ -27,7 +27,7 @@
Sharkitek is a Javascript / TypeScript library designed to ease development of client-side models. Sharkitek is a Javascript / TypeScript library designed to ease development of client-side models.
With Sharkitek, you define the architecture of your models by specifying their properties and their types. With Sharkitek, you define the architecture of your models by specifying their properties and their types.
Then, you can use the defined methods like `serialize`, `deserialize`, `patch` or `serializeDiff`. Then, you can use the defined methods like `serialize`, `deserialize`, `save` or `serializeDiff`.
```typescript ```typescript
class Example extends s.model({ class Example extends s.model({
@ -227,7 +227,7 @@ const result = model.serializeDiff();
// result = {} // result = {}
``` ```
#### `patch()` #### `save()`
Get difference between original values and current ones, then reset it. Get difference between original values and current ones, then reset it.
Similar to call `serializeDiff()` then `resetDiff()`. Similar to call `serializeDiff()` then `resetDiff()`.
@ -246,7 +246,7 @@ const model = (new TestModel()).deserialize({
model.title = "A new title for a new world"; model.title = "A new title for a new world";
const result = model.patch(); const result = model.save();
// if `id` is defined as the model identifier: // if `id` is defined as the model identifier:
// result = { id: 5, title: "A new title for a new world" } // result = { id: 5, title: "A new title for a new world" }
// if `id` is not defined as the model identifier: // if `id` is not defined as the model identifier:

View file

@ -1,6 +1,6 @@
{ {
"name": "@sharkitek/core", "name": "@sharkitek/core",
"version": "3.3.0", "version": "3.2.1",
"description": "TypeScript library for well-designed model architectures.", "description": "TypeScript library for well-designed model architectures.",
"keywords": [ "keywords": [
"deserialization", "deserialization",

View file

@ -105,7 +105,7 @@ export interface ModelDefinition<Shape extends ModelShape, IdentifierType, Model
* Get difference between original values and current ones, then reset it. * Get difference between original values and current ones, then reset it.
* Similar to call `serializeDiff()` then `resetDiff()`. * Similar to call `serializeDiff()` then `resetDiff()`.
*/ */
patch(): Partial<SerializedModel<Shape>>; save(): Partial<SerializedModel<Shape>>;
} }
/** /**
@ -243,12 +243,12 @@ export function model<ModelType extends Model<Shape, IdentifierType<Shape, Ident
{ {
this.forEachModelProperty((propertyName, propertyDefinition) => { this.forEachModelProperty((propertyName, propertyDefinition) => {
// For each property, set its original value to its current property value. // For each property, set its original value to its current property value.
this._originalProperties[propertyName] = structuredClone(this as PropertiesModel<Shape>)[propertyName]; this._originalProperties[propertyName] = (this as PropertiesModel<Shape>)[propertyName];
propertyDefinition.type.resetDiff((this as PropertiesModel<Shape>)[propertyName]); propertyDefinition.type.resetDiff((this as PropertiesModel<Shape>)[propertyName]);
}); });
} }
patch(): Partial<SerializedModel<Shape>> save(): Partial<SerializedModel<Shape>>
{ {
// Get the difference. // Get the difference.
const diff = this.serializeDiff(); const diff = this.serializeDiff();

View file

@ -54,40 +54,6 @@ export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<Ser
// Reset diff of all elements. // Reset diff of all elements.
value.forEach((value) => this.valueDefinition.type.resetDiff(value)); value.forEach((value) => 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.
}
} }
/** /**

View file

@ -48,15 +48,6 @@ export class ModelType<Shape extends ModelShape> extends Type<SerializedModel<Sh
// Reset diff of the given model. // Reset diff of the given model.
value?.resetDiff(); value?.resetDiff();
} }
propertyHasChanged(originalValue: Model<Shape>|null|undefined, currentValue: Model<Shape>|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();
}
} }
/** /**

View file

@ -66,46 +66,6 @@ export class ObjectType<Shape extends ModelShape> extends Type<SerializedModel<S
fieldDefinition.type.resetDiff(value?.[fieldName]); fieldDefinition.type.resetDiff(value?.[fieldName]);
}); });
} }
propertyHasChanged(originalValue: PropertiesModel<Shape>|null|undefined, currentValue: PropertiesModel<Shape>|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<Shape>|null|undefined, currentValue: SerializedModel<Shape>|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.
}
} }
/** /**

View file

@ -109,7 +109,7 @@ it("create and check state then serialize", () => {
}); });
it("deserialize then patch", () => { it("deserialize then save", () => {
const article = (new Article()).deserialize({ const article = (new Article()).deserialize({
id: 1, id: 1,
title: "this is a test", title: "this is a test",
@ -130,33 +130,35 @@ it("deserialize then patch", () => {
expect(article.isDirty()).toBeTruthy(); expect(article.isDirty()).toBeTruthy();
expect(article.patch()).toStrictEqual({ expect(article.save()).toStrictEqual({
id: 1, id: 1,
text: "Modified text.", text: "Modified text.",
}); });
}); });
it("patch with modified submodels", () => { it("save with modified submodels", () => {
const article = (new Article()).deserialize({ const article = (new Article()).deserialize({
id: 1, id: 1,
title: "this is a test", title: "this is a test",
authors: [ authors: [
{ name: "DOE", firstName: "John", email: "test@test.test", createdAt: (new Date()).toISOString(), active: true, }, { 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("1997-09-09")).toISOString(), active: false, }, { name: "TEST", firstName: "Another", email: "another@test.test", createdAt: (new Date()).toISOString(), active: false, },
], ],
text: "this is a long test.", text: "this is a long test.",
evaluation: "25.23", evaluation: "25.23",
tags: [ {name: "test"}, {name: "foo"} ], tags: [ {name: "test"}, {name: "foo"} ],
}); });
article.authors[0].name = "TEST"; article.authors = article.authors.map((author) => {
article.authors[1].createdAt.setMonth(9); author.name = "TEST";
return author;
});
expect(article.patch()).toStrictEqual({ expect(article.save()).toStrictEqual({
id: 1, id: 1,
authors: [ authors: [
{ name: "TEST" }, { name: "TEST", },
{ createdAt: (new Date("1997-10-09")).toISOString() }, //{ name: "TEST", firstName: "Another", email: "another@test.test" }, {}, //{ name: "TEST", firstName: "Another", email: "another@test.test" },
], ],
}); });
}); });