| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 | /* * EliasDB * * Copyright 2016 Matthias Ladkau. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */package interpreterimport (	"devt.de/krotik/eliasdb/eql/parser"	"devt.de/krotik/eliasdb/graph")// Runtime provider for GET queries// ================================/*Instance function for GET query components*/type getInst func(*GetRuntimeProvider, *parser.ASTNode) parser.Runtime/*Runtime map for GET query specific components*/var getProviderMap = map[string]getInst{	parser.NodeGET: getRuntimeInst,}/*GetRuntimeProvider data structure*/type GetRuntimeProvider struct {	*eqlRuntimeProvider}/*NewGetRuntimeProvider creates a new GetRuntimeProvider object. This providercan interpret GET queries.*/func NewGetRuntimeProvider(name string, part string, gm *graph.Manager, ni NodeInfo) *GetRuntimeProvider {	return &GetRuntimeProvider{&eqlRuntimeProvider{name, part, gm, ni, "", false, nil, "",		nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}}}/*Runtime returns a runtime component for a given ASTNode.*/func (rtp *GetRuntimeProvider) Runtime(node *parser.ASTNode) parser.Runtime {	if pinst, ok := generalProviderMap[node.Name]; ok {		return pinst(rtp.eqlRuntimeProvider, node)	} else if pinst, ok := getProviderMap[node.Name]; ok {		return pinst(rtp, node)	}	return invalidRuntimeInst(rtp.eqlRuntimeProvider, node)}// GET Runtime// ===========type getRuntime struct {	rtp  *GetRuntimeProvider	node *parser.ASTNode}func getRuntimeInst(rtp *GetRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &getRuntime{rtp, node}}/* Validate and reset this runtime component and all its child components.*/func (rt *getRuntime) Validate() error {	// First child is always the first node kind to query	// (validation of this value was done during lexing)	startKind := rt.node.Children[0].Token.Val	initErr := rt.rtp.init(startKind, rt.node.Children[1:])	if rt.rtp.groupScope == "" {		// Start keys can be provided by a simple node key iterator		startKeyIterator, err := rt.rtp.gm.NodeKeyIterator(rt.rtp.part, startKind)		if err != nil {			return err		} else if startKeyIterator == nil {			return rt.rtp.newRuntimeError(ErrUnknownNodeKind, startKind, rt.node.Children[0])		}		rt.rtp.nextStartKey = func() (string, error) {			nextKey := startKeyIterator.Next()			if startKeyIterator.LastError != nil {				return "", startKeyIterator.LastError			}			return nextKey, nil		}	} else {		// Try to lookup group node		nodes, _, err := rt.rtp.gm.TraverseMulti(rt.rtp.part, rt.rtp.groupScope,			GroupNodeKind, ":::"+startKind, false)		if err != nil {			return err		}		nodePtr := len(nodes)		// Iterate over all traversed nodes		rt.rtp.nextStartKey = func() (string, error) {			nodePtr--			if nodePtr >= 0 {				return nodes[nodePtr].Key(), nil			}			return "", nil		}	}	return initErr}/*Eval evaluate this runtime component.*/func (rt *getRuntime) Eval() (interface{}, error) {	// First validate the query and reset the runtime provider datastructures	if rt.rtp.specs == nil || !allowMultiEval {		if err := rt.Validate(); err != nil {			return nil, err		}	}	return rt.gaterResult(rt.node)}func (rt *getRuntime) gaterResult(topNode *parser.ASTNode) (interface{}, error) {	// Generate query	query, err := parser.PrettyPrint(topNode)	// Create result object	res := newSearchResult(rt.rtp.eqlRuntimeProvider, query)	if err == nil {		var more bool		// Go through all rows		more, err = rt.rtp.next()		for more && err == nil {			// Add row to the result			if err := res.addRow(rt.rtp.rowNode, rt.rtp.rowEdge); err != nil {				return nil, err			}			// More on to the next row			more, err = rt.rtp.next()		}		// Finish the result		res.finish()	}	return res, err}
 |