mirror of
https://github.com/MontFerret/ferret.git
synced 2025-07-17 01:32:22 +02:00
Added DISTINCT clause as an iterator
This commit is contained in:
@ -192,6 +192,7 @@ func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *sco
|
|||||||
|
|
||||||
var spread bool
|
var spread bool
|
||||||
var distinct bool
|
var distinct bool
|
||||||
|
var distinctSrc core.SourceMap
|
||||||
forRetCtx := ctx.ForExpressionReturn().(*fql.ForExpressionReturnContext)
|
forRetCtx := ctx.ForExpressionReturn().(*fql.ForExpressionReturnContext)
|
||||||
returnCtx := forRetCtx.ReturnExpression()
|
returnCtx := forRetCtx.ReturnExpression()
|
||||||
|
|
||||||
@ -203,7 +204,13 @@ func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *sco
|
|||||||
return nil, err
|
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)
|
predicate.Add(returnExp)
|
||||||
} else {
|
} else {
|
||||||
@ -225,7 +232,6 @@ func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *sco
|
|||||||
keyVarName,
|
keyVarName,
|
||||||
src,
|
src,
|
||||||
predicate,
|
predicate,
|
||||||
distinct,
|
|
||||||
spread,
|
spread,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -233,6 +239,10 @@ func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *sco
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if distinct {
|
||||||
|
forExp.AddDistinct(distinctSrc)
|
||||||
|
}
|
||||||
|
|
||||||
for _, clause := range ctx.AllForExpressionClause() {
|
for _, clause := range ctx.AllForExpressionClause() {
|
||||||
clause := clause.(*fql.ForExpressionClauseContext)
|
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
|
keyVar string
|
||||||
dataSource collections.IterableExpression
|
dataSource collections.IterableExpression
|
||||||
predicate core.Expression
|
predicate core.Expression
|
||||||
distinct bool
|
|
||||||
spread bool
|
spread bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +24,6 @@ func NewForExpression(
|
|||||||
keyVar string,
|
keyVar string,
|
||||||
dataSource collections.IterableExpression,
|
dataSource collections.IterableExpression,
|
||||||
predicate core.Expression,
|
predicate core.Expression,
|
||||||
distinct bool,
|
|
||||||
spread bool,
|
spread bool,
|
||||||
) (*ForExpression, error) {
|
) (*ForExpression, error) {
|
||||||
if valVar == "" {
|
if valVar == "" {
|
||||||
@ -45,7 +43,6 @@ func NewForExpression(
|
|||||||
valVar, keyVar,
|
valVar, keyVar,
|
||||||
dataSource,
|
dataSource,
|
||||||
predicate,
|
predicate,
|
||||||
distinct,
|
|
||||||
spread,
|
spread,
|
||||||
}, nil
|
}, 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...)
|
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) {
|
func (e *ForExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) {
|
||||||
iterator, err := e.dataSource.Iterate(ctx, scope)
|
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
|
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)
|
res := values.NewArray(10)
|
||||||
|
|
||||||
for iterator.HasNext() {
|
for iterator.HasNext() {
|
||||||
@ -98,28 +92,14 @@ func (e *ForExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value
|
|||||||
return values.None, err
|
return values.None, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var el core.Value
|
|
||||||
|
|
||||||
// The result shouldn't be distinct
|
|
||||||
// Just add the output
|
|
||||||
if !e.distinct {
|
|
||||||
el = out
|
|
||||||
} else {
|
|
||||||
// We need to check whether the value already exists in the result set
|
|
||||||
hash := out.Hash()
|
|
||||||
_, exists := hashes[hash]
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
hashes[hash] = true
|
|
||||||
el = out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if el != nil {
|
|
||||||
if !e.spread {
|
if !e.spread {
|
||||||
res.Push(el)
|
res.Push(out)
|
||||||
} else {
|
} else {
|
||||||
elements := el.(*values.Array)
|
elements, ok := out.(*values.Array)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return values.None, core.Error(core.ErrInvalidOperation, "spread of non-array value")
|
||||||
|
}
|
||||||
|
|
||||||
elements.ForEach(func(i core.Value, _ int) bool {
|
elements.ForEach(func(i core.Value, _ int) bool {
|
||||||
res.Push(i)
|
res.Push(i)
|
||||||
@ -128,7 +108,6 @@ func (e *ForExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user