...

Source file src/github.com/pelletier/go-toml/query/query.go

Documentation: github.com/pelletier/go-toml/query

     1  package query
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/pelletier/go-toml"
     7  )
     8  
     9  // NodeFilterFn represents a user-defined filter function, for use with
    10  // Query.SetFilter().
    11  //
    12  // The return value of the function must indicate if 'node' is to be included
    13  // at this stage of the TOML path.  Returning true will include the node, and
    14  // returning false will exclude it.
    15  //
    16  // NOTE: Care should be taken to write script callbacks such that they are safe
    17  // to use from multiple goroutines.
    18  type NodeFilterFn func(node interface{}) bool
    19  
    20  // Result is the result of Executing a Query.
    21  type Result struct {
    22  	items     []interface{}
    23  	positions []toml.Position
    24  }
    25  
    26  // appends a value/position pair to the result set.
    27  func (r *Result) appendResult(node interface{}, pos toml.Position) {
    28  	r.items = append(r.items, node)
    29  	r.positions = append(r.positions, pos)
    30  }
    31  
    32  // Values is a set of values within a Result.  The order of values is not
    33  // guaranteed to be in document order, and may be different each time a query is
    34  // executed.
    35  func (r Result) Values() []interface{} {
    36  	return r.items
    37  }
    38  
    39  // Positions is a set of positions for values within a Result.  Each index
    40  // in Positions() corresponds to the entry in Value() of the same index.
    41  func (r Result) Positions() []toml.Position {
    42  	return r.positions
    43  }
    44  
    45  // runtime context for executing query paths
    46  type queryContext struct {
    47  	result       *Result
    48  	filters      *map[string]NodeFilterFn
    49  	lastPosition toml.Position
    50  }
    51  
    52  // generic path functor interface
    53  type pathFn interface {
    54  	setNext(next pathFn)
    55  	// it is the caller's responsibility to set the ctx.lastPosition before invoking call()
    56  	// node can be one of: *toml.Tree, []*toml.Tree, or a scalar
    57  	call(node interface{}, ctx *queryContext)
    58  }
    59  
    60  // A Query is the representation of a compiled TOML path.  A Query is safe
    61  // for concurrent use by multiple goroutines.
    62  type Query struct {
    63  	root    pathFn
    64  	tail    pathFn
    65  	filters *map[string]NodeFilterFn
    66  }
    67  
    68  func newQuery() *Query {
    69  	return &Query{
    70  		root:    nil,
    71  		tail:    nil,
    72  		filters: &defaultFilterFunctions,
    73  	}
    74  }
    75  
    76  func (q *Query) appendPath(next pathFn) {
    77  	if q.root == nil {
    78  		q.root = next
    79  	} else {
    80  		q.tail.setNext(next)
    81  	}
    82  	q.tail = next
    83  	next.setNext(newTerminatingFn()) // init the next functor
    84  }
    85  
    86  // Compile compiles a TOML path expression. The returned Query can be used
    87  // to match elements within a Tree and its descendants. See Execute.
    88  func Compile(path string) (*Query, error) {
    89  	return parseQuery(lexQuery(path))
    90  }
    91  
    92  // Execute executes a query against a Tree, and returns the result of the query.
    93  func (q *Query) Execute(tree *toml.Tree) *Result {
    94  	result := &Result{
    95  		items:     []interface{}{},
    96  		positions: []toml.Position{},
    97  	}
    98  	if q.root == nil {
    99  		result.appendResult(tree, tree.GetPosition(""))
   100  	} else {
   101  		ctx := &queryContext{
   102  			result:  result,
   103  			filters: q.filters,
   104  		}
   105  		ctx.lastPosition = tree.Position()
   106  		q.root.call(tree, ctx)
   107  	}
   108  	return result
   109  }
   110  
   111  // CompileAndExecute is a shorthand for Compile(path) followed by Execute(tree).
   112  func CompileAndExecute(path string, tree *toml.Tree) (*Result, error) {
   113  	query, err := Compile(path)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	return query.Execute(tree), nil
   118  }
   119  
   120  // SetFilter sets a user-defined filter function.  These may be used inside
   121  // "?(..)" query expressions to filter TOML document elements within a query.
   122  func (q *Query) SetFilter(name string, fn NodeFilterFn) {
   123  	if q.filters == &defaultFilterFunctions {
   124  		// clone the static table
   125  		q.filters = &map[string]NodeFilterFn{}
   126  		for k, v := range defaultFilterFunctions {
   127  			(*q.filters)[k] = v
   128  		}
   129  	}
   130  	(*q.filters)[name] = fn
   131  }
   132  
   133  var defaultFilterFunctions = map[string]NodeFilterFn{
   134  	"tree": func(node interface{}) bool {
   135  		_, ok := node.(*toml.Tree)
   136  		return ok
   137  	},
   138  	"int": func(node interface{}) bool {
   139  		_, ok := node.(int64)
   140  		return ok
   141  	},
   142  	"float": func(node interface{}) bool {
   143  		_, ok := node.(float64)
   144  		return ok
   145  	},
   146  	"string": func(node interface{}) bool {
   147  		_, ok := node.(string)
   148  		return ok
   149  	},
   150  	"time": func(node interface{}) bool {
   151  		_, ok := node.(time.Time)
   152  		return ok
   153  	},
   154  	"bool": func(node interface{}) bool {
   155  		_, ok := node.(bool)
   156  		return ok
   157  	},
   158  }
   159  

View as plain text