-
Notifications
You must be signed in to change notification settings - Fork 11
/
main.go
125 lines (104 loc) · 2.89 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright 2018 Yaacov Zamir <kobi.zamir@gmail.com>
// and other contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package main.
package main
import (
"context"
"database/sql"
"encoding/json"
"flag"
"fmt"
"log"
sq "github.com/Masterminds/squirrel"
"github.com/yaacov/tsl/pkg/tsl"
"github.com/yaacov/tsl/pkg/walkers/ident"
walker "github.com/yaacov/tsl/pkg/walkers/sql"
"github.com/yaacov/tsl/cmd/model"
)
func check(err error) {
if err != nil {
log.Fatal(err)
}
}
// columnNamesMap mapps between user namespace and the SQL column names.
var columnNamesMap = map[string]string{
"title": "title",
"author": "author",
"spec.pages": "pages",
"spec.rating": "rating",
}
// checkColumnName checks if a coulumn name is valid in user space replace it
// with the mapped column name and returns and error if not a valid name.
func checkColumnName(s string) (string, error) {
// Chekc for column name in map.
if v, ok := columnNamesMap[s]; ok {
return v, nil
}
// If not found return string as is, and an error.
return s, fmt.Errorf("column \"%s\" not found", s)
}
func main() {
var bookID uint
var rows *sql.Rows
// Setup the input.
inputPtr := flag.String("i", "title is not null", "the tsl string to parse (e.g. \"title = 'Book'\")")
preparePtr := flag.Bool("p", false, "prepare a book collection for queries")
filePtr := flag.String("f", "./sqlite.db", "the sqlite database file name")
flag.Parse()
// Set context.
ctx := context.Background()
// Try to connect to mongo server.
tx, err := connect(ctx, *filePtr)
check(err)
defer tx.Commit()
// Create a clean books collection.
if *preparePtr {
err = prepareCollection(ctx, tx)
check(err)
}
// Parse input string into a TSL tree.
tree, err := tsl.ParseTSL(*inputPtr)
check(err)
// Check and replace user identifiers with the SQL table column names.
tree, err = ident.Walk(tree, checkColumnName)
check(err)
// Prepare SQL filter.
filter, err := walker.Walk(tree)
check(err)
// Query SQL table.
rows, err = sq.
Select("*").
Where(filter).
From("books").
RunWith(tx).
QueryContext(ctx)
check(err)
for rows.Next() {
elem := model.Book{}
err = rows.Scan(
&bookID,
&elem.Title,
&elem.Author,
&elem.Spec.Pages,
&elem.Spec.Rating,
)
check(err)
b, _ := json.Marshal(elem)
fmt.Printf("%s\n", string(b))
}
// Check for errors and exit.
err = rows.Err()
check(err)
}