2.2 Decorators - Baumgaer/Game GitHub Wiki
The framework of this project uses several decorators to manage things while setting a property / attribute or instantiating classes. Furthermore this decorators invoke several hooks to extend the behavior or react on a behavior.
NOTE: All arguments which are given to a decorator which is assignable to a class field are inherited to the corresponding decorator in a subclass but can be overwritten by setting the corresponding argument!
The @baseConstructor()
decorator is necessary to use @attribute()
, @property()
and @watched()
decorator because it controls the life cycle of a class and avoids several executions of decorator functionality. This decorator also integrates the @ObjectType()
decorator from typeGraphQL for models (see https://typegraphql.ml/docs/introduction.html).
The decorator takes a few parameters to change the behavior.
The first one can be a name which is used in api and database calls instead of the original class name. If it is not a name, it could be an object with options or an index for construction parameters.
The second one is an Object with options OR an index for construction parameters and the last one can only be an index for construction parameters.
The name and the options have only effect if used on a model.
export interface IBaseConstructorOpts extends ObjectOptions {
/**
* Defines the name of the collection where a model is saved in.
* Only effects the behavior of a model.
*
* @default "default"
* @type {string}
* @memberof baseConstructorOpts
*/
collectionName?: string;
/**
* Defines the name of the database where a model is saved in.
* Only effects the behavior of a model.
*
* @default "default"
* @type {string}
* @memberof IBaseConstructorOpts
*/
databaseName?: string;
}
The @property()
decorator takes some parameters which have effect to all types of classes which uses the @baseConstructor()
decorator.
This decorator is not necessary to define a column in a database or attribute in an api call (see #2.2.3).
This decorator does not integrate another decorator currently, but it nevertheless checks the type of the new value of the property to be type save at runtime and to avoid weird bugs.
export interface IPropertyParams {
/**
* If true the value will be saved in localStorage until its deletion
* in localStorage or in redis until its deletion in redis.
* This is useful to relieve heavy databases.
*
* @default false Values will NOT be saved in cache
* @type {boolean}
*/
saveInLocalStorage?: boolean;
/**
* Decides wether to be able to set values null or undefined on a property.
* It is also used to generate a graphQL schema when used in an attribute.
*
* @default false
* @type {boolean}
* @memberof IPropertyParams
*/
nullable?: boolean | NullableListOptions;
/**
* Disables the type guard on runtime. The TypeGuard of the API stays active!
*
* @type {boolean}
* @memberof IPropertyParams
*/
disableTypeGuard?: boolean;
/**
* The name of the function which will be executed after basic type checking
* and before final determination. The function must return a corresponding
* error if something went wrong.
*
* @type {string}
* @memberof IPropertyParams
*/
onTypeCheck?: string;
/**
* Defines the name of the function which should be called when the type check fails.
* By default it is onPropertyNameTypeCheckFail
*
* @type {string}
* @memberof IPropertyParams
*/
onTypeCheckFail?: string;
/**
* Defines the name of the function which will be executed if all type
* checks are succeeded.
*
* @type {string}
* @memberof IPropertyParams
*/
onTypeCheckSuccess?: string;
}
The @attribute()
decorator takes some parameters to change the behavior of classes which use the @baseConstructor()
decorator. Some of them have only effect to models and others have effect on everything.
The first parameter is a funktion which returns the type of the attribute OR an object with some options.
For the type funktion see https://typegraphql.ml/docs/introduction.html.
This decorator integrates the @Field()
decorator of typeGraphQL.
This decorator also takes care about setting the corresponding DOMAttribute when the attribute is changed in some way and is used to define the database and api schema. If a field is not marked as an attribute in a model, it is impossible to use it in an api call or database call.
/**
* For "AdvancedOptions" see type-graph-qL for more informations.
* @link https://typegraphql.ml/docs/introduction.html
*/
export interface IAttributeParams extends IPropertyParams, AdvancedOptions {
/**
* If true the value will not be sent to server if value is set
* or save() will be called. Only effects the behavior of a model.
*
* @default false
* @type {boolean}
* @memberof IAttributeParams
*/
noServerInteraction?: boolean;
/**
* If true the value will not be sent to client if value is set
* or save() will be called. Only effects the behavior of a model.
*
* @default false
* @type {boolean}
* @memberof IAttributeParams
*/
noClientInteraction?: boolean;
/**
* If true the value will not be sent to p2p clients of current client if
* value is set or save() will be called. Only effects the behavior of a model.
*
* @default false
* @type {boolean}
* @memberof IAttributeParams
*/
noP2PInteraction?: boolean;
/**
* If true, value will be saved automatically and immediately.
* If it is a number > 0 the value will be saved automatically but
* debounced which means that the number is the time in milliseconds of
* save timeout. Only effects the behavior of a model.
*
* @default false
* @type {(boolean | number)}
* @memberof IAttributeParams
*/
autoSave?: boolean | number;
/**
* Defines wether to persist data in a Database like ArangoDB or IndexedDB.
* Only effects the behavior of a model.
*
* @type {boolean}
* @memberof IAttributeParams
*/
doNotPersist?: boolean;
}
This decorator can be used with or without @attribute()
or @property()
decorator. It reacts on any changes which are made in some way (changed the value directly, added something to an array or object, ...).
To react on this behavior, it is possible to define the corresponding names of the function which should be invoked by the decorator. If no funktion name is given, it tries to invoke a funktion like on<Name><Action>
in Which <Name>
means the name of the field and <Action>
means:
- Init
- Change
- Add
- Remove
A special case is Init
. If there is no function available for this behavior, the Change
function will be used.
export interface IWatchedParams {
/**
* The name of the function which should be called when the value will be initialized.
* Gets a parameter with initial value.
*
* @type {string}
* @memberof IWatchParams
*/
onInit?: string;
/**
* The name of the function which should be called when the value will be changed
* Gets a parameter with new value and if it is an object or array it gets
* additionally a parameter with the path which was changed.
*
* @type {string}
* @memberof IWatchParams
*/
onChange?: string;
/**
* The name of the function which should be called when a value will be added to an array or object.
* Gets a parameter with the added value and the path where it was added.
*
* @type {string}
* @memberof IWatchParams
*/
onAdd?: string;
/**
* The name of the function which should be called when a value will be removed from an array or object.
* Gets a parameter with the removed value and the path where it was removed.
*
* @type {string}
* @memberof IWatchParams
*/
onRemove?: string;
}
Decorators invokes some other hooks to extend their behavior depending on the side where they are used (client / server) or which class is given (model / some other)
-
The following hooks are invoked on class initialization and field assignments:
-
renderTemplate(): void
Called by
@baseConstructor()
when the current instance is a component and it's time to render the template. -
onConstructedCallback(): void
Called by
@baseConstructor()
after constructor has finished and all fields are assigned. -
setUpdateNamespacedStorage(key: string, newVal: any, nsProp?: string): void
Called by
@property()
and@attribute()
to set or update a local storage (could be localStorage on client or something else on server) -
getNamespacedStorage(key: string, nsProp?: string, forceNS?: string): any
Called by
@baseConstructor
,@property()
and@attribute()
to get the value out of a local storage (could be localStorage on client or something else on server).
-
-
The following hooks are invoked before a value is assigned to a field:
-
on<NameOfField>TypeCheck(value: any): Error | undefined or self defined
Called by
@property()
and@attribute()
to extend the type guard behavior while checking the type of the value but after basic type checking. Must return a corresponding error if something was wrong. -
on<NameOfField>TypeCheckSuccess(): void or self defined
Called by
@property()
and@attribute()
to react on successful checked values. -
on<NameOfField>TypeCheckFail(error: Error): void or self defined
Called by
@property()
and@attribute()
to react on failed type checks. Takes an error as parameter.
-
-
The following hooks are invoked after an assignment of a field:
-
on<NameOfField>Init(setValue: any): void or self defined
Called by
@watched()
to react on first assignment of a field. Takes the assigned value as a parameter. -
on<NameOfField>Change(oldValue: any): void or self defined
Called by
@watched()
to react on direct changes of a field. Takes the old value as a parameter. -
on<NameOfField>Add(addedValue: any, path: string): void or self defined
Called by
@watched()
to react on added things to an array. Takes the added thing as a parameter. -
on<NameOfField>Remove(removedValue: any, path: string) or self defined
Called by
@watched()
to react on removed things from an array. Takes the removed thing as a parameter.
-