aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/query/parser.go28
-rw-r--r--pkg/query/parser_test.go50
2 files changed, 75 insertions, 3 deletions
diff --git a/pkg/query/parser.go b/pkg/query/parser.go
index 5de803c..d7f4fdd 100644
--- a/pkg/query/parser.go
+++ b/pkg/query/parser.go
@@ -53,8 +53,11 @@ type Statement struct {
Operator opType
Value Valuer
}
+
+type Statements []Statement
+
type Clause struct {
- Statements []Statement
+ Statements Statements
Clauses []*Clause
Operator clauseOperator
}
@@ -101,7 +104,7 @@ func (v StringValue) Compare(other Valuer) int {
}
type DatetimeValue struct {
- d time.Time
+ D time.Time
}
func (v DatetimeValue) Type() valuerType {
@@ -114,7 +117,7 @@ func (v DatetimeValue) Compare(other Valuer) int {
return 0
}
- return v.d.Compare(o.d)
+ return v.D.Compare(o.D)
}
var _ Valuer = StringValue{}
@@ -230,6 +233,16 @@ func (root *Clause) Flatten() {
stack = stack[:top]
hasMerged := false
+
+ // merge if only child clause
+ if len(node.Statements) == 0 && len(node.Clauses) == 1 {
+ child := node.Clauses[0]
+
+ node.Operator = child.Operator
+ node.Statements = child.Statements
+ node.Clauses = child.Clauses
+ }
+
// cannot be "modernized", node.Clauses is modified in loop
for i := 0; i < len(node.Clauses); i++ {
child := node.Clauses[i]
@@ -293,6 +306,15 @@ func (root Clause) Depth() int {
return maxHeight
}
+// Order of clause tree
+func (root Clause) Order() int {
+ count := 0
+ for range root.DFS() {
+ count++
+ }
+ return count
+}
+
func (root *Clause) DFS() iter.Seq[*Clause] {
return func(yield func(*Clause) bool) {
stack := make([]*Clause, 0, len(root.Clauses))
diff --git a/pkg/query/parser_test.go b/pkg/query/parser_test.go
index 7ee4987..c1f25d4 100644
--- a/pkg/query/parser_test.go
+++ b/pkg/query/parser_test.go
@@ -19,6 +19,26 @@ func TestClause_Flatten(t *testing.T) {
query.Clause{},
},
{
+ "empty with child",
+ &query.Clause{
+ Operator: query.COP_OR,
+ Clauses: []*query.Clause{
+ {
+ Operator: query.COP_AND,
+ Statements: []query.Statement{
+ {Category: query.CAT_AUTHOR, Operator: query.OP_AP, Value: query.StringValue{"jp"}},
+ },
+ },
+ },
+ },
+ query.Clause{
+ Operator: query.COP_AND,
+ Statements: []query.Statement{
+ {Category: query.CAT_AUTHOR, Operator: query.OP_AP, Value: query.StringValue{"jp"}},
+ },
+ },
+ },
+ {
"already flat",
&query.Clause{
Operator: query.COP_AND,
@@ -170,3 +190,33 @@ func TestClause_Flatten(t *testing.T) {
})
}
}
+
+func TestParse(t *testing.T) {
+ tests := []struct {
+ name string // description of this test case
+ // Named input parameters for target function.
+ tokens []query.Token
+ want *query.Clause
+ wantErr bool
+ }{
+ // TODO: Add test cases.
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, gotErr := query.Parse(tt.tokens)
+ if gotErr != nil {
+ if !tt.wantErr {
+ t.Errorf("Parse() failed: %v", gotErr)
+ }
+ return
+ }
+ if tt.wantErr {
+ t.Fatal("Parse() succeeded unexpectedly")
+ }
+ // TODO: update the condition below to compare got with tt.want.
+ if true {
+ t.Errorf("Parse() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}