Add models extension system.
This commit is contained in:
parent
576338fa62
commit
4648fd38e8
5 changed files with 190 additions and 133 deletions
|
@ -19,7 +19,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="Version 3.0.2" src="https://img.shields.io/badge/version-3.0.2-blue" />
|
<img alt="Version 3.1.0" src="https://img.shields.io/badge/version-3.1.0-blue" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sharkitek/core",
|
"name": "@sharkitek/core",
|
||||||
"version": "3.0.2",
|
"version": "3.1.0",
|
||||||
"description": "TypeScript library for well-designed model architectures.",
|
"description": "TypeScript library for well-designed model architectures.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"deserialization",
|
"deserialization",
|
||||||
|
|
|
@ -34,10 +34,20 @@ export type SerializedModel<Shape extends ModelShape> = {
|
||||||
*/
|
*/
|
||||||
export type Model<Shape extends ModelShape, IdentifierType = unknown> = ModelDefinition<Shape, IdentifierType> & PropertiesModel<Shape>;
|
export type Model<Shape extends ModelShape, IdentifierType = unknown> = ModelDefinition<Shape, IdentifierType> & PropertiesModel<Shape>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the extends function of model classes.
|
||||||
|
*/
|
||||||
|
export type ExtendsFunctionType<ModelType extends Model<Shape, IdentifierType<Shape, Identifier>>, Shape extends ModelShape, Identifier extends keyof Shape = any> =
|
||||||
|
<Extension extends object>(extension: ThisType<ModelType> & Extension) => ModelClass<ModelType & Extension, Shape, Identifier>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of a model class.
|
* Type of a model class.
|
||||||
*/
|
*/
|
||||||
export type ModelClass<Shape extends ModelShape, Identifier extends keyof Shape = any> = ConstructorOf<Model<Shape, IdentifierType<Shape, Identifier>>>;
|
export type ModelClass<ModelType extends Model<Shape, IdentifierType<Shape, Identifier>>, Shape extends ModelShape, Identifier extends keyof Shape = any> = (
|
||||||
|
ConstructorOf<ModelType> & {
|
||||||
|
extends: ExtendsFunctionType<ModelType, Shape, Identifier>;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier type.
|
* Identifier type.
|
||||||
|
@ -96,12 +106,14 @@ export interface ModelDefinition<Shape extends ModelShape, IdentifierType, Model
|
||||||
export function model<ModelType extends Model<Shape, IdentifierType<Shape, Identifier>>, Shape extends ModelShape, Identifier extends keyof Shape = any>(
|
export function model<ModelType extends Model<Shape, IdentifierType<Shape, Identifier>>, Shape extends ModelShape, Identifier extends keyof Shape = any>(
|
||||||
shape: Shape,
|
shape: Shape,
|
||||||
identifier?: Identifier,
|
identifier?: Identifier,
|
||||||
): ConstructorOf<ModelType>
|
): ModelClass<ModelType, Shape, Identifier>
|
||||||
{
|
{
|
||||||
// Get shape entries.
|
// Get shape entries.
|
||||||
const shapeEntries = Object.entries(shape) as [keyof Shape, UnknownDefinition][];
|
const shapeEntries = Object.entries(shape) as [keyof Shape, UnknownDefinition][];
|
||||||
|
|
||||||
return class GenericModel implements ModelDefinition<Shape, IdentifierType<Shape, Identifier>, ModelType>
|
return withExtends(
|
||||||
|
// Initialize generic model class.
|
||||||
|
class GenericModel implements ModelDefinition<Shape, IdentifierType<Shape, Identifier>, ModelType>
|
||||||
{
|
{
|
||||||
constructor()
|
constructor()
|
||||||
{
|
{
|
||||||
|
@ -232,5 +244,38 @@ export function model<ModelType extends Model<Shape, IdentifierType<Shape, Ident
|
||||||
return diff; // Return the difference.
|
return diff; // Return the difference.
|
||||||
}
|
}
|
||||||
|
|
||||||
} as unknown as ConstructorOf<ModelType>;
|
} as unknown as ConstructorOf<ModelType>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any Sharkitek model.
|
||||||
|
*/
|
||||||
|
export type AnyModel = Model<any, any>;
|
||||||
|
/**
|
||||||
|
* Any Sharkitek model class.
|
||||||
|
*/
|
||||||
|
export type AnyModelClass = ModelClass<AnyModel, any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add extends function to a model class.
|
||||||
|
* @param genericModel The model class on which to add the extends function.
|
||||||
|
*/
|
||||||
|
function withExtends<ModelType extends Model<Shape, IdentifierType<Shape, Identifier>>, Shape extends ModelShape, Identifier extends keyof Shape = any>(
|
||||||
|
genericModel: ConstructorOf<ModelType>
|
||||||
|
): ModelClass<ModelType, Shape, Identifier>
|
||||||
|
{
|
||||||
|
return Object.assign(
|
||||||
|
genericModel,
|
||||||
|
{ // Extends function definition.
|
||||||
|
extends<Extension extends object>(extension: Extension): ModelClass<ModelType & Extension, Shape, Identifier>
|
||||||
|
{
|
||||||
|
// Clone the model class and add extends function.
|
||||||
|
const classClone = withExtends(class extends (genericModel as AnyModelClass) {} as AnyModelClass as ConstructorOf<ModelType & Extension>);
|
||||||
|
// Add extension to the model class prototype.
|
||||||
|
Object.assign(classClone.prototype, extension);
|
||||||
|
return classClone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) as AnyModelClass as ModelClass<ModelType, Shape, Identifier>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,11 @@ class Author extends s.model({
|
||||||
email: s.property.string(),
|
email: s.property.string(),
|
||||||
createdAt: s.property.date(),
|
createdAt: s.property.date(),
|
||||||
active: s.property.bool(),
|
active: s.property.bool(),
|
||||||
|
}).extends({
|
||||||
|
extension(): string
|
||||||
|
{
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
active: boolean = true;
|
active: boolean = true;
|
||||||
|
@ -157,3 +162,9 @@ it("save with modified submodels", () => {
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("test author extension", () => {
|
||||||
|
const author = new Author();
|
||||||
|
author.name = "test name";
|
||||||
|
expect(author.extension()).toStrictEqual("test name");
|
||||||
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
@ -24,6 +25,6 @@
|
||||||
"lib": [
|
"lib": [
|
||||||
"ESNext",
|
"ESNext",
|
||||||
"DOM"
|
"DOM"
|
||||||
],
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue