1
0
mirror of https://github.com/MontFerret/ferret.git synced 2024-12-12 11:15:14 +02:00

Added DISTINCT clause as an iterator

This commit is contained in:
Tim Voronov 2018-10-07 01:23:35 -04:00
parent e0a7a8e6a1
commit 3f1ca554e2
3 changed files with 53 additions and 36 deletions

View File

@ -192,6 +192,7 @@ func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *sco
var spread bool
var distinct bool
var distinctSrc core.SourceMap
forRetCtx := ctx.ForExpressionReturn().(*fql.ForExpressionReturnContext)
returnCtx := forRetCtx.ReturnExpression()
@ -203,7 +204,13 @@ func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *sco
return nil, err
}
distinct = returnCtx.Distinct() != nil
distinctCtx := returnCtx.Distinct()
if distinctCtx != nil {
distinct = true
token := distinctCtx.GetSymbol()
distinctSrc = core.NewSourceMap(token.GetText(), token.GetLine(), token.GetColumn())
}
predicate.Add(returnExp)
} else {
@ -225,7 +232,6 @@ func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *sco
keyVarName,
src,
predicate,
distinct,
spread,
)
@ -233,6 +239,10 @@ func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *sco
return nil, err
}
if distinct {
forExp.AddDistinct(distinctSrc)
}
for _, clause := range ctx.AllForExpressionClause() {
clause := clause.(*fql.ForExpressionClauseContext)

View File

@ -0,0 +1,28 @@
package clauses
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/collections"
"github.com/MontFerret/ferret/pkg/runtime/core"
)
type DistinctClause struct {
*baseClause
}
func NewDistinctClause(
src core.SourceMap,
dataSource collections.IterableExpression,
) *DistinctClause {
return &DistinctClause{&baseClause{src, dataSource}}
}
func (clause *DistinctClause) Iterate(ctx context.Context, scope *core.Scope) (collections.Iterator, error) {
src, err := clause.dataSource.Iterate(ctx, scope)
if err != nil {
return nil, err
}
return collections.NewUniqueIterator(src)
}

View File

@ -15,7 +15,6 @@ type ForExpression struct {
keyVar string
dataSource collections.IterableExpression
predicate core.Expression
distinct bool
spread bool
}
@ -25,7 +24,6 @@ func NewForExpression(
keyVar string,
dataSource collections.IterableExpression,
predicate core.Expression,
distinct bool,
spread bool,
) (*ForExpression, error) {
if valVar == "" {
@ -45,7 +43,6 @@ func NewForExpression(
valVar, keyVar,
dataSource,
predicate,
distinct,
spread,
}, nil
}
@ -62,6 +59,10 @@ func (e *ForExpression) AddSort(src core.SourceMap, sorters ...*clauses.SorterEx
e.dataSource = clauses.NewSortClause(src, e.dataSource, e.valVar, sorters...)
}
func (e *ForExpression) AddDistinct(src core.SourceMap) {
e.dataSource = clauses.NewDistinctClause(src, e.dataSource)
}
func (e *ForExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) {
iterator, err := e.dataSource.Iterate(ctx, scope)
@ -69,13 +70,6 @@ func (e *ForExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value
return values.None, err
}
// Hash map for a check for uniqueness
var hashes map[uint64]bool
if e.distinct {
hashes = make(map[uint64]bool)
}
res := values.NewArray(10)
for iterator.HasNext() {
@ -98,35 +92,20 @@ func (e *ForExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value
return values.None, err
}
var el core.Value
// The result shouldn't be distinct
// Just add the output
if !e.distinct {
el = out
if !e.spread {
res.Push(out)
} else {
// We need to check whether the value already exists in the result set
hash := out.Hash()
_, exists := hashes[hash]
elements, ok := out.(*values.Array)
if !exists {
hashes[hash] = true
el = out
if !ok {
return values.None, core.Error(core.ErrInvalidOperation, "spread of non-array value")
}
}
if el != nil {
if !e.spread {
res.Push(el)
} else {
elements := el.(*values.Array)
elements.ForEach(func(i core.Value, _ int) bool {
res.Push(i)
elements.ForEach(func(i core.Value, _ int) bool {
res.Push(i)
return true
})
}
return true
})
}
}