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:
parent
e0a7a8e6a1
commit
3f1ca554e2
@ -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)
|
||||
|
||||
|
28
pkg/runtime/expressions/clauses/distinct.go
Normal file
28
pkg/runtime/expressions/clauses/distinct.go
Normal 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)
|
||||
}
|
@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user