helpers.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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. /*
  11. Package interpreter contains the GraphQL interpreter for EliasDB.
  12. */
  13. package interpreter
  14. import (
  15. "fmt"
  16. "sort"
  17. "strconv"
  18. "devt.de/krotik/common/lang/graphql/parser"
  19. )
  20. // Not Implemented Runtime
  21. // =======================
  22. /*
  23. Special runtime for not implemented constructs.
  24. */
  25. type invalidRuntime struct {
  26. rtp *GraphQLRuntimeProvider
  27. node *parser.ASTNode
  28. }
  29. /*
  30. invalidRuntimeInst returns a new runtime component instance.
  31. */
  32. func invalidRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  33. return &invalidRuntime{rtp, node}
  34. }
  35. /*
  36. Validate this node and all its child nodes.
  37. */
  38. func (rt *invalidRuntime) Validate() error {
  39. return rt.rtp.newFatalRuntimeError(ErrInvalidConstruct, rt.node.Name, rt.node)
  40. }
  41. /*
  42. Eval evaluate this runtime component.
  43. */
  44. func (rt *invalidRuntime) Eval() (map[string]interface{}, error) {
  45. return nil, rt.rtp.newFatalRuntimeError(ErrInvalidConstruct, rt.node.Name, rt.node)
  46. }
  47. // Value Runtime
  48. // =============
  49. /*
  50. Special runtime for values.
  51. */
  52. type valueRuntime struct {
  53. *invalidRuntime
  54. rtp *GraphQLRuntimeProvider
  55. node *parser.ASTNode
  56. }
  57. /*
  58. valueRuntimeInst returns a new runtime component instance.
  59. */
  60. func valueRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  61. return &valueRuntime{&invalidRuntime{rtp, node}, rtp, node}
  62. }
  63. /*
  64. Value returns the calculated value of the expression.
  65. */
  66. func (rt *valueRuntime) Value() interface{} {
  67. if rt.node.Name == parser.NodeVariable {
  68. val, ok := rt.rtp.VariableValues[rt.node.Token.Val]
  69. if !ok {
  70. rt.rtp.handleRuntimeError(fmt.Errorf(
  71. "Variable %s was used but not declared", rt.node.Token.Val),
  72. []string{}, rt.node)
  73. }
  74. return val
  75. } else if rt.node.Name == parser.NodeValue || rt.node.Name == parser.NodeDefaultValue {
  76. val := rt.node.Token.Val
  77. if rt.node.Token.ID == parser.TokenIntValue {
  78. i, _ := strconv.ParseInt(val, 10, 64)
  79. return i
  80. } else if rt.node.Token.ID == parser.TokenFloatValue {
  81. f, _ := strconv.ParseFloat(val, 64)
  82. return f
  83. } else if rt.node.Token.ID == parser.TokenStringValue {
  84. return rt.node.Token.Val
  85. } else if val == "true" {
  86. return true
  87. } else if val == "false" {
  88. return false
  89. } else if val == "null" {
  90. return nil
  91. }
  92. } else if rt.node.Name == parser.NodeObjectValue {
  93. res := make(map[string]interface{})
  94. for _, c := range rt.node.Children {
  95. res[c.Token.Val] = c.Children[0].Runtime.(*valueRuntime).Value()
  96. }
  97. return res
  98. } else if rt.node.Name == parser.NodeListValue {
  99. res := make([]interface{}, 0)
  100. for _, c := range rt.node.Children {
  101. res = append(res, c.Runtime.(*valueRuntime).Value())
  102. }
  103. return res
  104. }
  105. // Default (e.g. enum type)
  106. return rt.node.Token.Val
  107. }
  108. // Data sorting
  109. // ============
  110. /*
  111. dataSort sorts a list of maps.
  112. */
  113. func dataSort(list []map[string]interface{}, attr string, ascending bool) {
  114. sort.Sort(&DataSlice{list, attr, ascending})
  115. }
  116. /*
  117. DataSlice attaches the methods of sort.Interface to []map[string]interface{},
  118. sorting in ascending or descending order by a given attribute.
  119. */
  120. type DataSlice struct {
  121. data []map[string]interface{}
  122. attr string
  123. ascending bool
  124. }
  125. /*
  126. Len belongs to the sort.Interface.
  127. */
  128. func (d DataSlice) Len() int { return len(d.data) }
  129. /*
  130. Less belongs to the sort.Interface.
  131. */
  132. func (d DataSlice) Less(i, j int) bool {
  133. ia, ok1 := d.data[i][d.attr]
  134. ja, ok2 := d.data[j][d.attr]
  135. if ok1 && ok2 {
  136. if d.ascending {
  137. return fmt.Sprint(ia) < fmt.Sprint(ja)
  138. }
  139. return fmt.Sprint(ia) > fmt.Sprint(ja)
  140. }
  141. return false
  142. }
  143. /*
  144. Swap belongs to the sort.Interface.
  145. */
  146. func (d DataSlice) Swap(i, j int) {
  147. d.data[i], d.data[j] = d.data[j], d.data[i]
  148. }