README.md
1# Query package
2
3## Overview
4
5Package query performs JSONPath-like queries on a TOML document.
6
7The query path implementation is based loosely on the JSONPath specification:
8http://goessner.net/articles/JsonPath/.
9
10The idea behind a query path is to allow quick access to any element, or set
11of elements within TOML document, with a single expression.
12
13```go
14result, err := query.CompileAndExecute("$.foo.bar.baz", tree)
15```
16
17This is roughly equivalent to:
18
19```go
20next := tree.Get("foo")
21if next != nil {
22 next = next.Get("bar")
23 if next != nil {
24 next = next.Get("baz")
25 }
26}
27result := next
28```
29
30err is nil if any parsing exception occurs.
31
32If no node in the tree matches the query, result will simply contain an empty list of
33items.
34
35As illustrated above, the query path is much more efficient, especially since
36the structure of the TOML file can vary. Rather than making assumptions about
37a document's structure, a query allows the programmer to make structured
38requests into the document, and get zero or more values as a result.
39
40## Query syntax
41
42The syntax of a query begins with a root token, followed by any number
43sub-expressions:
44
45```
46$
47 Root of the TOML tree. This must always come first.
48.name
49 Selects child of this node, where 'name' is a TOML key
50 name.
51['name']
52 Selects child of this node, where 'name' is a string
53 containing a TOML key name.
54[index]
55 Selcts child array element at 'index'.
56..expr
57 Recursively selects all children, filtered by an a union,
58 index, or slice expression.
59..*
60 Recursive selection of all nodes at this point in the
61 tree.
62.*
63 Selects all children of the current node.
64[expr,expr]
65 Union operator - a logical 'or' grouping of two or more
66 sub-expressions: index, key name, or filter.
67[start:end:step]
68 Slice operator - selects array elements from start to
69 end-1, at the given step. All three arguments are
70 optional.
71[?(filter)]
72 Named filter expression - the function 'filter' is
73 used to filter children at this node.
74```
75
76## Query Indexes And Slices
77
78Index expressions perform no bounds checking, and will contribute no
79values to the result set if the provided index or index range is invalid.
80Negative indexes represent values from the end of the array, counting backwards.
81
82```go
83// select the last index of the array named 'foo'
84query.CompileAndExecute("$.foo[-1]", tree)
85```
86
87Slice expressions are supported, by using ':' to separate a start/end index pair.
88
89```go
90// select up to the first five elements in the array
91query.CompileAndExecute("$.foo[0:5]", tree)
92```
93
94Slice expressions also allow negative indexes for the start and stop
95arguments.
96
97```go
98// select all array elements except the last one.
99query.CompileAndExecute("$.foo[0:-1]", tree)
100```
101
102Slice expressions may have an optional stride/step parameter:
103
104```go
105// select every other element
106query.CompileAndExecute("$.foo[0::2]", tree)
107```
108
109Slice start and end parameters are also optional:
110
111```go
112// these are all equivalent and select all the values in the array
113query.CompileAndExecute("$.foo[:]", tree)
114query.CompileAndExecute("$.foo[::]", tree)
115query.CompileAndExecute("$.foo[::1]", tree)
116query.CompileAndExecute("$.foo[0:]", tree)
117query.CompileAndExecute("$.foo[0::]", tree)
118query.CompileAndExecute("$.foo[0::1]", tree)
119```
120
121## Query Filters
122
123Query filters are used within a Union [,] or single Filter [] expression.
124A filter only allows nodes that qualify through to the next expression,
125and/or into the result set.
126
127```go
128// returns children of foo that are permitted by the 'bar' filter.
129query.CompileAndExecute("$.foo[?(bar)]", tree)
130```
131
132There are several filters provided with the library:
133
134```
135tree
136 Allows nodes of type Tree.
137int
138 Allows nodes of type int64.
139float
140 Allows nodes of type float64.
141string
142 Allows nodes of type string.
143time
144 Allows nodes of type time.Time.
145bool
146 Allows nodes of type bool.
147```
148
149## Query Results
150
151An executed query returns a Result object. This contains the nodes
152in the TOML tree that qualify the query expression. Position information
153is also available for each value in the set.
154
155```go
156// display the results of a query
157results := query.CompileAndExecute("$.foo.bar.baz", tree)
158for idx, value := results.Values() {
159 fmt.Println("%v: %v", results.Positions()[idx], value)
160}
161```
162
163## Compiled Queries
164
165Queries may be executed directly on a Tree object, or compiled ahead
166of time and executed discretely. The former is more convenient, but has the
167penalty of having to recompile the query expression each time.
168
169```go
170// basic query
171results := query.CompileAndExecute("$.foo.bar.baz", tree)
172
173// compiled query
174query, err := toml.Compile("$.foo.bar.baz")
175results := query.Execute(tree)
176
177// run the compiled query again on a different tree
178moreResults := query.Execute(anotherTree)
179```
180
181## User Defined Query Filters
182
183Filter expressions may also be user defined by using the SetFilter()
184function on the Query object. The function must return true/false, which
185signifies if the passed node is kept or discarded, respectively.
186
187```go
188// create a query that references a user-defined filter
189query, _ := query.Compile("$[?(bazOnly)]")
190
191// define the filter, and assign it to the query
192query.SetFilter("bazOnly", func(node interface{}) bool{
193 if tree, ok := node.(*Tree); ok {
194 return tree.Has("baz")
195 }
196 return false // reject all other node types
197})
198
199// run the query
200query.Execute(tree)
201```
202