package main
import (
"fmt""cuelang.org/go/cue""cuelang.org/go/cue/cuecontext""cuelang.org/go/cue/errors")
const val = `
i: int
s: string
t: [string]: string
_h: int
_h: "hidden"
#d: int
#d: "bar"
`funcmain() {
c := cuecontext.New()
v := c.CompileString(val)
// try out different validation schemes
printErr("loose error", loose(v))
printErr("every error", every(v))
printErr("strict error", strict(v))
fmt.Printf("\nvalue:\n%#v\n", v)
}
funcprintErr(prefix string, err error) {
if err !=nil {
msg := errors.Details(err, nil)
fmt.Printf("%s:\n%s\n", prefix, msg)
}
}
funcloose(v cue.Value) error {
return v.Validate(
// not final or concrete
cue.Concrete(false),
// check minimally
cue.Definitions(false),
cue.Hidden(false),
cue.Optional(false),
)
}
funcevery(v cue.Value) error {
return v.Validate(
// not final or concrete
cue.Concrete(false),
// check everything
cue.Definitions(true),
cue.Hidden(true),
cue.Optional(true),
)
}
funcstrict(v cue.Value) error {
return v.Validate(
// ensure final and concrete
cue.Final(),
cue.Concrete(true),
// check everything
cue.Definitions(true),
cue.Hidden(true),
cue.Optional(true),
)
}
go run validate.go
loose error:
#d: conflicting values int and "bar" (mismatched types int and string):
7:5
8:5
_h: conflicting values int and "hidden" (mismatched types int and string):
5:5
6:5
every error:
#d: conflicting values int and "bar" (mismatched types int and string):
7:5
8:5
_h: conflicting values int and "hidden" (mismatched types int and string):
5:5
6:5
strict error:
#d: conflicting values int and "bar" (mismatched types int and string):
7:5
8:5
_h: conflicting values int and "hidden" (mismatched types int and string):
5:5
6:5
value:
i: int
s: string
t: {
[string]: string
}
_h: _|_ // conflicting values int and "hidden" (mismatched types int and string)
#d: _|_ // conflicting values int and "bar" (mismatched types int and string)
package main
import (
"fmt""cuelang.org/go/cue""cuelang.org/go/cue/cuecontext""cuelang.org/go/cue/errors")
const schema = `
v: {
i: int
s: string
}
`const val = `
v: {
i: "hello"
s: 1
}
`funcmain() {
c := cuecontext.New()
s := c.CompileString(schema, cue.Filename("schema.cue"))
v := c.CompileString(val, cue.Filename("val.cue"))
// unify the schema and value
u := s.Unify(v)
// check for errors during unification
if u.Err() !=nil {
msg := errors.Details(u.Err(), nil)
fmt.Printf("Unify Error:\n%s\n", msg)
}
// To get all errors, we need to validate
err := u.Validate()
if err !=nil {
msg := errors.Details(err, nil)
fmt.Printf("Validate Error:\n%s\n", msg)
}
// print u
fmt.Printf("%#v\n", u)
}
go run unify.go
Unify Error:
v.i: conflicting values int and "hello" (mismatched types int and string):
schema.cue:3:5
val.cue:3:5
Validate Error:
v.i: conflicting values int and "hello" (mismatched types int and string):
schema.cue:3:5
val.cue:3:5
v.s: conflicting values string and 1 (mismatched types string and int):
schema.cue:4:5
val.cue:4:5
v: {
i: _|_ // conflicting values int and "hello" (mismatched types int and string)
s: _|_ // conflicting values string and 1 (mismatched types string and int)
}
Subsume 是一种在格的概念下比较两个 Value 的关系的强力工具。
Subsume 会告诉你一个 Value 是不是另一个的实例。换句话说,他检查一个 Value 是否完全向后兼容另一个。
下面的例子里,我们对每一对 Value 检查两个方向的容纳情况。
每一对的两个方向,期待的情况是一个方向通过而另一个失败。
subsume.go
package main
import (
"fmt""cuelang.org/go/cue""cuelang.org/go/cue/cuecontext""cuelang.org/go/cue/errors")
const schemaWithNumber = `
{
i: number
s: string
}
`const schemaWithInt = `
{
i: int
s: string
}
`const constraint = `
{
i: >10 // this will only be subsumed by number, not int
s: =~"^foo"
}
`const val = `
{
i: 100
s: "foobar"
}
`const constraintType = `
{
i: uint
s: string
}
`funcmain() {
ctx := cuecontext.New()
sn := ctx.CompileString(schemaWithNumber, cue.Filename("schema_number.cue"))
si := ctx.CompileString(schemaWithInt, cue.Filename("schema_int.cue"))
c := ctx.CompileString(constraint, cue.Filename("constraint.cue"))
v := ctx.CompileString(val, cue.Filename("val.cue"))
b := ctx.CompileString(constraintType, cue.Filename("bad.cue"))
// check subsumptions
printErr("sn > c", sn.Subsume(c))
printErr("c > sn", c.Subsume(sn))
printErr("sn > v", sn.Subsume(v))
printErr("v > sn", v.Subsume(sn))
// this seems not intuitive, we'll talk it later
printErr("si > c", si.Subsume(c))
printErr("c > si", c.Subsume(si))
printErr("si > v", si.Subsume(v))
printErr("v > si", v.Subsume(si))
printErr("s > b", si.Subsume(b))
printErr("b > v", b.Subsume(v))
}
funcprintErr(prefix string, err error) {
if err !=nil {
msg := errors.Details(err, nil)
fmt.Printf("%s:\n%s\n", prefix, msg)
}
}
go run subsume.go
c > sn:
field i not present in {i:number,s:string}:
schema_number.cue:2:1
missing field "i"
v > sn:
field i not present in {i:number,s:string}:
schema_number.cue:2:1
missing field "i"
si > c:
field i not present in {i:>10,s:=~"^foo"}:
constraint.cue:2:1
missing field "i"
c > si:
field i not present in {i:int,s:string}:
schema_int.cue:2:1
missing field "i"
v > si:
field i not present in {i:int,s:string}:
schema_int.cue:2:1
missing field "i"