Models

We define models as assets you interact with in a blockchain.
Every data structure should be a model, since it defines what are the minimum necessary properties to be present.
The package @worldsibu/convector-core-model
contains the necessary code to create models. Here's an example of one:
Notice we're extending ConvectorModel
. This class is full of rich methods you can use to manipulate the data.
There are multiple decorators you can use to model the data:
@ReadOnly()
- used when you want a property to be set once and then sealed to modifications@Required()
- used when you want the property to be ensured there will be a value@Default(val | () => val)
- used when you want to provide a default value before saving the data to the blockchain if there was no value provided@Required(Schema|Model)
- used to validate the property to conform a format
Here's a more complex example with nested objects and arrays
Usage
To create a base model file through Convector CLI run.
conv generate model <NAME-OF-MODEL>
Then you can edit it and adapt it as you need.
More advanced
The children classes can be used in 1 of 3 ways:
1. As an model query
or
2. As a param constructor and validator
3. As a container to start filling the model
API
Models are based on ConvectorModel<T>
, and it provides some basic static methods to use on models.
Querying the chaincode
Some static methods are present for you to query the chaincode storage. All these methods are subject to the storage
capabilities, for example, using storage-couchdb
you will be able to query the database in a more fashion way, even using views.
Basic properties
All models are required to have an id
and a type
field. The declaration of both can be omitted if wanted, but both of them must have a value. If you pass a string as the only param while instantiating a model, it will be used as the ID of that model.
Base methods
- To fetch the model content from the ledger and load the data into a model use
async myModel.fetch()
, the ID must have been set before this - To create or update a whole model in the blockchain you must use
async myModel.save()
- To update a portion of an existing model in the blockchain you must use
async myModel.update({ changes })
- To delete the model content in the blockchain you must use
async myModel.delete()
however, notice that a delete in blockchain terms, is just removing the current value from the state, but the historical data will still be there and cannot be removed - To clone a model you can use
myModel.clone()
- To convert a model to json you can do
JSON.stringify(myModel)
ormyModel.toJSON()
- To get the historical changes of a model you can do
myModel.history()
. This will return an array of objects containing thetxId
, thetimestamp
, and thevalue
through the time.
FlatConvectorModel
The ConvectorModel
type is pretty convenient as it enhances your code by accepting decorators for example (which auto-generate validations for you). But a class extending the ConvectorModel
type will also have multiple functions you may not want in your properties inside of model, for example .save()
.getOne()
and so on. That would be confusing for your code base and your team.
Sometimes you need to add a nested property inside of your object where the nested property won't exist by itself (it won't be saved or queried separately from the parent object). But having decorators is quite useful. So to have both? The solution to such scenario is adding the property as a FlatConvectorModel
, with this you will keep the ability to add decorators but it won't drag all the functions a regular ConvectorModel
brings.
In your code, this would look like this:
With this, validations will be propagated through the child objects.
Lazy loading
Some complex scenarios may need you to have circular dependencies, so how can we handle this scenario with such dynamic validations? There's a new property since 1.3 in which you can use `yup.lazy` to avoid circular dependencies issues.
Inheritance
Inheritance is another hot feature enabled after 1.3. Inheriting object types is required in complex scenarios but one may expect that even validations may be inherited, right? It's possible to achieve this in this way: