2.5 Models - Baumgaer/Game GitHub Wiki

A model in this project is not just a data structure with some functionality. It is mor a definition for the API and the database and it manages the communication between multiple components.

A model uses BDOs so you should read the project structure section before you go ahead.

import { baseConstructor, attribute, property } from '~bdo/utils/decorators';
import { BDOModel } from '~bdo/lib/BDOModel';
import { Int } from "type-graphql";

/**
 * This is the BDO part of a model. It should contain the most part of the
 * attributes which are used to define the schema of the collection in the
 * database and the API. Remember that a BDO is used on client side and server
 * side.
 */
export function BDOMyModelFactory<TBase extends Constructor<BDOModel>>(ctor: TBase) {

    /**
     * Because this is a BDO the class has to be abstract and this has to be
     * defined in the baseConstructor. The collectionName is necessary for the
     * database which corresponds to the collection where the model is stored in.
     * You also can define a description that is displayed in graphiQL and if the
     * model IMPLEMENTS (not extends) another abstract class this musst be
     * defined too. interfaces cant be used in a model because they are not
     * emitted on compilation.
     */
    @baseConstructor({ isAbstract: true, collectionName: "MyCollection" })
    abstract class BDOMyModel extends ctor {

        /**
         * This is an necessary attribute of type "Inventory". Types that are
         * not primitive types musst be defined inside the attribute because
         * typeannotations are not emitted on compile time. If this were a
         * primitive type you could omit the parameter for types.
         */
        @attribute(_type => Inventory) public inventory!: Inventory;

        /**
         * This is an optional attribute. When an attribute is optional this has
         * to be passed as an option parameter in the decorator. You also can
         * pass the same parameters into the attribute which are used in the
         * property decorator.
         */
        @attribute({ nullable: true }) public description?: string;

        /**
         * This is an optional attribute with a default value which is
         * overwritten for the API in the defaultValue parameter.
         * Also the name of the attribute is overwritten from names to
         * deprecatedNames with a reason which will be shown in graphiQL.
         * Because this is an array you must give the type in the parameters of
         * the attribute. Please note, that you have to use the wrapper type
         * String (capitalized S) instead of the primitive type.
         */
        @attribute(_type => [String], {
            nullable: true,
            defaultValue: ["first deprecated name", "second deprecated name"],
            name: "deprecatedNames",
            deprecationReason: "some reason here"
        }) public names?: string[] = ["first name", "second name"];

        /**
         * This is a watched attribute with type number. Because graphQL is
         * strongly typed you have to pass the corresponding type to the attribute.
         * In this case the type is INT (integer). This attribute will also
         * never be sent to the server.
         */
        @watched() @attribute(_type => Int, {
            noServerInteraction: true
        }) age = 26;

        /**
         * As in a component you have to define a constructor. See the components
         * tutorial at the constructor for more information.
         */
        constructor(_params?: ConstParams<BDOMyModel>) {
            super();
        }

        /**
         * Of course you can define methods as usually.
         */
        protected aMethodName() {
            // Some stuff here
        }

    }
    return BDOMyModel;
}

You also can define attributes in a none BDO section. On the server side they will just extend the the generated schema for graphQL and eventually rename fields in the document of the collection in the database. On the client side they will change the behavior of the localStorage or indexedDB corresponding to the functionality of graphQL.

Furthermore it is possible to use the property decorator. If this is used there is no database interaction or p2p interaction or something like that. It also is not present in the API.

For more information about the attribute decorator in a model, see https://typegraphql.ml/docs/introduction.html. You just have to keep in mind, that the ObjectType decorator of type-graphQL is integrated into the baseConstructor decorator and the Field decorator of type-graphQL is integrated in the attribute decorator.

When you have defined the BDO part of your model, you have to define the real model like this:

import { BDOMyModelFactory } from "~bdo/models/BDOMyModel";
import { ClientModel } from '~client/lib/ClientModel';
import { baseConstructor } from "~bdo/utils/decorators";

/**
 * here you can overwrite the defined collection name of the BDO part in case
 * the client or the server uses different collections.
 */
@baseConstructor({ collectionName: "Test" })
export class MyModel extends BDOMyModelFactory(ClientModel) {

    constructor(_params?: ConstParams<MyModel>) {
        super();
    }

    /**
     * just a method
     */
    public aMethod() {
        // Do some magic
    }
}
⚠️ **GitHub.com Fallback** ⚠️