CUE values have a number of methods that we can use
to inspect their contents, state, and location.
While we saw how to print the full value and its error state,
the functions here provide more granular details.
We will be using the following CUE file
for the examples in this section.
When you lookup a value, how do you know if it was found?
That is where Exists comes in.
IsConcrete can tell you if an atom field has data or is a terminal error.
For lists and structs, it will report true if they exist and not recurse to check subvalues.
When disjunctions and defaults are used…
exists.go
package main
import (
"fmt""os""cuelang.org/go/cue""cuelang.org/go/cue/cuecontext")
funcmain() {
c := cuecontext.New()
// read and compile value
d, _ := os.ReadFile("value.cue")
val := c.CompileBytes(d)
paths := []string{
"a",
"d.g",
"x.y",
}
for _, path :=range paths {
fmt.Printf("==== %s ====\n", path)
v := val.LookupPath(cue.ParsePath(path))
p := v.Path()
x := v.Exists()
c := v.IsConcrete()
fmt.Printf("%q %v %v\n%# v\n", p, x, c, v)
}
}
go run exists.go
==== a ====
"a" true true
b: "b"
c: "c"
e: int
==== d.g ====
"d.g" true false
_
==== x.y ====
"" false true
_|_ // field "x" not found
Use Validate to check complete values for concreteness.
Kind and IncompleteKind will tell you the underlying type of a value.
IncompleteKind is more granular and returns type info regarless of how complete a value is
(the names may seem a bit backwards).
kind.go
package main
import (
"fmt""os""cuelang.org/go/cue""cuelang.org/go/cue/cuecontext")
funcmain() {
c := cuecontext.New()
// read and compile value
d, _ := os.ReadFile("value.cue")
val := c.CompileBytes(d)
paths := []string{
"a",
"a.e",
"d.g",
"l",
"b",
"x.y",
}
for _, path :=range paths {
v := val.LookupPath(cue.ParsePath(path))
k := v.Kind()
i := v.IncompleteKind()
fmt.Printf("%q %v %v %v\n", path, k, i, v)
}
}
go run kind.go
"a" struct struct {
b: "b"
c: "c"
e: int
}
"a.e" _|_ int int
"d.g" _|_ _ _
"l" list list [1, 2, "y", "z"]
"b" bytes bytes 'abc123'
"x.y" _|_ _|_ _|_ // field "x" not found
You can also switch on the results of both functions.
Values have a number of functions for turning the abstract into the underlying type.
You will first want to know what type of value you are dealing with before trying to convert it.
conversions.go
package main
import (
"fmt""os""cuelang.org/go/cue""cuelang.org/go/cue/cuecontext")
funcmain() {
c := cuecontext.New()
// read and compile value
d, _ := os.ReadFile("value.cue")
val := c.CompileBytes(d)
var (
s string b []byte i int64 f float64 )
// read into Go basic types
s, _ = val.LookupPath(cue.ParsePath("a.b")).String()
b, _ = val.LookupPath(cue.ParsePath("b")).Bytes()
i, _ = val.LookupPath(cue.ParsePath("d.e")).Int64()
f, _ = val.LookupPath(cue.ParsePath("d.f")).Float64()
fmt.Println(s, b, i, f)
// an error
s, err := val.LookupPath(cue.ParsePath("a.e")).String()
if err !=nil {
fmt.Println(err)
}
}
go run conversions.go
b [97 98 99 49 50 51] 42 3.14
a.e: cannot use value int (type int) as string
Len
Len will tell you the length of a list or how many bytes are in a bytes.
length.go
package main
import (
"fmt""os""cuelang.org/go/cue""cuelang.org/go/cue/cuecontext")
funcmain() {
c := cuecontext.New()
// read and compile value
d, _ := os.ReadFile("value.cue")
val := c.CompileBytes(d)
paths := []string{
"a",
"d.e",
"d.g",
"l",
"b",
}
for _, path :=range paths {
fmt.Printf("==== %s ====\n", path)
v := val.LookupPath(cue.ParsePath(path))
p := v.Path()
k := v.IncompleteKind()
l := v.Len()
fmt.Printf("%q %v %v\n%# v\n", p, k, l, v)
}
}
go run length.go
==== a ====
"a" struct _|_ // len not supported for type struct
b: "b"
c: "c"
e: int
==== d.g ====
"d.g" _ _|_ // len not supported for type _|_
_
==== l ====
"l" list 4
[1, 2, "y", "z"]
==== b ====
"b" bytes 6
'abc123'