aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/query/compiler.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/query/compiler.go')
-rw-r--r--pkg/query/compiler.go159
1 files changed, 145 insertions, 14 deletions
diff --git a/pkg/query/compiler.go b/pkg/query/compiler.go
index d566b05..f0df4b4 100644
--- a/pkg/query/compiler.go
+++ b/pkg/query/compiler.go
@@ -3,6 +3,8 @@ package query
import (
"fmt"
"strings"
+
+ "github.com/jpappel/atlas/pkg/util"
)
const MAX_CLAUSE_DEPTH int = 16
@@ -77,21 +79,150 @@ func (stmt Statement) Compile(b *strings.Builder) (*string, error) {
return nil, nil
}
-func (stmts Statements) Compile(b *strings.Builder, delim string) ([]string, error) {
+func (s Statements) Compile(b *strings.Builder, delim string) ([]string, error) {
var args []string
- // TODO: handle meta category
- for i, stmt := range stmts {
- if i != 0 {
- b.WriteString(delim)
+ sCount := 0
+ for cat, catStmts := range s.CategoryPartition() {
+ // TODO: make sure sorted
+ // TODO: loop over partitions
+ if len(catStmts) == 0 {
+ continue
+ }
+ var catStr string
+ switch cat {
+ case CAT_AUTHOR:
+ catStr = "author "
+ case CAT_DATE:
+ catStr = "date "
+ case CAT_FILETIME:
+ catStr = "fileTime "
+ case CAT_LINKS:
+ catStr = "link "
+ case CAT_META:
+ catStr = "meta "
+ case CAT_TAGS:
+ catStr = "tag "
+ case CAT_TITLE:
+ catStr = "title "
+ default:
+ return nil, &CompileError{
+ fmt.Sprintf("unexpected query.catType %#v", cat),
+ }
}
- b.WriteByte(' ')
- arg, err := stmt.Compile(b)
- if err != nil {
- return nil, err
- } else if arg != nil {
- args = append(args, *arg)
+ for op, opStmts := range catStmts.OperatorPartition() {
+ if len(opStmts) == 0 {
+ continue
+ }
+ var opStr string
+ switch op {
+ case OP_AP:
+ if cat.IsOrdered() {
+ opStr = "BETWEEN "
+ } else {
+ opStr = "LIKE "
+ }
+ case OP_EQ:
+ if cat.IsSet() {
+ opStr = "IN "
+ } else {
+ opStr = "= "
+ }
+ case OP_GE:
+ // NOTE: doesn't raise compiler error if operator used on invalid category
+ opStr = ">= "
+ case OP_GT:
+ // NOTE: doesn't raise compiler error if operator used on invalid category
+ opStr = "> "
+ case OP_LE:
+ // NOTE: doesn't raise compiler error if operator used on invalid category
+ opStr = "<= "
+ case OP_LT:
+ // NOTE: doesn't raise compiler error if operator used on invalid category
+ opStr = "< "
+ case OP_NE:
+ if cat.IsSet() {
+ opStr = "NOT IN "
+ } else {
+ opStr = "!= "
+ }
+ case OP_PIPE:
+ opStr = "?op_pipe "
+ case OP_ARG:
+ opStr = "?op_arg "
+ default:
+ return nil, &CompileError{
+ fmt.Sprintf("unexpected query.opType %#v", op),
+ }
+ }
+
+ if cat.IsSet() && op != OP_AP {
+ b.WriteString(catStr)
+ b.WriteString(opStr)
+ b.WriteByte('(')
+ idx := 0
+ for _, stmt := range opStmts {
+ arg, ok := stmt.Value.buildCompile(b)
+ if ok {
+ args = append(args, arg)
+ }
+ if idx != len(opStmts)-1 {
+ b.WriteByte(',')
+ }
+ sCount++
+ idx++
+ }
+ b.WriteString(") ")
+ } else if cat.IsOrdered() && op == OP_AP {
+ idx := 0
+ for _, stmt := range opStmts {
+ b.WriteString(catStr)
+ d, ok := stmt.Value.(DatetimeValue)
+ if !ok {
+ panic("type corruption, expected DatetimeValue")
+ }
+
+ start, end := util.FuzzDatetime(d.D)
+
+ b.WriteString(opStr)
+ fmt.Fprint(b, start.Unix(), " ")
+ b.WriteString("AND ")
+ fmt.Fprint(b, end.Unix(), " ")
+ if idx != len(opStmts)-1 {
+ b.WriteString(delim)
+ b.WriteByte(' ')
+ }
+ idx++
+ sCount++
+ }
+ } else {
+ idx := 0
+ for _, stmt := range opStmts {
+ b.WriteString(catStr)
+ b.WriteString(opStr)
+ arg, ok := stmt.Value.buildCompile(b)
+ if ok {
+ if op == OP_AP {
+ args = append(args, "%"+arg+"%")
+ } else {
+ args = append(args, arg)
+ }
+ }
+ b.WriteByte(' ')
+ if idx != len(opStmts)-1 {
+ b.WriteString(delim)
+ b.WriteByte(' ')
+ }
+ idx++
+ sCount++
+ }
+ }
+
+ if sCount != len(s) {
+ b.WriteString(delim)
+ b.WriteByte(' ')
+ }
}
}
@@ -101,7 +232,7 @@ func (stmts Statements) Compile(b *strings.Builder, delim string) ([]string, err
func (root Clause) Compile() (string, []string, error) {
if d := root.Depth(); d > MAX_CLAUSE_DEPTH {
return "", nil, &CompileError{
- fmt.Sprint("exceeded maximum clause depth of 8: ", d),
+ fmt.Sprintf("exceeded maximum clause depth: %d > %d", d, MAX_CLAUSE_DEPTH),
}
}
@@ -117,13 +248,13 @@ func (c Clause) buildCompile(b *strings.Builder) ([]string, error) {
b.WriteString("( ")
var delim string
- switch cop := c.Operator; cop {
+ switch c.Operator {
case COP_AND:
delim = "AND"
case COP_OR:
delim = "OR"
default:
- return nil, &CompileError{fmt.Sprint("invalid clause operator ", cop)}
+ return nil, &CompileError{fmt.Sprint("invalid clause operator ", c.Operator)}
}
args, err := c.Statements.Compile(b, delim)