diff options
Diffstat (limited to 'pkg/query/compiler.go')
| -rw-r--r-- | pkg/query/compiler.go | 159 |
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) |
