p1: /v2/scrape, /v1/fetch, auth, CLI, contract tests
Single Fetcher.Fetch on the Guard that holds DenyPrefixes. skipTlsVerification is ignored. No 502. keys add writes the secret only to --out. Release binary has no -test-allow-prefix.
This commit is contained in:
+942
@@ -0,0 +1,942 @@
|
||||
package gojq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Parse a query string, and returns the query struct.
|
||||
//
|
||||
// If parsing failed, it returns an error of type [*ParseError], which has
|
||||
// the byte offset and the invalid token. The byte offset is the scanned bytes
|
||||
// when the error occurred. The token is empty if the error occurred after
|
||||
// scanning the entire query string.
|
||||
func Parse(src string) (*Query, error) {
|
||||
l := newLexer(src)
|
||||
if yyParse(l) > 0 {
|
||||
return nil, l.err
|
||||
}
|
||||
return l.result, nil
|
||||
}
|
||||
|
||||
// Query represents the abstract syntax tree of a jq query.
|
||||
type Query struct {
|
||||
Meta *ConstObject
|
||||
Imports []*Import
|
||||
FuncDefs []*FuncDef
|
||||
Term *Term
|
||||
Left *Query
|
||||
Right *Query
|
||||
Patterns []*Pattern
|
||||
Op Operator
|
||||
}
|
||||
|
||||
// Run the query.
|
||||
//
|
||||
// It is safe to call this method in goroutines, to reuse a parsed [*Query].
|
||||
func (e *Query) Run(v any) Iter {
|
||||
return e.RunWithContext(context.Background(), v)
|
||||
}
|
||||
|
||||
// RunWithContext runs the query with context.
|
||||
func (e *Query) RunWithContext(ctx context.Context, v any) Iter {
|
||||
code, err := Compile(e)
|
||||
if err != nil {
|
||||
return NewIter(err)
|
||||
}
|
||||
return code.RunWithContext(ctx, v)
|
||||
}
|
||||
|
||||
func (e *Query) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Query) writeTo(s *strings.Builder) {
|
||||
if e.Meta != nil {
|
||||
s.WriteString("module ")
|
||||
e.Meta.writeTo(s)
|
||||
s.WriteString(";\n")
|
||||
}
|
||||
for _, im := range e.Imports {
|
||||
im.writeTo(s)
|
||||
}
|
||||
for _, fd := range e.FuncDefs {
|
||||
fd.writeTo(s)
|
||||
s.WriteByte(' ')
|
||||
}
|
||||
if e.Term != nil {
|
||||
e.Term.writeTo(s)
|
||||
} else if e.Right != nil {
|
||||
e.Left.writeTo(s)
|
||||
if e.Op != OpComma {
|
||||
s.WriteByte(' ')
|
||||
}
|
||||
for i, p := range e.Patterns {
|
||||
if i == 0 {
|
||||
s.WriteString("as ")
|
||||
} else {
|
||||
s.WriteString("?// ")
|
||||
}
|
||||
p.writeTo(s)
|
||||
s.WriteByte(' ')
|
||||
}
|
||||
s.WriteString(e.Op.String())
|
||||
s.WriteByte(' ')
|
||||
e.Right.writeTo(s)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Query) toIndexKey() any {
|
||||
if e.Term == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Term.toIndexKey()
|
||||
}
|
||||
|
||||
func (e *Query) toIndices(xs []any) []any {
|
||||
if e.Term == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Term.toIndices(xs)
|
||||
}
|
||||
|
||||
// Import ...
|
||||
type Import struct {
|
||||
ImportPath string
|
||||
ImportAlias string
|
||||
IncludePath string
|
||||
Meta *ConstObject
|
||||
}
|
||||
|
||||
func (e *Import) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Import) writeTo(s *strings.Builder) {
|
||||
if e.ImportPath != "" {
|
||||
s.WriteString("import ")
|
||||
jsonEncodeString(s, e.ImportPath)
|
||||
s.WriteString(" as ")
|
||||
s.WriteString(e.ImportAlias)
|
||||
} else {
|
||||
s.WriteString("include ")
|
||||
jsonEncodeString(s, e.IncludePath)
|
||||
}
|
||||
if e.Meta != nil {
|
||||
s.WriteByte(' ')
|
||||
e.Meta.writeTo(s)
|
||||
}
|
||||
s.WriteString(";\n")
|
||||
}
|
||||
|
||||
// FuncDef ...
|
||||
type FuncDef struct {
|
||||
Name string
|
||||
Args []string
|
||||
Body *Query
|
||||
}
|
||||
|
||||
func (e *FuncDef) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *FuncDef) writeTo(s *strings.Builder) {
|
||||
s.WriteString("def ")
|
||||
s.WriteString(e.Name)
|
||||
if len(e.Args) > 0 {
|
||||
s.WriteByte('(')
|
||||
for i, e := range e.Args {
|
||||
if i > 0 {
|
||||
s.WriteString("; ")
|
||||
}
|
||||
s.WriteString(e)
|
||||
}
|
||||
s.WriteByte(')')
|
||||
}
|
||||
s.WriteString(": ")
|
||||
e.Body.writeTo(s)
|
||||
s.WriteByte(';')
|
||||
}
|
||||
|
||||
// Term ...
|
||||
type Term struct {
|
||||
Type TermType
|
||||
Index *Index
|
||||
Func *Func
|
||||
Object *Object
|
||||
Array *Array
|
||||
Number string
|
||||
Unary *Unary
|
||||
Format string
|
||||
Str *String
|
||||
If *If
|
||||
Try *Try
|
||||
Reduce *Reduce
|
||||
Foreach *Foreach
|
||||
Label *Label
|
||||
Break string
|
||||
Query *Query
|
||||
SuffixList []*Suffix
|
||||
}
|
||||
|
||||
func (e *Term) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Term) writeTo(s *strings.Builder) {
|
||||
switch e.Type {
|
||||
case TermTypeIdentity:
|
||||
s.WriteByte('.')
|
||||
case TermTypeRecurse:
|
||||
s.WriteString("..")
|
||||
case TermTypeNull:
|
||||
s.WriteString("null")
|
||||
case TermTypeTrue:
|
||||
s.WriteString("true")
|
||||
case TermTypeFalse:
|
||||
s.WriteString("false")
|
||||
case TermTypeIndex:
|
||||
e.Index.writeTo(s)
|
||||
case TermTypeFunc:
|
||||
e.Func.writeTo(s)
|
||||
case TermTypeObject:
|
||||
e.Object.writeTo(s)
|
||||
case TermTypeArray:
|
||||
e.Array.writeTo(s)
|
||||
case TermTypeNumber:
|
||||
s.WriteString(e.Number)
|
||||
case TermTypeUnary:
|
||||
e.Unary.writeTo(s)
|
||||
case TermTypeFormat:
|
||||
s.WriteString(e.Format)
|
||||
if e.Str != nil {
|
||||
s.WriteByte(' ')
|
||||
e.Str.writeTo(s)
|
||||
}
|
||||
case TermTypeString:
|
||||
e.Str.writeTo(s)
|
||||
case TermTypeIf:
|
||||
e.If.writeTo(s)
|
||||
case TermTypeTry:
|
||||
e.Try.writeTo(s)
|
||||
case TermTypeReduce:
|
||||
e.Reduce.writeTo(s)
|
||||
case TermTypeForeach:
|
||||
e.Foreach.writeTo(s)
|
||||
case TermTypeLabel:
|
||||
e.Label.writeTo(s)
|
||||
case TermTypeBreak:
|
||||
s.WriteString("break ")
|
||||
s.WriteString(e.Break)
|
||||
case TermTypeQuery:
|
||||
s.WriteByte('(')
|
||||
e.Query.writeTo(s)
|
||||
s.WriteByte(')')
|
||||
}
|
||||
for _, e := range e.SuffixList {
|
||||
e.writeTo(s)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Term) toIndexKey() any {
|
||||
switch e.Type {
|
||||
case TermTypeNumber:
|
||||
return toNumber(e.Number)
|
||||
case TermTypeUnary:
|
||||
return e.Unary.toNumber()
|
||||
case TermTypeString:
|
||||
if e.Str.Queries == nil {
|
||||
return e.Str.Str
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Term) toIndices(xs []any) []any {
|
||||
switch e.Type {
|
||||
case TermTypeIndex:
|
||||
if xs = e.Index.toIndices(xs); xs == nil {
|
||||
return nil
|
||||
}
|
||||
case TermTypeQuery:
|
||||
if xs = e.Query.toIndices(xs); xs == nil {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
for _, s := range e.SuffixList {
|
||||
if xs = s.toIndices(xs); xs == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return xs
|
||||
}
|
||||
|
||||
func (e *Term) toNumber() any {
|
||||
if e.Type == TermTypeNumber {
|
||||
return toNumber(e.Number)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unary ...
|
||||
type Unary struct {
|
||||
Op Operator
|
||||
Term *Term
|
||||
}
|
||||
|
||||
func (e *Unary) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Unary) writeTo(s *strings.Builder) {
|
||||
s.WriteString(e.Op.String())
|
||||
e.Term.writeTo(s)
|
||||
}
|
||||
|
||||
func (e *Unary) toNumber() any {
|
||||
v := e.Term.toNumber()
|
||||
if v != nil && e.Op == OpSub {
|
||||
v = funcOpNegate(v)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Pattern ...
|
||||
type Pattern struct {
|
||||
Name string
|
||||
Array []*Pattern
|
||||
Object []*PatternObject
|
||||
}
|
||||
|
||||
func (e *Pattern) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Pattern) writeTo(s *strings.Builder) {
|
||||
if e.Name != "" {
|
||||
s.WriteString(e.Name)
|
||||
} else if len(e.Array) > 0 {
|
||||
s.WriteByte('[')
|
||||
for i, e := range e.Array {
|
||||
if i > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
e.writeTo(s)
|
||||
}
|
||||
s.WriteByte(']')
|
||||
} else if len(e.Object) > 0 {
|
||||
s.WriteByte('{')
|
||||
for i, e := range e.Object {
|
||||
if i > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
e.writeTo(s)
|
||||
}
|
||||
s.WriteByte('}')
|
||||
}
|
||||
}
|
||||
|
||||
// PatternObject ...
|
||||
type PatternObject struct {
|
||||
Key string
|
||||
KeyString *String
|
||||
KeyQuery *Query
|
||||
Val *Pattern
|
||||
}
|
||||
|
||||
func (e *PatternObject) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *PatternObject) writeTo(s *strings.Builder) {
|
||||
if e.Key != "" {
|
||||
s.WriteString(e.Key)
|
||||
} else if e.KeyString != nil {
|
||||
e.KeyString.writeTo(s)
|
||||
} else if e.KeyQuery != nil {
|
||||
s.WriteByte('(')
|
||||
e.KeyQuery.writeTo(s)
|
||||
s.WriteByte(')')
|
||||
}
|
||||
if e.Val != nil {
|
||||
s.WriteString(": ")
|
||||
e.Val.writeTo(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Index ...
|
||||
type Index struct {
|
||||
Name string
|
||||
Str *String
|
||||
Start *Query
|
||||
End *Query
|
||||
IsSlice bool
|
||||
}
|
||||
|
||||
func (e *Index) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Index) writeTo(s *strings.Builder) {
|
||||
if l := s.Len(); l > 0 {
|
||||
// ". .x" != "..x" and "0 .x" != "0.x"
|
||||
if c := s.String()[l-1]; c == '.' || '0' <= c && c <= '9' {
|
||||
s.WriteByte(' ')
|
||||
}
|
||||
}
|
||||
s.WriteByte('.')
|
||||
e.writeSuffixTo(s)
|
||||
}
|
||||
|
||||
func (e *Index) writeSuffixTo(s *strings.Builder) {
|
||||
if e.Name != "" {
|
||||
s.WriteString(e.Name)
|
||||
} else if e.Str != nil {
|
||||
e.Str.writeTo(s)
|
||||
} else {
|
||||
s.WriteByte('[')
|
||||
if e.IsSlice {
|
||||
if e.Start != nil {
|
||||
e.Start.writeTo(s)
|
||||
}
|
||||
s.WriteByte(':')
|
||||
if e.End != nil {
|
||||
e.End.writeTo(s)
|
||||
}
|
||||
} else {
|
||||
e.Start.writeTo(s)
|
||||
}
|
||||
s.WriteByte(']')
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Index) toIndexKey() any {
|
||||
if e.Name != "" {
|
||||
return e.Name
|
||||
} else if e.Str != nil {
|
||||
if e.Str.Queries == nil {
|
||||
return e.Str.Str
|
||||
}
|
||||
} else if !e.IsSlice {
|
||||
return e.Start.toIndexKey()
|
||||
} else {
|
||||
var start, end any
|
||||
ok := true
|
||||
if e.Start != nil {
|
||||
start = e.Start.toIndexKey()
|
||||
ok = start != nil
|
||||
}
|
||||
if e.End != nil && ok {
|
||||
end = e.End.toIndexKey()
|
||||
ok = end != nil
|
||||
}
|
||||
if ok {
|
||||
return map[string]any{"start": start, "end": end}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Index) toIndices(xs []any) []any {
|
||||
if k := e.toIndexKey(); k != nil {
|
||||
return append(xs, k)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Func ...
|
||||
type Func struct {
|
||||
Name string
|
||||
Args []*Query
|
||||
}
|
||||
|
||||
func (e *Func) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Func) writeTo(s *strings.Builder) {
|
||||
s.WriteString(e.Name)
|
||||
if len(e.Args) > 0 {
|
||||
s.WriteByte('(')
|
||||
for i, e := range e.Args {
|
||||
if i > 0 {
|
||||
s.WriteString("; ")
|
||||
}
|
||||
e.writeTo(s)
|
||||
}
|
||||
s.WriteByte(')')
|
||||
}
|
||||
}
|
||||
|
||||
// String ...
|
||||
type String struct {
|
||||
Str string
|
||||
Queries []*Query
|
||||
}
|
||||
|
||||
func (e *String) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *String) writeTo(s *strings.Builder) {
|
||||
if e.Queries == nil {
|
||||
jsonEncodeString(s, e.Str)
|
||||
return
|
||||
}
|
||||
s.WriteByte('"')
|
||||
for _, e := range e.Queries {
|
||||
if e.Term.Str == nil {
|
||||
s.WriteString(`\`)
|
||||
e.writeTo(s)
|
||||
} else {
|
||||
es := e.String()
|
||||
s.WriteString(es[1 : len(es)-1])
|
||||
}
|
||||
}
|
||||
s.WriteByte('"')
|
||||
}
|
||||
|
||||
// Object ...
|
||||
type Object struct {
|
||||
KeyVals []*ObjectKeyVal
|
||||
}
|
||||
|
||||
func (e *Object) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Object) writeTo(s *strings.Builder) {
|
||||
if len(e.KeyVals) == 0 {
|
||||
s.WriteString("{}")
|
||||
return
|
||||
}
|
||||
s.WriteString("{ ")
|
||||
for i, kv := range e.KeyVals {
|
||||
if i > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
kv.writeTo(s)
|
||||
}
|
||||
s.WriteString(" }")
|
||||
}
|
||||
|
||||
// ObjectKeyVal ...
|
||||
type ObjectKeyVal struct {
|
||||
Key string
|
||||
KeyString *String
|
||||
KeyQuery *Query
|
||||
Val *Query
|
||||
}
|
||||
|
||||
func (e *ObjectKeyVal) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *ObjectKeyVal) writeTo(s *strings.Builder) {
|
||||
if e.Key != "" {
|
||||
s.WriteString(e.Key)
|
||||
} else if e.KeyString != nil {
|
||||
e.KeyString.writeTo(s)
|
||||
} else if e.KeyQuery != nil {
|
||||
s.WriteByte('(')
|
||||
e.KeyQuery.writeTo(s)
|
||||
s.WriteByte(')')
|
||||
}
|
||||
if e.Val != nil {
|
||||
s.WriteString(": ")
|
||||
e.Val.writeTo(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Array ...
|
||||
type Array struct {
|
||||
Query *Query
|
||||
}
|
||||
|
||||
func (e *Array) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Array) writeTo(s *strings.Builder) {
|
||||
s.WriteByte('[')
|
||||
if e.Query != nil {
|
||||
e.Query.writeTo(s)
|
||||
}
|
||||
s.WriteByte(']')
|
||||
}
|
||||
|
||||
// Suffix ...
|
||||
type Suffix struct {
|
||||
Index *Index
|
||||
Iter bool
|
||||
Optional bool
|
||||
}
|
||||
|
||||
func (e *Suffix) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Suffix) writeTo(s *strings.Builder) {
|
||||
if e.Index != nil {
|
||||
if e.Index.Name != "" || e.Index.Str != nil {
|
||||
e.Index.writeTo(s)
|
||||
} else {
|
||||
e.Index.writeSuffixTo(s)
|
||||
}
|
||||
} else if e.Iter {
|
||||
s.WriteString("[]")
|
||||
} else if e.Optional {
|
||||
s.WriteByte('?')
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Suffix) toTerm() *Term {
|
||||
if e.Index != nil {
|
||||
return &Term{Type: TermTypeIndex, Index: e.Index}
|
||||
} else if e.Iter {
|
||||
return &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{{Iter: true}}}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Suffix) toIndices(xs []any) []any {
|
||||
if e.Index == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Index.toIndices(xs)
|
||||
}
|
||||
|
||||
// If ...
|
||||
type If struct {
|
||||
Cond *Query
|
||||
Then *Query
|
||||
Elif []*IfElif
|
||||
Else *Query
|
||||
}
|
||||
|
||||
func (e *If) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *If) writeTo(s *strings.Builder) {
|
||||
s.WriteString("if ")
|
||||
e.Cond.writeTo(s)
|
||||
s.WriteString(" then ")
|
||||
e.Then.writeTo(s)
|
||||
for _, e := range e.Elif {
|
||||
s.WriteByte(' ')
|
||||
e.writeTo(s)
|
||||
}
|
||||
if e.Else != nil {
|
||||
s.WriteString(" else ")
|
||||
e.Else.writeTo(s)
|
||||
}
|
||||
s.WriteString(" end")
|
||||
}
|
||||
|
||||
// IfElif ...
|
||||
type IfElif struct {
|
||||
Cond *Query
|
||||
Then *Query
|
||||
}
|
||||
|
||||
func (e *IfElif) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *IfElif) writeTo(s *strings.Builder) {
|
||||
s.WriteString("elif ")
|
||||
e.Cond.writeTo(s)
|
||||
s.WriteString(" then ")
|
||||
e.Then.writeTo(s)
|
||||
}
|
||||
|
||||
// Try ...
|
||||
type Try struct {
|
||||
Body *Query
|
||||
Catch *Query
|
||||
}
|
||||
|
||||
func (e *Try) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Try) writeTo(s *strings.Builder) {
|
||||
s.WriteString("try ")
|
||||
e.Body.writeTo(s)
|
||||
if e.Catch != nil {
|
||||
s.WriteString(" catch ")
|
||||
e.Catch.writeTo(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce ...
|
||||
type Reduce struct {
|
||||
Query *Query
|
||||
Pattern *Pattern
|
||||
Start *Query
|
||||
Update *Query
|
||||
}
|
||||
|
||||
func (e *Reduce) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Reduce) writeTo(s *strings.Builder) {
|
||||
s.WriteString("reduce ")
|
||||
e.Query.writeTo(s)
|
||||
s.WriteString(" as ")
|
||||
e.Pattern.writeTo(s)
|
||||
s.WriteString(" (")
|
||||
e.Start.writeTo(s)
|
||||
s.WriteString("; ")
|
||||
e.Update.writeTo(s)
|
||||
s.WriteByte(')')
|
||||
}
|
||||
|
||||
// Foreach ...
|
||||
type Foreach struct {
|
||||
Query *Query
|
||||
Pattern *Pattern
|
||||
Start *Query
|
||||
Update *Query
|
||||
Extract *Query
|
||||
}
|
||||
|
||||
func (e *Foreach) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Foreach) writeTo(s *strings.Builder) {
|
||||
s.WriteString("foreach ")
|
||||
e.Query.writeTo(s)
|
||||
s.WriteString(" as ")
|
||||
e.Pattern.writeTo(s)
|
||||
s.WriteString(" (")
|
||||
e.Start.writeTo(s)
|
||||
s.WriteString("; ")
|
||||
e.Update.writeTo(s)
|
||||
if e.Extract != nil {
|
||||
s.WriteString("; ")
|
||||
e.Extract.writeTo(s)
|
||||
}
|
||||
s.WriteByte(')')
|
||||
}
|
||||
|
||||
// Label ...
|
||||
type Label struct {
|
||||
Ident string
|
||||
Body *Query
|
||||
}
|
||||
|
||||
func (e *Label) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *Label) writeTo(s *strings.Builder) {
|
||||
s.WriteString("label ")
|
||||
s.WriteString(e.Ident)
|
||||
s.WriteString(" | ")
|
||||
e.Body.writeTo(s)
|
||||
}
|
||||
|
||||
// ConstTerm ...
|
||||
type ConstTerm struct {
|
||||
Object *ConstObject
|
||||
Array *ConstArray
|
||||
Number string
|
||||
Str string
|
||||
Null bool
|
||||
True bool
|
||||
False bool
|
||||
}
|
||||
|
||||
func (e *ConstTerm) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *ConstTerm) writeTo(s *strings.Builder) {
|
||||
if e.Object != nil {
|
||||
e.Object.writeTo(s)
|
||||
} else if e.Array != nil {
|
||||
e.Array.writeTo(s)
|
||||
} else if e.Number != "" {
|
||||
s.WriteString(e.Number)
|
||||
} else if e.Null {
|
||||
s.WriteString("null")
|
||||
} else if e.True {
|
||||
s.WriteString("true")
|
||||
} else if e.False {
|
||||
s.WriteString("false")
|
||||
} else {
|
||||
jsonEncodeString(s, e.Str)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ConstTerm) toValue() any {
|
||||
if e.Object != nil {
|
||||
return e.Object.ToValue()
|
||||
} else if e.Array != nil {
|
||||
return e.Array.toValue()
|
||||
} else if e.Number != "" {
|
||||
return toNumber(e.Number)
|
||||
} else if e.Null {
|
||||
return nil
|
||||
} else if e.True {
|
||||
return true
|
||||
} else if e.False {
|
||||
return false
|
||||
} else {
|
||||
return e.Str
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ConstTerm) toString() (string, bool) {
|
||||
if e.Object != nil || e.Array != nil ||
|
||||
e.Number != "" || e.Null || e.True || e.False {
|
||||
return "", false
|
||||
}
|
||||
return e.Str, true
|
||||
}
|
||||
|
||||
// ConstObject ...
|
||||
type ConstObject struct {
|
||||
KeyVals []*ConstObjectKeyVal
|
||||
}
|
||||
|
||||
func (e *ConstObject) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *ConstObject) writeTo(s *strings.Builder) {
|
||||
if len(e.KeyVals) == 0 {
|
||||
s.WriteString("{}")
|
||||
return
|
||||
}
|
||||
s.WriteString("{ ")
|
||||
for i, kv := range e.KeyVals {
|
||||
if i > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
kv.writeTo(s)
|
||||
}
|
||||
s.WriteString(" }")
|
||||
}
|
||||
|
||||
// ToValue converts the object to map[string]any.
|
||||
func (e *ConstObject) ToValue() map[string]any {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
v := make(map[string]any, len(e.KeyVals))
|
||||
for _, e := range e.KeyVals {
|
||||
key := e.Key
|
||||
if key == "" {
|
||||
key = e.KeyString
|
||||
}
|
||||
v[key] = e.Val.toValue()
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// ConstObjectKeyVal ...
|
||||
type ConstObjectKeyVal struct {
|
||||
Key string
|
||||
KeyString string
|
||||
Val *ConstTerm
|
||||
}
|
||||
|
||||
func (e *ConstObjectKeyVal) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *ConstObjectKeyVal) writeTo(s *strings.Builder) {
|
||||
if e.Key != "" {
|
||||
s.WriteString(e.Key)
|
||||
} else {
|
||||
jsonEncodeString(s, e.KeyString)
|
||||
}
|
||||
s.WriteString(": ")
|
||||
e.Val.writeTo(s)
|
||||
}
|
||||
|
||||
// ConstArray ...
|
||||
type ConstArray struct {
|
||||
Elems []*ConstTerm
|
||||
}
|
||||
|
||||
func (e *ConstArray) String() string {
|
||||
var s strings.Builder
|
||||
e.writeTo(&s)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (e *ConstArray) writeTo(s *strings.Builder) {
|
||||
s.WriteByte('[')
|
||||
for i, e := range e.Elems {
|
||||
if i > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
e.writeTo(s)
|
||||
}
|
||||
s.WriteByte(']')
|
||||
}
|
||||
|
||||
func (e *ConstArray) toValue() []any {
|
||||
v := make([]any, len(e.Elems))
|
||||
for i, e := range e.Elems {
|
||||
v[i] = e.toValue()
|
||||
}
|
||||
return v
|
||||
}
|
||||
Reference in New Issue
Block a user