Skip to content

Commit 91e2b6d

Browse files
committed
docs: fresh paint and restructuring for newer versions
1 parent b47f57b commit 91e2b6d

File tree

13 files changed

+300
-263
lines changed

13 files changed

+300
-263
lines changed

.github/workflows/mkdocs.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: ci
2+
on:
3+
push:
4+
branches:
5+
- main
6+
paths:
7+
- 'mkdocs.yml'
8+
- 'docs/**'
9+
permissions:
10+
contents: write
11+
jobs:
12+
deploy:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
- name: Configure Git Credentials
17+
run: |
18+
git config user.name github-actions[bot]
19+
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
20+
- uses: actions/setup-python@v5
21+
with:
22+
python-version: 3.x
23+
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
24+
- uses: actions/cache@v4
25+
with:
26+
key: mkdocs-material-${{ env.cache_id }}
27+
path: .cache
28+
restore-keys: |
29+
mkdocs-material-
30+
- run: pip install mkdocs-material
31+
- run: mkdocs gh-deploy --force

docs/advanced/annotations.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ All annotation validators are created by making the annotation class extend `Str
1616
implement `FieldValidator` or `ClassValidator`. When constructing the validation mode for the
1717
generated structure, the field annotations are collected and the individual validators are created.
1818

19-
## API Schema Visitor
20-
21-
Using the `APISchemaObjectMetaVisitor` interface, you can create a visitor that will be called
22-
when the api schema is generated for a structure.
23-
2419
## Converter Supplier
2520

2621
Using the `ConverterSupplyingVisitor` interface, you can create a converter supplying visitor that

docs/advanced/tree_converters.md

Lines changed: 0 additions & 85 deletions
This file was deleted.

docs/basics/converters.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Converters
2+
3+
Dog provides a number of built-in converters for common types. However, you may need to create your
4+
own converters for custom types. This section will explain how to create custom converters and how
5+
to register them in the `DogEngine`.
6+
7+
## Simple Converters
8+
9+
``` { .dart .annotate title="Example using the SimpleDogConverter" }
10+
class LatLng {
11+
final double lat;
12+
final double lng;
13+
14+
LatLng(this.lat, this.lng);
15+
16+
@override
17+
String toString() => "LatLng($lat, $lng)";
18+
}
19+
20+
@linkSerializer/*(1)!*/
21+
class LatLngConverter extends SimpleDogConverter<LatLng>/*(2)!*/ {
22+
LatLngConverter() : super(serialName: "LatLng");
23+
24+
@override
25+
LatLng deserialize(value, DogEngine engine) {
26+
var list = value as List;
27+
return LatLng(list[0], list[1]);
28+
}
29+
30+
@override
31+
serialize(LatLng value, DogEngine engine) {
32+
return [value.lat, value.lng];
33+
}
34+
}
35+
```
36+
37+
1. The `@linkSerializer` annotation is used to automatically register the converter in the `DogEngine`.
38+
2. The `SimpleDogConverter` class is a convenience class that implements `DogConverter` and provides
39+
both the NativeSerializerMode and the GraphSerializerMode. It also creates a synthetic structure for
40+
the converter type that uses the `serialName`.
41+
42+
In this example, we created a converter for the `LatLng` class. The converter is registered in the
43+
`DogEngine` using the `@linkSerializer` annotation. The 'SimpleDogConverter' base class is the easiest
44+
way to create a converter – it implements the `DogConverter` interface and automatically creates a native
45+
serialization mode and a synthetic structure.
46+
47+
??? info "Manual Registration"
48+
To manually register a converter in the `DogEngine`, you can use the `registerAutomatic` method to
49+
register converter and also link both the structure and it's associated type.
50+
51+
To **only** register the converter for a **specific type**, use `registerAssociatedConverter`.
52+
To **only** register a **structure**, use `registerStructure`.
53+
To **only** register a converter, **without associating** it with a type, use `registerShelvedConverter`.
54+
55+
56+
## Tree Converters
57+
Tree converters build a tree of converters based on a given `TypeTree`. In the newer versions of dogs, **most of the
58+
complex serialization is done using tree converters.**
59+
60+
Each node inside the tree represents a **single terminal or compound type**.
61+
Generally, all type trees consist of a base type (e.g. `int`, `String`, `List`, `Map`, etc.) and
62+
a list of type arguments. There are also some special types of type trees for specific use-cases:
63+
64+
- `QualifiedTypeTree` also contain a final combined type of the tree, which results in it being able to be fully
65+
cached once constructed.
66+
- `SyntheticTypeCapture` doesn't define a base type, but uses the **serial name** of a structure like a type,
67+
allowing dynamically generated structures to be used as if they had a backing type. To enable this, downstream
68+
type safety is not guaranteed and trying to access the captured type will return `dynamic`.
69+
- `UnsafeRuntimeTypeCapture` uses the **runtime type** of value as a simple version of a type tree. Has the same
70+
limitations as synthetic type captures.
71+
72+
To construct a converter tree converter, the engine invokes the converter creation **top-down**, starting with the
73+
first base type. If the type tree has type arguments, the base converter will most likely **resolve the type argument subtrees
74+
recursively**.
75+
76+
``` { .dart title="List Converter using createIterableFactory" }
77+
final myListFactory = TreeBaseConverterFactory.createIterableFactory<MyList>(
78+
wrap: <T>(Iterable<T> entries) => MyList(entries.toList()),
79+
unwrap: <T>(MyList value) => value,
80+
);
81+
```
82+
Iterable converters are the most basic and also the most common type of tree converters. They are
83+
easy to create and can be used to convert any type of iterable. The `wrap` and `unwrap` functions
84+
are used to convert the iterable to and from the tree's base type.
85+
86+
``` { .dart title="Registering a custom tree base factory" }
87+
dogs.registerTreeBaseFactory(
88+
TypeToken<MyConverterBaseType>(),
89+
myCustomConverterFactory
90+
);
91+
```
92+
93+
You can register a custom tree base factory using the `registerTreeBaseFactory` method of the `DogEngine`.
94+
95+
```{ .dart title="Map Converter using NTreeArgConverter" }
96+
final mapFactory = TreeBaseConverterFactory.createNargsFactory<Map>(
97+
nargs: 2, consume: <K, V>() => MapNTreeArgConverter<K, V>()
98+
);
99+
100+
class MapNTreeArgConverter<K,V> extends NTreeArgConverter<Map> {
101+
@override
102+
Map deserialize(value, DogEngine engine) {
103+
return (value as Map).map<K,V>((key, value) => MapEntry<K,V>(
104+
deserializeArg(key, 0, engine),
105+
deserializeArg(value, 1, engine),
106+
));
107+
}
108+
109+
@override
110+
serialize(Map value, DogEngine engine) {
111+
return value.map((key, value) => MapEntry(
112+
serializeArg(key, 0, engine),
113+
serializeArg(value, 1, engine),
114+
));
115+
}
116+
}
117+
```
118+
`NTreeArgConverters` are used to convert complex types that have a fixed number of type arguments.
119+
The consume method is used to expand the stored type arguments to usable generic type arguments
120+
which then need to be used to create a NTreeArgConverter. The `NTreeArgConverter` class provides
121+
the `deserializeArg` and `serializeArg` methods to convert generic items using the converter
122+
associated with the type argument at the given index.
123+
124+
``` { .dart title="Complex Container using NTreeArgConverter" }
125+
final containerFactory = TreeBaseConverterFactory.createNargsFactory<Container>(
126+
nargs: 3, consume: <A,B,C>() => ContainerConverter<A,B,C>(),
127+
);
128+
129+
class Container<A,B,C> {
130+
final A a;
131+
final B b;
132+
final C c;
133+
134+
Container(this.a, this.b, this.c);
135+
136+
String toString() => "Container<$A, $B, $C>($a, $b, $c)";
137+
}
138+
139+
class ContainerConverter<A,B,C> extends NTreeArgConverter<Container> {
140+
141+
@override
142+
Container deserialize(value, DogEngine engine) {
143+
return Container<A,B,C>(
144+
deserializeArg(value["a"], 0, engine),
145+
deserializeArg(value["b"], 1, engine),
146+
deserializeArg(value["c"], 2, engine),
147+
);
148+
}
149+
150+
@override
151+
serialize(Container value, DogEngine engine) {
152+
return {
153+
"a": serializeArg(value.a, 0, engine),
154+
"b": serializeArg(value.b, 1, engine),
155+
"c": serializeArg(value.c, 2, engine)
156+
};
157+
}
158+
}
159+
```
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 5. Polymorphism
1+
# Polymorphism
22
DOGs supports polymorphism on a per-field basis. This means that you can have a field with any type
33
you want, as long as all leaf types are serializable. If you want to use polymorphism, you need to
44
add the `@polymorphic` annotation - This is required so you don't accidentally use polymorphism
@@ -81,6 +81,4 @@ class Person {
8181
Person(this.name, this.attachment);
8282
}
8383
84-
```
85-
86-
[Continue Reading! :material-arrow-right:](/converters/){ .md-button .md-button--primary }
84+
```
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 3. Projection
1+
# Projection
22

33
You can project multiple objects and maps into a single object by using the `project` method.
44

@@ -31,4 +31,3 @@ var reduced = dogs.project<NameAndAge>(
3131
the engine can only infer the type for concrete classes. If you want to project collections or
3232
other non-concrete types, convert the object using `toNative()` first.
3333

34-
[Continue Reading! :material-arrow-right:](/validation/){ .md-button .md-button--primary }

0 commit comments

Comments
 (0)