Basic Tutorial (TypeScript)
This tutorial introduces how CBOT can be used to utilize TypeScript to create a proper Typed Model which is the intended use case for the protocol. For basic usage and introduction refer to the JavaScript -tutorial first.
Installation
npm i @sisujs/meta-cbot
Typed Example: Library
This example employs the same concepts as the untyped one but with actual types.
Because TypeScript type system does not exist in runtime, a separate meta-model needs to be created to retain that information.
Namespace
The first step is to create a namespace. This namespace does not correspond in any way to TypeScript namespaces, but it is an important tool for categorizing the Meta-model into usable groups.
Namespace is created as follows:
import { Meta, Namespace, Value } from '@sisujs/common';
const NS = Namespace.of('library').init();
The init() function ensures that this is the first time Namespace for the name
is declared thus preventing namespace pollution.
Typed Model
Then model is created as follows:
@NS.class('Author')
class Author {
@Value.string()
name: string
@(Value.of(Temporal.PlainDate))
birthdate: Temporal.PlainDate
}
@NS.class('Book')
class Book {
@Value.string()
title: string
@Value.string()
isbn: string
@(Value.of(Author))
author: Author
@Value.int32()
publicationYear: number
@Value.number()
rating: number
}
@NS.class('Catalog')
class Catalog {
@Value.string()
genre: string
@(Value.array().of(Book))
books: Book[]
@(Value.set().of(Author))
authors: Set<Author>
}
NS.seal([
Author,
Book,
Catalog
]);
What can be observed here is that classes and all their properties require a corresponding decorator that duplicates the intent for using the meta-model. It is also possible to have (transient) properties without a decorator, and these will not be included in the model.
Also, I used a int32 as the value-type for publicationYear. Although
JavaScript itself does not support integers the protocol does.
The last thing is to call seal() function for all declared types, which
prevents adding further declarations.
The next step is to create the values. There are two possibilites two create new objects through the model.
Creating Objects
Manual Creation
Creating object manually happens as expected:
const isaac = new Author();
isaac.name = "Isaac Asimov";
isaac.birthdate = Temporal.PlainDate.from('1920-01-02');
Using Meta-Model
It is also possible to use the meta-model itself to create a proper object tree with partial templates and plain objects in following way:
const foundation = Meta.of(Book, {
title: "Foundation",
isbn: "978-0-394-51330-7",
publicationYear: 1951,
author: isaac,
rating: 5.6
});
const iRobot = Meta.of(Book, {
title: "I, Robot",
isbn: "978-0-394-51331-4",
publicationYear: 1950,
author: isaac
});
const catalog = [
Meta.of(Catalog, {
genre: "Science Fiction",
books: [foundation, iRobot],
authors: new Set([isaac])
})
];
Cbot instance
Next a proper Cbot-instance is created as follows:
const cbot = Cbot.getInstance({
namespaces: [NS],
temporalApiEnabled: true
});
Instead of adding a staticKeys-parameter, I've added two other options
to it.
First is the namespaces which adds the namespaces I am interested in. This
illustrates why namespacing is important. You may have types for multiple
purposes, and you may not want to expose them all publicly. In such cases, a
different namespace can be used for the private types.
The other option is temporalApiEnabled which adds the ability to use Temporal API if it is available in the environment.
Usage
Next we can serialize and deserialize a catalog as expected:
const msg = cbot.serialize(catalog);
const deserialized:Catalog = cbot.deserialize(msg);
console.log("Is correct type: " + (deserialized instanceof Catalog));