Add a simple object type and other improvements.

This commit is contained in:
Madeorsk 2024-09-28 17:02:40 +02:00
parent eb920a3d6d
commit bb5eed5162
Signed by: Madeorsk
GPG key ID: 677E51CA765BB79F
5 changed files with 98 additions and 3 deletions

View file

@ -28,7 +28,7 @@ export class Definition<SerializedType, SharkitekType>
* @param type - The model property type.
* @param options - Property definition options.
*/
export function SDefine<SerializedType, SharkitekType>(type: Type<SerializedType, SharkitekType>, options: DefinitionOptions<SerializedType, SharkitekType> = {})
export function SDefine<SerializedType, SharkitekType>(type: Type<SerializedType, SharkitekType>, options: DefinitionOptions<SerializedType, SharkitekType> = {}): Definition<SerializedType, SharkitekType>
{
return new Definition(type, options);
return new Definition<SerializedType, SharkitekType>(type, options);
}

View file

@ -6,7 +6,7 @@ import {Type} from "./Type";
export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<SerializedValueType[], SharkitekValueType[]>
{
/**
* Constructs a new array type of Sharkitek model property.
* Constructs a new array type of a Sharkitek model property.
* @param valueType - Type of the array values.
*/
constructor(protected valueType: Type<SerializedValueType, SharkitekValueType>)

View file

@ -0,0 +1,77 @@
import {Type} from "./Type";
import {Definition} from "../Definition";
/**
* Type of a simple object.
*/
export class ObjectType<Keys extends symbol|string> extends Type<Record<Keys, any>, Record<Keys, any>>
{
/**
* Constructs a new object type of a Sharkitek model property.
* @param fieldsTypes Object fields types.
*/
constructor(protected fieldsTypes: Record<Keys, Definition<unknown, unknown>>)
{
super();
}
deserialize(value: Record<Keys, any>): Record<Keys, any>
{
if (value === undefined) return undefined;
if (value === null) return null;
return Object.fromEntries(
// For each defined field, deserialize its value according to its type.
(Object.entries(this.fieldsTypes) as [Keys, Definition<any, any>][]).map(([fieldName, fieldDefinition]) => (
// Return an entry with the current field name and the deserialized value.
[fieldName, fieldDefinition.type.deserialize(value[fieldName])]
))
) as Record<Keys, any>;
}
serialize(value: Record<Keys, any>): Record<Keys, any>
{
if (value === undefined) return undefined;
if (value === null) return null;
return Object.fromEntries(
// For each defined field, serialize its value according to its type.
(Object.entries(this.fieldsTypes) as [Keys, Definition<any, any>][]).map(([fieldName, fieldDefinition]) => (
// Return an entry with the current field name and the serialized value.
[fieldName, fieldDefinition.type.serialize(value[fieldName])]
))
) as Record<Keys, any>;
}
serializeDiff(value: Record<Keys, any>): Record<Keys, any>
{
if (value === undefined) return undefined;
if (value === null) return null;
return Object.fromEntries(
// For each defined field, serialize its diff value according to its type.
(Object.entries(this.fieldsTypes) as [Keys, Definition<any, any>][]).map(([fieldName, fieldDefinition]) => (
// Return an entry with the current field name and the serialized diff value.
[fieldName, fieldDefinition.type.serializeDiff(value[fieldName])]
))
) as Record<Keys, any>;
}
resetDiff(value: Record<Keys, any>): void
{
// For each field, reset its diff.
(Object.entries(this.fieldsTypes) as [Keys, Definition<any, any>][]).forEach(([fieldName, fieldDefinition]) => {
// Reset diff of the current field.
fieldDefinition.type.resetDiff(value[fieldName]);
});
}
}
/**
* Type of a simple object.
* @param fieldsTypes Object fields types.
*/
export function SObject<Keys extends symbol|string>(fieldsTypes: Record<Keys, Definition<unknown, unknown>>): ObjectType<Keys>
{
return new ObjectType<Keys>(fieldsTypes);
}

View file

@ -10,4 +10,5 @@ export * from "./Model/Types/DateType";
export * from "./Model/Types/DecimalType";
export * from "./Model/Types/ModelType";
export * from "./Model/Types/NumericType";
export * from "./Model/Types/ObjectType";
export * from "./Model/Types/StringType";

View file

@ -10,6 +10,7 @@ import {
ModelDefinition,
SDefine, ModelIdentifier
} from "../src";
import {SObject} from "../src/Model/Types/ObjectType";
/**
* Another test model.
@ -54,6 +55,9 @@ class Article extends Model<Article>
authors: Author[] = [];
text: string;
evaluation: number;
tags: {
name: string;
}[];
protected SIdentifier(): ModelIdentifier<Article>
{
@ -68,6 +72,11 @@ class Article extends Model<Article>
authors: SDefine(SArray(SModel(Author))),
text: SDefine(SString),
evaluation: SDefine(SDecimal),
tags: SDefine(SArray(
SObject({
name: SDefine(SString),
})
)),
};
}
}
@ -82,6 +91,7 @@ it("deserialize", () => {
],
text: "this is a long test.",
evaluation: "25.23",
tags: [ {name: "test"}, {name: "foo"} ],
}).serialize()).toStrictEqual({
id: 1,
title: "this is a test",
@ -91,6 +101,7 @@ it("deserialize", () => {
],
text: "this is a long test.",
evaluation: "25.23",
tags: [ {name: "test"}, {name: "foo"} ],
});
});
@ -104,6 +115,9 @@ it("create and check state then serialize", () => {
];
article.text = "this is a long test.";
article.evaluation = 25.23;
article.tags = [];
article.tags.push({name: "test"});
article.tags.push({name: "foo"});
expect(article.isNew()).toBeTruthy();
expect(article.getIdentifier()).toStrictEqual(1);
@ -116,6 +130,7 @@ it("create and check state then serialize", () => {
],
text: "this is a long test.",
evaluation: "25.23",
tags: [ {name: "test"}, {name: "foo"} ],
});
});
@ -130,6 +145,7 @@ it("deserialize then save", () => {
],
text: "this is a long test.",
evaluation: "25.23",
tags: [ {name: "test"}, {name: "foo"} ],
});
expect(article.isNew()).toBeFalsy();
@ -156,6 +172,7 @@ it("save with modified submodels", () => {
],
text: "this is a long test.",
evaluation: "25.23",
tags: [ {name: "test"}, {name: "foo"} ],
});
article.authors = article.authors.map((author) => {