Derive a column's datatype in columnDatatype alone

This commit is contained in:
2026-09-28 11:15:09 +02:00
committed by Lillem4n
parent 86118e2710
commit b2ffac5317
4 changed files with 20 additions and 36 deletions
+17 -30
View File
@@ -82,8 +82,14 @@ func checkColumns(s nodeScope) error {
} }
} }
} }
if _, err := columnDatatype(column); err != nil { if len(items) == 0 {
return fmt.Errorf("%s: field %q: %w", path, name, err) return nil
}
first := itemDatatype(items[0])
for _, it := range items[1:] {
if d := itemDatatype(it); d != first {
return fmt.Errorf("%s: field %q: %w", path, name, disagreement(items[0], first, it, d))
}
} }
return nil return nil
} }
@@ -101,42 +107,23 @@ func checkColumns(s nodeScope) error {
}) })
} }
// columnDatatype is the datatype a column's items hold. They must agree, since a // columnDatatype is the datatype a column holds, which its first item decides: checkColumns refuses
// column holds one; a column only ever null is a string. // a column whose items disagree. A table's column, like one only ever null, has no item and is a string.
func columnDatatype(n node) (DataType, error) { func columnDatatype(n node) DataType {
items, _ := columnItems(n) items, _ := columnItems(n)
if len(items) == 0 { if len(items) == 0 {
return DataTypeString, nil return DataTypeString
} }
first := itemDatatype(items[0]) return itemDatatype(items[0])
for _, t := range items[1:] {
if d := itemDatatype(t); d != first {
return first, disagreement(items[0], first, t, d)
}
}
return first, nil
} }
// itemDatatype is the datatype a column item declares, else that of the column it is. // itemDatatype is the datatype a column item declares, else that of the column it reads.
func itemDatatype(t *template) DataType { func itemDatatype(t *template) DataType {
if t.datatype != DataTypeString { if t.datatype == DataTypeString && t.readsColumn != nil {
return columnDatatype(t.readsColumn.column)
}
return t.datatype return t.datatype
} }
return readDatatype(t)
}
// readDatatype is the datatype of the column t is, reading it by one reference alone; a string
// when t reads none.
func readDatatype(t *template) DataType {
if t.readsColumn == nil {
return DataTypeString
}
items, _ := columnItems(t.readsColumn.column)
if len(items) == 0 {
return DataTypeString
}
return itemDatatype(items[0]) // checkColumns refuses that column where its items disagree
}
// columnItems is a column's template items, its choices unwrapped, and whether one is null. // columnItems is a column's template items, its choices unwrapped, and whether one is null.
func columnItems(n node) (items []*template, nullable bool) { func columnItems(n node) (items []*template, nullable bool) {
+1 -2
View File
@@ -254,8 +254,7 @@ func recordOf(n node) (*template, []Column, error) {
} }
columns := make([]Column, len(names)) columns := make([]Column, len(names))
for i, name := range names { for i, name := range names {
datatype, _ := columnDatatype(t.fields[name]) // checkColumns refused items that disagree wherever DataType is read columns[i] = Column{Name: name, DataType: columnDatatype(t.fields[name])}
columns[i] = Column{Name: name, DataType: datatype}
} }
return t, columns, nil return t, columns, nil
} }
-2
View File
@@ -21,8 +21,6 @@ Self-sufficiency 5.6), every seat capped by Locality, and all nine naming
This round, in order: This round, in order:
- Derive a column's datatype in one place: `columnItems` yields nothing for a
`tableColumn`, and six callers re-derive it from items.
- Give `head`, `index`, `bound` and `draw` one meaning each, name `table.family` - Give `head`, `index`, `bound` and `draw` one meaning each, name `table.family`
for the root it returns, and replace the token kind bytes `'l'`, `'t'`, `'f'` and for the root it returns, and replace the token kind bytes `'l'`, `'t'`, `'f'` and
`'b'`, whose `'l'` means different things in `ftoken` and `formatToken`. `'b'`, whose `'l'` means different things in `ftoken` and `formatToken`.
+2 -2
View File
@@ -34,8 +34,8 @@ func (p *valueProof) checkDatatype(path string, n node) error {
if !ok || t.datatype == DataTypeString { if !ok || t.datatype == DataTypeString {
return nil return nil
} }
if d := readDatatype(t); d == t.datatype { if r := t.readsColumn; r != nil && columnDatatype(r.column) == t.datatype {
return fmt.Errorf(`%s: %s takes datatype %s from the column it reads; drop "datatype"`, path, t.format, d) return fmt.Errorf(`%s: %s takes datatype %s from the column it reads; drop "datatype"`, path, t.format, t.datatype)
} }
if reason := p.proveColumnItem(t).not[t.datatype]; reason != "" { if reason := p.proveColumnItem(t).not[t.datatype]; reason != "" {
return fmt.Errorf("%s: datatype %s: %s", path, t.datatype, reason) return fmt.Errorf("%s: datatype %s: %s", path, t.datatype, reason)