-
-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: new core data model #530
Merged
jonaslagoni
merged 19 commits into
asyncapi:next
from
jonaslagoni:feature/prepare_for_new_internal_model
Feb 28, 2022
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
3ec9ddb
Added initial take on setup.
jonaslagoni ada7efe
Added extra docs
jonaslagoni 3300b94
Added extra docs
jonaslagoni efe4ef2
Updated tables
jonaslagoni c4fd2df
Updated docs
jonaslagoni 3afcdda
Ignore specific example test
jonaslagoni 9965bad
Updated descriptions
jonaslagoni 57b56a4
Change
jonaslagoni 238cf3d
Changed description to meta model
jonaslagoni af74a02
Adapted the documentation
jonaslagoni 82db2a3
Added new images
jonaslagoni ec455ec
Updated code
jonaslagoni ab9e31e
Fixed testing
jonaslagoni 194b2e7
updated tables
jonaslagoni aa93ee4
Added missing changes
jonaslagoni a4480d4
fixed example
jonaslagoni 38de302
Added next branch release config
jonaslagoni 2769d6f
Update wordings
jonaslagoni 1bfcb37
Merge branch 'next' into feature/prepare_for_new_internal_model
jonaslagoni File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# The Process | ||
|
||
In order to generate data models from all kinds of inputs, we need a common structure for how we interact with one. That structure is called `MetaModel` often referred to as `Modelina Meta Model`, `Raw Meta Model`, or `MMM`. And there are two parts to it, there is the **meta model** and then the **constrained meta model**. | ||
|
||
# The Meta Model | ||
The **meta model** is what inputs (now and in the future) such as Protobuf, JSON Schema, JSON Type Definition, GraphQL types, are gonna be converted into. | ||
|
||
These are the meta models and their meaning: | ||
- **ArrayModel** is an unordered collection of a specific **MetaModel**. | ||
- **TupleModel** is an ordered collection of **MetaModel**s. | ||
- **EnumModel** is group of constants. | ||
- **UnionModel** represent that the model can be either/or other **MetaModel**s. | ||
- **ObjectModel** is a structure, that can be generated to class/interface/struct, etc, depending on the output language | ||
- **DictionaryModel** is a map/dictionary of key/value **MetaModel**s. | ||
- **ReferencedModel** is primarily used for when models should be split up ([see the splitting of meta models](#the-splitting-of-data-models)) and referenced, or it could be an external reference to an external entity. | ||
- **BooleanModel** represent boolean values. | ||
- **IntegerModel** represent natural numbers. | ||
- **FloatModel** represent floating-point numbers. | ||
- **StringModel** represent string values. | ||
- **AnyModel** represent generic values that cannot otherwise be represented by one of the other models. | ||
|
||
<p align="center"> | ||
<img src="./img/MetaModel.png" /> | ||
</p> | ||
|
||
|
||
## The Constrained Meta Model | ||
|
||
Before the **meta models**s reaches the generator, it needs to be `constrained` to the output. | ||
|
||
For example, constraining the **EnumModel** in Java means taking the raw enum key (for the **meta model** there are no constrains to what values may be used) such as `something% something` and convert it to a compliant (to the output) enum key that can be accessed directly, without having to call external libraries to find out of the result. | ||
|
||
This means that if you accessed `EnumValueModel.key` you would get `something% something`, and with the Java constrained variant `ConstrainedEnumValueModel.key` you get (example) `SOMETHING_PERCENT_SOMETHING`. | ||
|
||
How and what are constrained? | ||
|
||
The answer to this question is not straightforward, cause each language has unique constraints that the meta models much adhere to. This is TBD. | ||
|
||
<p align="center"> | ||
<img src="./img/ConstrainedMetaModel.png" /> | ||
</p> | ||
|
||
|
||
## The Basics | ||
|
||
Inputs generally don't have the faintest idea about the constraints of an output and it is therefore the **meta model** does not have any constraints, and it is perfectly normal and expected to name your properties `my property`. | ||
|
||
Before the model reaches the generator, it gets transformed to a **constrained meta model**. Here it converts the raw **meta model** into only having valid values for the specific output. For example (and this accounts for almost all languages) you cannot render a property with the name `my property`, as they generally follow some kind of common naming format such as using camel case `myProperty` or pascal case `MyProperty`. | ||
|
||
This transformation happen in three stages. | ||
|
||
<p align="center"> | ||
<img src="./img/RenderingProcess.png" /> | ||
</p> | ||
|
||
1. Process the input and transform it into the meta model. See [The meta model](./the_meta_model.md) for more information. | ||
2. Split the meta model into separate models that are rendered separately. See [The splitting of meta models](#The-splitting-of-data-models) for more information. | ||
3. Constrain the meta models to the output language. See [The constrained meta model](#the-constrained-data-model) for more information. | ||
|
||
## The splitting of Meta Models | ||
Each generator requires a different splitting of the **meta model**s because it varies which should be rendered as is, and which need to be rendered separately. | ||
|
||
For example with the current TS generator, we split the following models: | ||
- **ObjectModel**, because we want to generate it into interfaces, or classes | ||
- **EnumModel**, because we want to generate a representation for enums | ||
|
||
For the Java generator, we split the following models: | ||
- **ObjectModel**, because we want to generate it into a Java Class | ||
- **EnumModel**, because we want to generate it into a Java Enum. | ||
- **TupleModel** (TS have these models natively supported, Java don't, so we need to generate alternatives) | ||
- **UnionModel** (TS have these models natively supported, Java don't, so we need to generate alternatives) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Meta model | ||
|
||
Using the internal meta model representation, you can create your own data models from scratch, and still utilize the generators full sweep of features. | ||
|
||
## How to run this example | ||
|
||
Run this example using: | ||
|
||
```sh | ||
npm i && npm run start | ||
``` | ||
|
||
If you are on Windows, use the `start:windows` script instead: | ||
|
||
```sh | ||
npm i && npm run start:windows | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); | ||
import {generate} from './index'; | ||
|
||
describe('Should be able to use generator with meta model', () => { | ||
afterAll(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
test('and should log expected output to console', async () => { | ||
await generate(); | ||
//Generate is called 2x, so even though we expect 1 model, we double it | ||
expect(spy.mock.calls.length).toEqual(2); | ||
expect(spy.mock.calls[1]).toMatchSnapshot(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { TypeScriptGenerator, ObjectModel, StringModel } from '../../src'; | ||
|
||
const generator = new TypeScriptGenerator(); | ||
const customModel = new ObjectModel(); | ||
const propertyModel = new StringModel(); | ||
customModel.addProperty('test property name', propertyModel); | ||
|
||
export async function generate() : Promise<void> { | ||
const models = await generator.generate(rootModel); | ||
for (const model of models) { | ||
console.log(model.result); | ||
} | ||
} | ||
generate(); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"config" : { "example_name" : "meta-model" }, | ||
"scripts": { | ||
"install": "cd ../.. && npm i", | ||
"start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", | ||
"start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", | ||
"test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", | ||
"test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand idea about that but maybe we should call it as
Language Meta Model
and then callJavaEnumModel
etc... I think that it will produce some confusion because in some languages it will be exactly constraint model, because some languages don't support enums/unions etc but some allow more freedom than others. What do you think?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe just
Language Model
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is that all outputs should by some means support all MetaModels in one capacity or another.
For example for unions, if they are not supported like in TS
string | number
we can always render them asany
or create wrapper classesclass unionT { stringProp: string, numberProp: string }
. It all comes down to the output it's possibilities, as well as what the user defines through options.The constrained variant only refers to the values within the models, i.e. property name/type, model name and type, enum values, and keys, that ensure they are properly formatted in correct syntax.
So to me language meta model makes less sense I think 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and ok this is more generic, so 👌🏼 then, thanks for explanation! However I wonder if we really need to call this
Constrained Meta
. Maybe if we have a Meta Model which is "basic" then Data Model might be a better name for it, as the "final" version for the language?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constrained, refers to the process the meta models go through, i.e. the contrainer (
TypeScriptConstrained
, etc).What would you change the naming of the process and model name to, to make it consistant? 🤔
Can you try elaborate a bit more why you think
constrain
does not encapsulate correctly what it does?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name may be but I am a man who thinks differently. To me constraint means that something is limited but in a validation/parsing way (probably too much JSON Scheme, hah 😄 ) and not in a language constraint way. I'm also not a fan of Java jargon to call it like
LanguageConstrainedMetaModel
, soConstrainedMetaModel
is ok but I'd prefer without Meta ->ConstrainedModel
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, okay yea, I see 😄 Is there a way we need to highlight this difference in the docs?
Regarding
ConstrainedModel
, the "problem" is that the constrained model, is of type meta model as it inherits the class 😅 Think that will create more confusion, even though it is a long name 🤔What if we keept it for now, and once we are ready to merge from
next
tomaster
we can evaluate it then if it makes sense or not?