lookup.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package interpreter
  11. import (
  12. "devt.de/krotik/eliasdb/eql/parser"
  13. "devt.de/krotik/eliasdb/graph"
  14. )
  15. // Runtime provider for LOOKUP queries
  16. // ===================================
  17. /*
  18. Instance function for LOOKUP query components
  19. */
  20. type lookupInst func(*LookupRuntimeProvider, *parser.ASTNode) parser.Runtime
  21. /*
  22. Runtime map for LOOKUP query specific components
  23. */
  24. var lookupProviderMap = map[string]lookupInst{
  25. parser.NodeLOOKUP: lookupRuntimeInst,
  26. }
  27. /*
  28. LookupRuntimeProvider data structure
  29. */
  30. type LookupRuntimeProvider struct {
  31. *eqlRuntimeProvider
  32. }
  33. /*
  34. NewLookupRuntimeProvider creates a new LookupRuntimeProvider object. This provider
  35. can interpret LOOKUP queries.
  36. */
  37. func NewLookupRuntimeProvider(name string, part string, gm *graph.Manager, ni NodeInfo) *LookupRuntimeProvider {
  38. return &LookupRuntimeProvider{&eqlRuntimeProvider{name, part, gm, ni, "", false, nil, "",
  39. nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}}
  40. }
  41. /*
  42. Runtime returns a runtime component for a given ASTNode.
  43. */
  44. func (rtp *LookupRuntimeProvider) Runtime(node *parser.ASTNode) parser.Runtime {
  45. if pinst, ok := generalProviderMap[node.Name]; ok {
  46. return pinst(rtp.eqlRuntimeProvider, node)
  47. } else if pinst, ok := lookupProviderMap[node.Name]; ok {
  48. return pinst(rtp, node)
  49. }
  50. return invalidRuntimeInst(rtp.eqlRuntimeProvider, node)
  51. }
  52. // LOOKUP Runtime
  53. // ==============
  54. type lookupRuntime struct {
  55. *getRuntime
  56. rtp *LookupRuntimeProvider
  57. node *parser.ASTNode
  58. }
  59. func lookupRuntimeInst(rtp *LookupRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  60. return &lookupRuntime{&getRuntime{&GetRuntimeProvider{rtp.eqlRuntimeProvider}, node}, rtp, node}
  61. }
  62. /*
  63. Validate and reset this runtime component and all its child components.
  64. */
  65. func (rt *lookupRuntime) Validate() error {
  66. // First child is always the first node kind to query
  67. // (validation of this value was done during lexing)
  68. startKind := rt.node.Children[0].Token.Val
  69. // Check how many keys were given
  70. var keys []string
  71. // Assume initially that only keys where given
  72. initIndex := len(rt.node.Children) - 1
  73. for i, child := range rt.node.Children[1:] {
  74. if child.Token.ID != parser.TokenVALUE {
  75. // We have a first non-id child
  76. initIndex = i
  77. break
  78. } else {
  79. // Collect all given keys
  80. keys = append(keys, child.Token.Val)
  81. }
  82. }
  83. // Initialise the runtime provider
  84. initErr := rt.rtp.init(startKind, rt.node.Children[initIndex+1:])
  85. if rt.rtp.groupScope == "" {
  86. nodePtr := len(keys)
  87. if nodePtr > 0 {
  88. // Iterate over all traversed nodes
  89. rt.rtp.nextStartKey = func() (string, error) {
  90. nodePtr--
  91. if nodePtr >= 0 {
  92. return keys[nodePtr], nil
  93. }
  94. return "", nil
  95. }
  96. }
  97. } else {
  98. // Build a map of keys
  99. keyMap := make(map[string]string)
  100. for _, key := range keys {
  101. keyMap[key] = ""
  102. }
  103. // Try to lookup group node
  104. nodes, _, err := rt.rtp.gm.TraverseMulti(rt.rtp.part, rt.rtp.groupScope,
  105. GroupNodeKind, ":::"+startKind, false)
  106. if err != nil {
  107. return err
  108. }
  109. nodePtr := len(nodes)
  110. // Iterate over all traversed nodes
  111. rt.rtp.nextStartKey = func() (string, error) {
  112. nodePtr--
  113. if nodePtr >= 0 {
  114. nodeKey := nodes[nodePtr].Key()
  115. if _, ok := keyMap[nodeKey]; ok {
  116. return nodeKey, nil
  117. }
  118. return rt.rtp.nextStartKey()
  119. }
  120. return "", nil
  121. }
  122. }
  123. return initErr
  124. }
  125. /*
  126. Eval evaluate this runtime component.
  127. */
  128. func (rt *lookupRuntime) Eval() (interface{}, error) {
  129. if err := rt.Validate(); err != nil {
  130. return nil, err
  131. }
  132. return rt.getRuntime.gaterResult(rt.node)
  133. }