Skip to content

Commit 24548ef

Browse files
committed
Allow count distinct operation.
1 parent 5c89099 commit 24548ef

File tree

5 files changed

+54
-25
lines changed

5 files changed

+54
-25
lines changed

internal/knowledge/query_expression_builder.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package knowledge
22

3-
import "fmt"
3+
import (
4+
"fmt"
5+
"strings"
46

5-
import "strings"
6-
7-
import "github.com/clems4ever/go-graphkb/internal/query"
7+
"github.com/clems4ever/go-graphkb/internal/query"
8+
)
89

910
type ExpressionBuilder struct {
1011
QueryGraph *QueryGraph
@@ -159,8 +160,12 @@ func (sev *SQLExpressionVisitor) OnExitPropertyOrLabelsExpression(e query.QueryP
159160
return nil
160161
}
161162

162-
func (sev *SQLExpressionVisitor) OnExitFunctionInvocation(name string) error {
163-
sev.functionInvocation = fmt.Sprintf("%s(%s)", name, sev.expression)
163+
func (sev *SQLExpressionVisitor) OnExitFunctionInvocation(name string, distinct bool) error {
164+
distinctStr := ""
165+
if distinct {
166+
distinctStr = "DISTINCT "
167+
}
168+
sev.functionInvocation = fmt.Sprintf("%s(%s%s)", name, distinctStr, sev.expression)
164169
sev.expression = ""
165170
return nil
166171
}

internal/knowledge/query_expression_parser.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ type ExpressionVisitor interface {
3030
OnIntegerLiteral(value int64) error
3131
OnBooleanLiteral(value bool) error
3232

33-
OnEnterFunctionInvocation(name string) error
34-
OnExitFunctionInvocation(name string) error
33+
OnEnterFunctionInvocation(name string, distinct bool) error
34+
OnExitFunctionInvocation(name string, distinct bool) error
3535

3636
OnEnterParenthesizedExpression() error
3737
OnExitParenthesizedExpression() error
@@ -123,7 +123,8 @@ func (ep *ExpressionParser) ParsePropertyOrLabelsExpression(q *query.QueryProper
123123
}
124124
} else if q.Atom.FunctionInvocation != nil {
125125
fnName := strings.ToUpper(q.Atom.FunctionInvocation.FunctionName)
126-
err := ep.visitor.OnEnterFunctionInvocation(fnName)
126+
distinct := q.Atom.FunctionInvocation.Distinct
127+
err := ep.visitor.OnEnterFunctionInvocation(fnName, distinct)
127128
if err != nil {
128129
return err
129130
}
@@ -134,7 +135,7 @@ func (ep *ExpressionParser) ParsePropertyOrLabelsExpression(q *query.QueryProper
134135
return err
135136
}
136137
}
137-
err = ep.visitor.OnExitFunctionInvocation(fnName)
138+
err = ep.visitor.OnExitFunctionInvocation(fnName, distinct)
138139
if err != nil {
139140
return err
140141
}
@@ -425,17 +426,21 @@ func (evb *ExpressionVisitorBase) OnStringLiteral(value string) error
425426
func (evb *ExpressionVisitorBase) OnDoubleLiteral(value float64) error { return nil }
426427
func (evb *ExpressionVisitorBase) OnIntegerLiteral(value int64) error { return nil }
427428
func (evb *ExpressionVisitorBase) OnBooleanLiteral(value bool) error { return nil }
428-
func (evb *ExpressionVisitorBase) OnEnterFunctionInvocation(name string) error { return nil }
429-
func (evb *ExpressionVisitorBase) OnExitFunctionInvocation(name string) error { return nil }
430-
func (evb *ExpressionVisitorBase) OnEnterParenthesizedExpression() error { return nil }
431-
func (evb *ExpressionVisitorBase) OnExitParenthesizedExpression() error { return nil }
432-
func (evb *ExpressionVisitorBase) OnStringOperator(operator query.StringOperator) error { return nil }
433-
func (evb *ExpressionVisitorBase) OnEnterUnaryExpression() error { return nil }
434-
func (evb *ExpressionVisitorBase) OnExitUnaryExpression() error { return nil }
435-
func (evb *ExpressionVisitorBase) OnEnterPowerOfExpression() error { return nil }
436-
func (evb *ExpressionVisitorBase) OnExitPowerOfExpression() error { return nil }
437-
func (evb *ExpressionVisitorBase) OnEnterMultipleDivideModuloExpression() error { return nil }
438-
func (evb *ExpressionVisitorBase) OnExitMultipleDivideModuloExpression() error { return nil }
429+
func (evb *ExpressionVisitorBase) OnEnterFunctionInvocation(name string, distinct bool) error {
430+
return nil
431+
}
432+
func (evb *ExpressionVisitorBase) OnExitFunctionInvocation(name string, distinct bool) error {
433+
return nil
434+
}
435+
func (evb *ExpressionVisitorBase) OnEnterParenthesizedExpression() error { return nil }
436+
func (evb *ExpressionVisitorBase) OnExitParenthesizedExpression() error { return nil }
437+
func (evb *ExpressionVisitorBase) OnStringOperator(operator query.StringOperator) error { return nil }
438+
func (evb *ExpressionVisitorBase) OnEnterUnaryExpression() error { return nil }
439+
func (evb *ExpressionVisitorBase) OnExitUnaryExpression() error { return nil }
440+
func (evb *ExpressionVisitorBase) OnEnterPowerOfExpression() error { return nil }
441+
func (evb *ExpressionVisitorBase) OnExitPowerOfExpression() error { return nil }
442+
func (evb *ExpressionVisitorBase) OnEnterMultipleDivideModuloExpression() error { return nil }
443+
func (evb *ExpressionVisitorBase) OnExitMultipleDivideModuloExpression() error { return nil }
439444
func (evb *ExpressionVisitorBase) OnMultiplyDivideModuloOperator(operator query.MultiplyDivideModuloOperator) error {
440445
return nil
441446
}

internal/knowledge/query_projection_visitor.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package knowledge
22

3-
import "github.com/clems4ever/go-graphkb/internal/query"
3+
import (
4+
"fmt"
45

5-
import "fmt"
6+
"github.com/clems4ever/go-graphkb/internal/query"
7+
)
68

79
type ProjectionVisitor struct {
810
ExpressionVisitorBase
@@ -27,7 +29,8 @@ func (pv *ProjectionVisitor) ParseExpression(q *query.QueryExpression) error {
2729
return nil
2830
}
2931

30-
func (pv *ProjectionVisitor) OnEnterFunctionInvocation(name string) error {
32+
// OnEnterFunctionInvocation called when the EnterFunctionoInvocation is parsed. Name is the name of the function.
33+
func (pv *ProjectionVisitor) OnEnterFunctionInvocation(name string, distinct bool) error {
3134
if name == "COUNT" {
3235
pv.Aggregation = true
3336
pv.funcInvoc = true
@@ -51,6 +54,7 @@ func (pv *ProjectionVisitor) OnVariable(name string) error {
5154
default:
5255
pv.etype = PropertyExprType
5356
}
57+
5458
pv.TypeAndIndex = typeAndIndex
5559
return nil
5660
}
@@ -67,6 +71,5 @@ func (pv *ProjectionVisitor) OnExitPropertyOrLabelsExpression(e query.QueryPrope
6771
pv.ExpressionType = pv.etype
6872
}
6973
pv.properties = nil
70-
pv.funcInvoc = false
7174
return nil
7275
}

internal/knowledge/query_sql_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ UNION
116116
(SELECT a1.value FROM assets a0, assets a1, relations r0
117117
WHERE ((a0.type = 'variable' AND a1.type = 'name') AND (r0.from_id = a1.id AND r0.to_id = a0.id)))
118118
LIMIT 10`,
119+
},
120+
QueryCase{
121+
Cypher: "MATCH (v:variable)-[r]-(n:name) RETURN v.name, COUNT(DISTINCT n.name)",
122+
SQL: `
123+
SELECT a0.name, COUNT(DISTINCT a1.name) FROM
124+
((SELECT a0.name, COUNT(DISTINCT a1.name) FROM assets a0, assets a1, relations r0
125+
WHERE ((a0.type = 'variable' AND a1.type = 'name') AND (r0.from_id = a0.id AND r0.to_id = a1.id)))
126+
UNION ALL
127+
(SELECT a0.name, COUNT(DISTINCT a1.name) FROM assets a0, assets a1, relations r0
128+
WHERE ((a0.type = 'variable' AND a1.type = 'name') AND (r0.from_id = a1.id AND r0.to_id = a0.id))))
129+
GROUP BY a0.name`,
119130
},
120131
QueryCase{
121132
Cypher: "MATCH (v)-[r]-(n) RETURN n LIMIT 10",

internal/query/query.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,11 +578,16 @@ func (cl *BaseCypherVisitor) VisitOC_ParenthesizedExpression(c *parser.OC_Parent
578578
type QueryFunctionInvocation struct {
579579
FunctionName string
580580
Expressions []QueryExpression
581+
Distinct bool
581582
}
582583

583584
func (cl *BaseCypherVisitor) VisitOC_FunctionInvocation(c *parser.OC_FunctionInvocationContext) interface{} {
584585
q := QueryFunctionInvocation{}
585586
expressions := make([]QueryExpression, 0)
587+
if c.DISTINCT() != nil {
588+
q.Distinct = true
589+
}
590+
586591
for i := range c.AllOC_Expression() {
587592
expressions = append(expressions, c.OC_Expression(i).Accept(cl).(QueryExpression))
588593
}

0 commit comments

Comments
 (0)