Skip to content

Commit 0cf634c

Browse files
authored
Merge pull request #685 from jvalue/rfc20-table-schema-value-type
rfc(0020): table-schema-value-type
2 parents 32359c8 + 426f07e commit 0cf634c

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<!--
2+
SPDX-FileCopyrightText: 2025 Friedrich-Alexander-Universitat Erlangen-Nurnberg
3+
4+
SPDX-License-Identifier: AGPL-3.0-only
5+
-->
6+
7+
# RFC 0020: Value types as table schema
8+
9+
| | |
10+
|---|---|
11+
| Feature Tag | `table-schema-value-types` |
12+
| Status | `ACCEPTED` |
13+
| Responsible | `jrentlez` |
14+
<!--
15+
Status Overview:
16+
- DRAFT: The RFC is not ready for a review and currently under change. Feel free to already ask for feedback on the structure and contents at this stage.
17+
- DISCUSSION: The RFC is open for discussion. Usually, we open a PR to trigger discussions.
18+
- ACCEPTED: The RFC was accepted. Create issues to prepare implementation of the RFC.
19+
- REJECTED: The RFC was rejected. If another revision emerges, switch to status DRAFT.
20+
-->
21+
22+
## Summary
23+
24+
Table schemata are now defined by value types. Sheet rows are parsed into table
25+
rows, using transforms and the following new concepts:
26+
- New `SheetRow` value type with a new cell access syntax
27+
- New syntax to create a table row with an expression
28+
29+
## Motivation
30+
31+
- Currently, table schemata cannot be reused.
32+
- The parsing of table rows is hard-coded.
33+
- A specific table schema is always parsed the same.
34+
35+
## Explanation
36+
37+
### Example
38+
39+
```jayvee
40+
valuetype Coordinate {
41+
x oftype integer;
42+
y oftype integer;
43+
}
44+
45+
transform ParseCoordinate {
46+
from row oftype SheetRow;
47+
to coord oftype Coordinate;
48+
49+
coord: {
50+
x: asInteger row["x"],
51+
y: asInteger row[2],
52+
};
53+
}
54+
55+
block CoordinateTable oftype TableInterpreter {
56+
columns: Coordinate;
57+
rowParsedWith: ParseCoordinate;
58+
}
59+
```
60+
The table output by `CoordinateTable` has two columns `x` and `y`, both
61+
containing integer values.
62+
63+
### Table schemata defined by value types
64+
65+
From now on, value types are used to define a table schema, each property
66+
defining a column.
67+
68+
### Parsing sheet rows into table rows
69+
70+
Parsing sheet rows is done explicitly by the user, inside a transform, with some
71+
additional restrictions:
72+
- only one input of type `SheetRow`.
73+
- only one output with the same value type as in `<block>`'s `columns` property.
74+
- must create a row with the row-creation syntax
75+
76+
#### New value type `SheetRow`
77+
78+
`SheetRow` is a new builtin value type only available in transforms that are
79+
used to parse rows.
80+
Values of type `SheetRow` can be indexed using brackets:
81+
- `row[<integer>]`: evaluates to the cell with index `<integer>`
82+
- `row[<string>]`: evaluates to the cell in column `<string>`
83+
84+
#### New row-creation syntax
85+
86+
The row-creation syntax follows this pattern (inspired by the JavaScript object
87+
syntax):
88+
```jayvee
89+
{
90+
<value type property>: <expression>,
91+
// ...
92+
}
93+
```
94+
95+
### Constraint handling
96+
97+
Constraints are validated after every change to a value within the table. For
98+
example:
99+
100+
```jayvee
101+
valuetype Coordinate {
102+
x oftype integer;
103+
y oftype integer;
104+
105+
constraint inFirstQuadrant: x >= 0 && y >= 0;
106+
}
107+
108+
block CoordinateTable oftype TableInterpreter {
109+
columns: Coordinate;
110+
rowParsedWith: /* ... */;
111+
}
112+
113+
transform invert {
114+
from n oftype integer;
115+
to inverted oftype integer;
116+
117+
inverted: -n;
118+
}
119+
120+
block Inverter oftype TableTransformer {
121+
inputColumns: ["x"];
122+
outputColumn: "x";
123+
uses: invert;
124+
}
125+
```
126+
127+
All values of column `x` would now be invalid because of the `inFirstQuadrant`
128+
constraints.
129+
130+
If `Inverter` would create a new column `minus_x` instead of overwriting `x`,
131+
then the values of `minus_x` would be valid.
132+
133+
### Nested value types
134+
135+
Using nested value types as table schema is allowed, but the resulting table
136+
represents a flattened variant of the nested type. The following code:
137+
```jayvee
138+
valuetype Coordinate {
139+
x oftype integer;
140+
y oftype integer;
141+
}
142+
valuetype Circle {
143+
center oftype Coordinate;
144+
radius oftype integer;
145+
}
146+
147+
transform ParseCircle {
148+
from row oftype SheetRow;
149+
to circle oftype Circle;
150+
151+
circle: {
152+
center: { x: asInteger row["x"], y: asInteger row["y"]},
153+
radius: asInteger row["r"],
154+
};
155+
}
156+
157+
block CircleTable oftype TableInterpreter {
158+
columns: Circle;
159+
rowParsedWith: ParseCircle;
160+
}
161+
```
162+
results in a table with three columns, `x`, `y` and `radius` all of type
163+
integer.
164+
165+
## Drawbacks
166+
167+
- Column names in tables must match the ID regex (e.g. no spaces).
168+
169+
## Alternatives
170+
171+
- There are different approaches to handling the nested value types:
172+
- Forbid using nested value types as table schema definitions
173+
- Save nested value types as dictionaries and serialize to JSON when writing
174+
to a database
175+
176+
## Possible Future Changes/Enhancements
177+
178+
- Use foreign keys to represent nested value types when writing to a database.
179+
- Allow inlining the transform and value type definitions into the
180+
TableInterpreter definition

0 commit comments

Comments
 (0)