Skip to content

Commit 41d3f37

Browse files
committed
more-reamde
Signed-off-by: yaacov <[email protected]>
1 parent af9e344 commit 41d3f37

File tree

2 files changed

+326
-0
lines changed

2 files changed

+326
-0
lines changed

README_usage.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# TSL Usage Guide
2+
3+
A set examples showing how to use TSL in various scenarios.
4+
5+
---
6+
7+
## 1. Parsing and validating filter expressions
8+
9+
Use case: receive a filter string from a REST API, validate its syntax, and print a human‐readable tree or report errors.
10+
11+
```go
12+
import (
13+
"fmt"
14+
"github.com/yaacov/tree-search-language/v6/pkg/tsl"
15+
)
16+
17+
func parseFilter(input string) {
18+
tree, err := tsl.ParseTSL(input)
19+
if err != nil {
20+
// SyntaxError contains Message, Position, Context
21+
fmt.Printf("Invalid filter: %s\n", err)
22+
return
23+
}
24+
defer tree.Free()
25+
26+
// If we reach here, syntax is valid; tree can be marshaled to JSON/YAML
27+
data, _ := tree.MarshalJSON()
28+
fmt.Printf("Parsed filter tree:\n%s\n", data)
29+
}
30+
```
31+
32+
**Explanation**
33+
- `ParseTSL` returns a syntax‐checked AST.
34+
- On error, you get precise position and context.
35+
- A valid tree can be serialized for debugging or logging.
36+
37+
---
38+
39+
## 2. In‑memory record filtering
40+
41+
Use case: filter a slice of user records in Go without touching a database.
42+
43+
```go
44+
import "github.com/yaacov/tree-search-language/v6/pkg/walkers/semantics"
45+
46+
records := []map[string]interface{}{
47+
{"name":"alice","age":30},
48+
{"name":"bob","age":25},
49+
}
50+
51+
tree, _ := tsl.ParseTSL("age >= 28")
52+
defer tree.Free()
53+
54+
for _, rec := range records {
55+
eval := func(field string) (interface{}, bool) {
56+
val, ok := rec[field]
57+
return val, ok
58+
}
59+
match, _ := semantics.Walk(tree, eval)
60+
if match.(bool) {
61+
// rec passed the filter
62+
fmt.Println("Matches:", rec)
63+
}
64+
}
65+
```
66+
67+
**Explanation**
68+
- Supply a lookup function (`eval`) that returns `value, ok`.
69+
- `Walk` applies the expression tree to each record.
70+
- Great for in‑process filtering of JSON, CSV, or config objects.
71+
72+
---
73+
74+
## 3. Generating SQL WHERE clauses
75+
76+
Use case: convert a user‐supplied filter into a parameterized WHERE clause using Squirrel.
77+
78+
```go
79+
import (
80+
sq "github.com/Masterminds/squirrel"
81+
"github.com/yaacov/tree-search-language/v6/pkg/walkers/sql"
82+
)
83+
84+
tree, _ := tsl.ParseTSL("status = 'active' AND score > 50")
85+
defer tree.Free()
86+
87+
filter, _ := sql.Walk(tree) // returns a squirrel.Sqlizer
88+
query, args, _ := sq.Select("*").
89+
From("players").
90+
Where(filter).
91+
ToSql()
92+
93+
// query: "SELECT * FROM players WHERE (status = ? AND score > ?)"
94+
// args: ["active", 50]
95+
```
96+
97+
**Explanation**
98+
- `sql.Walk` produces a Squirrel filter object.
99+
- The returned SQL is safe against injection (parameters are placeholders).
100+
- You can tack this onto any SELECT/UPDATE/DELETE builder.
101+
102+
---
103+
104+
## 4. Visualizing expression trees
105+
106+
Use case: debug complex filters by exporting to Graphviz DOT and rendering a diagram.
107+
108+
```go
109+
import (
110+
"fmt"
111+
"github.com/yaacov/tree-search-language/v6/pkg/walkers/graphviz"
112+
)
113+
114+
tree, _ := tsl.ParseTSL("name LIKE '%doe%' OR (age BETWEEN 20 AND 30)")
115+
defer tree.Free()
116+
117+
dotContent, _ := graphviz.Walk("", tree, "FilterTree")
118+
dot := fmt.Sprintf("digraph FilterTree {\n%s\n}", dotContent)
119+
fmt.Println(dot)
120+
// Pipe output into `dot -Tpng` to see the visual tree
121+
```
122+
123+
**Explanation**
124+
- `graphviz.Walk` returns a snippet of DOT nodes and edges.
125+
- Wrap it in a `digraph { … }` block.
126+
- Use standard Graphviz tools to generate PNG/SVG for documentation.
127+
128+
---
129+
130+
## 5. Renaming fields (identifier mapping)
131+
132+
Use case: let end users filter on logical names, map them to actual database or JSON fields.
133+
134+
```go
135+
import "github.com/yaacov/tree-search-language/v6/pkg/walkers/ident"
136+
137+
mapping := map[string]string{
138+
"user": "customers.name",
139+
"balance": "accounts.current_balance",
140+
}
141+
142+
mapper := func(id string) (string, error) {
143+
if col, ok := mapping[id]; ok {
144+
return col, nil
145+
}
146+
return "", fmt.Errorf("unknown field: %s", id)
147+
}
148+
149+
tree, _ := tsl.ParseTSL("user = 'alice' AND balance > 1000")
150+
defer tree.Free()
151+
152+
newTree, _ := ident.Walk(tree, mapper)
153+
defer newTree.Free()
154+
155+
// newTree now uses "customers.name" and "accounts.current_balance"
156+
```
157+
158+
**Explanation**
159+
- `ident.Walk` clones the AST and applies your mapping function to each identifier.
160+
- Invalid identifiers cause an error early in the pipeline.
161+
- Ideal for decoupling front‑end field names from internal schemas.
162+
163+
---

v6/README_usage.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# TSL Usage Guide
2+
3+
A set examples showing how to use TSL in various scenarios.
4+
5+
---
6+
7+
## 1. Parsing and validating filter expressions
8+
9+
Use case: receive a filter string from a REST API, validate its syntax, and print a human‐readable tree or report errors.
10+
11+
```go
12+
import (
13+
"fmt"
14+
"github.com/yaacov/tree-search-language/v6/pkg/tsl"
15+
)
16+
17+
func parseFilter(input string) {
18+
tree, err := tsl.ParseTSL(input)
19+
if err != nil {
20+
// SyntaxError contains Message, Position, Context
21+
fmt.Printf("Invalid filter: %s\n", err)
22+
return
23+
}
24+
defer tree.Free()
25+
26+
// If we reach here, syntax is valid; tree can be marshaled to JSON/YAML
27+
data, _ := tree.MarshalJSON()
28+
fmt.Printf("Parsed filter tree:\n%s\n", data)
29+
}
30+
```
31+
32+
**Explanation**
33+
- `ParseTSL` returns a syntax‐checked AST.
34+
- On error, you get precise position and context.
35+
- A valid tree can be serialized for debugging or logging.
36+
37+
---
38+
39+
## 2. In‑memory record filtering
40+
41+
Use case: filter a slice of user records in Go without touching a database.
42+
43+
```go
44+
import "github.com/yaacov/tree-search-language/v6/pkg/walkers/semantics"
45+
46+
records := []map[string]interface{}{
47+
{"name":"alice","age":30},
48+
{"name":"bob","age":25},
49+
}
50+
51+
tree, _ := tsl.ParseTSL("age >= 28")
52+
defer tree.Free()
53+
54+
for _, rec := range records {
55+
eval := func(field string) (interface{}, bool) {
56+
val, ok := rec[field]
57+
return val, ok
58+
}
59+
match, _ := semantics.Walk(tree, eval)
60+
if match.(bool) {
61+
// rec passed the filter
62+
fmt.Println("Matches:", rec)
63+
}
64+
}
65+
```
66+
67+
**Explanation**
68+
- Supply a lookup function (`eval`) that returns `value, ok`.
69+
- `Walk` applies the expression tree to each record.
70+
- Great for in‑process filtering of JSON, CSV, or config objects.
71+
72+
---
73+
74+
## 3. Generating SQL WHERE clauses
75+
76+
Use case: convert a user‐supplied filter into a parameterized WHERE clause using Squirrel.
77+
78+
```go
79+
import (
80+
sq "github.com/Masterminds/squirrel"
81+
"github.com/yaacov/tree-search-language/v6/pkg/walkers/sql"
82+
)
83+
84+
tree, _ := tsl.ParseTSL("status = 'active' AND score > 50")
85+
defer tree.Free()
86+
87+
filter, _ := sql.Walk(tree) // returns a squirrel.Sqlizer
88+
query, args, _ := sq.Select("*").
89+
From("players").
90+
Where(filter).
91+
ToSql()
92+
93+
// query: "SELECT * FROM players WHERE (status = ? AND score > ?)"
94+
// args: ["active", 50]
95+
```
96+
97+
**Explanation**
98+
- `sql.Walk` produces a Squirrel filter object.
99+
- The returned SQL is safe against injection (parameters are placeholders).
100+
- You can tack this onto any SELECT/UPDATE/DELETE builder.
101+
102+
---
103+
104+
## 4. Visualizing expression trees
105+
106+
Use case: debug complex filters by exporting to Graphviz DOT and rendering a diagram.
107+
108+
```go
109+
import (
110+
"fmt"
111+
"github.com/yaacov/tree-search-language/v6/pkg/walkers/graphviz"
112+
)
113+
114+
tree, _ := tsl.ParseTSL("name LIKE '%doe%' OR (age BETWEEN 20 AND 30)")
115+
defer tree.Free()
116+
117+
dotContent, _ := graphviz.Walk("", tree, "FilterTree")
118+
dot := fmt.Sprintf("digraph FilterTree {\n%s\n}", dotContent)
119+
fmt.Println(dot)
120+
// Pipe output into `dot -Tpng` to see the visual tree
121+
```
122+
123+
**Explanation**
124+
- `graphviz.Walk` returns a snippet of DOT nodes and edges.
125+
- Wrap it in a `digraph { … }` block.
126+
- Use standard Graphviz tools to generate PNG/SVG for documentation.
127+
128+
---
129+
130+
## 5. Renaming fields (identifier mapping)
131+
132+
Use case: let end users filter on logical names, map them to actual database or JSON fields.
133+
134+
```go
135+
import "github.com/yaacov/tree-search-language/v6/pkg/walkers/ident"
136+
137+
mapping := map[string]string{
138+
"user": "customers.name",
139+
"balance": "accounts.current_balance",
140+
}
141+
142+
mapper := func(id string) (string, error) {
143+
if col, ok := mapping[id]; ok {
144+
return col, nil
145+
}
146+
return "", fmt.Errorf("unknown field: %s", id)
147+
}
148+
149+
tree, _ := tsl.ParseTSL("user = 'alice' AND balance > 1000")
150+
defer tree.Free()
151+
152+
newTree, _ := ident.Walk(tree, mapper)
153+
defer newTree.Free()
154+
155+
// newTree now uses "customers.name" and "accounts.current_balance"
156+
```
157+
158+
**Explanation**
159+
- `ident.Walk` clones the AST and applies your mapping function to each identifier.
160+
- Invalid identifiers cause an error early in the pipeline.
161+
- Ideal for decoupling front‑end field names from internal schemas.
162+
163+
---

0 commit comments

Comments
 (0)