Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Adding sort method to query language #297

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions conformance/tests/ot_sort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from __future__ import absolute_import

import gripql

def test_sort_name(man):
errors = []

G = man.setGraph("swapi")

q = G.query().V().hasLabel("Character").sort( "name" )
last = ""
for row in q:
#print(row)
if row["data"]["name"] < last:
errors.append("incorrect sort: %s < %s" % (row["data"]["name"], last))
last = row["data"]["name"]
return errors



def test_sort_units(man):
errors = []
G = man.setGraph("swapi")

q = G.query().V().hasLabel("Vehicle").sort( "max_atmosphering_speed" )
last = 0
for row in q:
#print(row)
value = row["data"]["max_atmosphering_speed"]
if value < last:
errors.append("incorrect sort: %s < %s" % (value, last))
last = value


q = G.query().V().hasLabel("Vehicle").sort( "max_atmosphering_speed", decending=True )
last = 1000000000
for row in q:
#print(row)
value = row["data"]["max_atmosphering_speed"]
if value > last:
errors.append("incorrect sort: %s > %s" % (value, last))
last = value

return errors

159 changes: 159 additions & 0 deletions engine/core/processors_sort.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package core

import (
"context"
"reflect"
"slices"

"github.com/bmeg/grip/gdbi"
"github.com/bmeg/grip/gripql"
"github.com/bmeg/grip/log"
)

// Sort rows
type Sort struct {
sortFields []*gripql.SortField
}

// compareAny compares two variables of any type.
func compareAny(a, b any) int {

if a == nil && b != nil {
return -1
} else if a != nil && b == nil {
return 1
} else if a == nil && b == nil {
return 0
}

// Get the types of the variables.
ta := reflect.TypeOf(a)
tb := reflect.TypeOf(b)

// If the types are not the same, return a comparison based on type names.
if ta != tb {
return int(ta.Kind()) - int(tb.Kind())
}

// Compare values based on their types.
switch ta.Kind() {
case reflect.Int:
// Compare integer values.
return compareInts(a.(int), b.(int))
case reflect.Float64:
// Compare float values.
return compareFloats(a.(float64), b.(float64))
case reflect.String:
// Compare string values.
return compareStrings(a.(string), b.(string))
case reflect.Bool:
// Compare boolean values.
return compareBooleans(a.(bool), b.(bool))
case reflect.Struct:
// Optionally handle structs here.
// For now, just comparing based on memory address.
return comparePointers(a, b)
default:
// For unsupported types, we just use pointers for comparison.
log.Warningf("Unsupported types: %s %s", ta, tb)
return comparePointers(a, b)
}
}

// compareInts compares two integers.
func compareInts(a, b int) int {
if a < b {
return -1
} else if a > b {
return 1
}
return 0
}

// compareFloats compares two float64 values.
func compareFloats(a, b float64) int {
if a < b {
return -1
} else if a > b {
return 1
}
return 0
}

// compareStrings compares two string values.
func compareStrings(a, b string) int {
if a < b {
return -1
} else if a > b {
return 1
}
return 0
}

// compareBooleans compares two boolean values.
func compareBooleans(a, b bool) int {
if !a && b {
return -1
} else if a && !b {
return 1
}
return 0
}

// comparePointers compares two pointers.
func comparePointers(a, b interface{}) int {
ptrA := reflect.ValueOf(a).Pointer()
ptrB := reflect.ValueOf(b).Pointer()
if ptrA < ptrB {
return -1
} else if ptrA > ptrB {
return 1
}
return 0
}

func (s *Sort) compare(a, b gdbi.Traveler) int {
for _, f := range s.sortFields {
aVal := gdbi.TravelerPathLookup(a, f.Field)
bVal := gdbi.TravelerPathLookup(b, f.Field)
x := compareAny(aVal, bVal)
if x != 0 {
if f.Decending {
return -x
} else {
return x
}
}
}
return 0
}

// Process runs LookupEdges
func (s *Sort) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe, out gdbi.OutPipe) context.Context {

signals := []gdbi.Traveler{}

list := []gdbi.Traveler{}

go func() {
defer close(out)
for t := range in {
if t.IsSignal() {
signals = append(signals, t)
} else {
list = append(list, t) //TODO: develop disk backed system
}
}
slices.SortFunc(list, s.compare)
//emit signals first (?)
for _, s := range signals {
out <- s
}
for _, s := range list {
out <- s
}

}()

return ctx
}
4 changes: 4 additions & 0 deletions engine/core/statement_compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ func (sc *DefaultStmtCompiler) Aggregate(stmt *gripql.GraphStatement_Aggregate,
return &aggregate{stmt.Aggregate.Aggregations}, nil
}

func (sc *DefaultStmtCompiler) Sort(gs *gripql.GraphStatement_Sort, ps *gdbi.State) (gdbi.Processor, error) {
return &Sort{gs.Sort.Fields}, nil
}

func (sc *DefaultStmtCompiler) Custom(gs *gripql.GraphStatement, ps *gdbi.State) (gdbi.Processor, error) {

switch stmt := gs.GetStatement().(type) {
Expand Down
2 changes: 2 additions & 0 deletions gdbi/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,7 @@ type StatementCompiler interface {
Fields(gs *gripql.GraphStatement_Fields, ps *State) (Processor, error)
Aggregate(gs *gripql.GraphStatement_Aggregate, ps *State) (Processor, error)

Sort(gs *gripql.GraphStatement_Sort, ps *State) (Processor, error)

Custom(gs *gripql.GraphStatement, ps *State) (Processor, error)
}
4 changes: 4 additions & 0 deletions gdbi/statement_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ func StatementProcessor(
ps.LastType = AggregationData
return out, err

case *gripql.GraphStatement_Sort:
out, err := sc.Sort(stmt, ps)
return out, err

default:

return sc.Custom(gs, ps)
Expand Down
2 changes: 1 addition & 1 deletion gripper/gripper.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion gripper/gripper_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading