167 lines
2.6 KiB
Markdown
167 lines
2.6 KiB
Markdown
# Examples
|
|
|
|
This chapter combines Decodal's main constructs in complete examples.
|
|
|
|
## Basic configuration schema
|
|
|
|
```dcdl
|
|
Host = String;
|
|
|
|
Port = Int & >= 1 & <= 65535;
|
|
NarrowedPort = Port & > 443;
|
|
|
|
MyConfig = {
|
|
host = Host;
|
|
port = NarrowedPort default 8080;
|
|
feature_hoge = {
|
|
enable = Bool default true;
|
|
fuga = Int default 10;
|
|
};
|
|
};
|
|
|
|
NewConfig = MyConfig & {
|
|
host = "127.0.0.1";
|
|
port = 8000;
|
|
};
|
|
|
|
disabled_config = NewConfig & {
|
|
feature_hoge.enable = false;
|
|
};
|
|
|
|
enabled_config = NewConfig;
|
|
```
|
|
|
|
## Array schema
|
|
|
|
```dcdl
|
|
Services = [...{
|
|
name = String;
|
|
port = Int default 8080;
|
|
}];
|
|
|
|
[
|
|
{ name = "api"; },
|
|
{ name = "worker"; port = 9000; },
|
|
] as Services
|
|
```
|
|
|
|
An abstract array requires an element constraint.
|
|
In this example, `port` in the first element materializes to `8080`.
|
|
|
|
## Associative arrays and range refinement
|
|
|
|
```dcdl
|
|
Service = {
|
|
port = Int;
|
|
enabled = Bool default true;
|
|
};
|
|
|
|
services = {
|
|
api = { port = 8080; };
|
|
worker = { port = 8081; enabled = false; };
|
|
} as {...Service};
|
|
```
|
|
|
|
`api` and `worker` are arbitrary keys, and each value is refined to a range narrower than `Service`.
|
|
In the result of `as`, `api.enabled` remains abstract. Its default of `true` is selected only when the complete result is materialized.
|
|
|
|
## Functions and constraints
|
|
|
|
```dcdl
|
|
let
|
|
Port = Int & >= 1 & <= 65535;
|
|
add_offset = (base: Port, offset: Int) => base + offset;
|
|
in
|
|
add_offset(8000, 80)
|
|
```
|
|
|
|
Evaluation result:
|
|
|
|
```text
|
|
8080
|
|
```
|
|
|
|
## match
|
|
|
|
```dcdl
|
|
(
|
|
input_a: {
|
|
hoge = Int & >= 0;
|
|
},
|
|
input_b: {
|
|
fuga = 20;
|
|
}
|
|
) =>
|
|
let
|
|
inputs = {
|
|
a = input_a;
|
|
b = input_b;
|
|
};
|
|
in
|
|
{
|
|
foo = match inputs.a.hoge {
|
|
>= 20: {
|
|
value = 200;
|
|
};
|
|
>= 10: {
|
|
value = 100;
|
|
};
|
|
_: {
|
|
value = 300;
|
|
};
|
|
};
|
|
}
|
|
```
|
|
|
|
`match` evaluates arms in order, so place narrower conditions before broader ones.
|
|
|
|
## Deep patch
|
|
|
|
```dcdl
|
|
Base = {
|
|
feature_hoge = {
|
|
enable = Bool default true;
|
|
fuga = Int default 10;
|
|
};
|
|
};
|
|
|
|
Patched = Base // {
|
|
feature_hoge.enable = false;
|
|
};
|
|
```
|
|
|
|
`Patched` is equivalent to:
|
|
|
|
```dcdl
|
|
{
|
|
feature_hoge = {
|
|
enable = false;
|
|
fuga = Int default 10;
|
|
};
|
|
}
|
|
```
|
|
|
|
## Cyclic imports
|
|
|
|
```dcdl
|
|
# main.dcdl
|
|
{
|
|
schema = {
|
|
hoge = String;
|
|
};
|
|
|
|
result = (import "./func.dcdl")(schema);
|
|
}
|
|
```
|
|
|
|
```dcdl
|
|
# func.dcdl
|
|
(input: (import "./main.dcdl").schema) =>
|
|
{
|
|
# ...
|
|
}
|
|
```
|
|
|
|
`func.dcdl` imports `main.dcdl`, but it references only `main.schema`.
|
|
The cyclic import is valid as long as `main.schema` does not depend on `main.result`.
|