123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /*
- * 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 interpreter contains the GraphQL interpreter for EliasDB.
- */
- package interpreter
- import (
- "fmt"
- "sort"
- "strconv"
- "devt.de/krotik/common/lang/graphql/parser"
- )
- // Not Implemented Runtime
- // =======================
- /*
- Special runtime for not implemented constructs.
- */
- type invalidRuntime struct {
- rtp *GraphQLRuntimeProvider
- node *parser.ASTNode
- }
- /*
- invalidRuntimeInst returns a new runtime component instance.
- */
- func invalidRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
- return &invalidRuntime{rtp, node}
- }
- /*
- Validate this node and all its child nodes.
- */
- func (rt *invalidRuntime) Validate() error {
- return rt.rtp.newFatalRuntimeError(ErrInvalidConstruct, rt.node.Name, rt.node)
- }
- /*
- Eval evaluate this runtime component.
- */
- func (rt *invalidRuntime) Eval() (map[string]interface{}, error) {
- return nil, rt.rtp.newFatalRuntimeError(ErrInvalidConstruct, rt.node.Name, rt.node)
- }
- // Value Runtime
- // =============
- /*
- Special runtime for values.
- */
- type valueRuntime struct {
- *invalidRuntime
- rtp *GraphQLRuntimeProvider
- node *parser.ASTNode
- }
- /*
- valueRuntimeInst returns a new runtime component instance.
- */
- func valueRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
- return &valueRuntime{&invalidRuntime{rtp, node}, rtp, node}
- }
- /*
- Value returns the calculated value of the expression.
- */
- func (rt *valueRuntime) Value() interface{} {
- if rt.node.Name == parser.NodeVariable {
- val, ok := rt.rtp.VariableValues[rt.node.Token.Val]
- if !ok {
- rt.rtp.handleRuntimeError(fmt.Errorf(
- "Variable %s was used but not declared", rt.node.Token.Val),
- []string{}, rt.node)
- }
- return val
- } else if rt.node.Name == parser.NodeValue || rt.node.Name == parser.NodeDefaultValue {
- val := rt.node.Token.Val
- if rt.node.Token.ID == parser.TokenIntValue {
- i, _ := strconv.ParseInt(val, 10, 64)
- return i
- } else if rt.node.Token.ID == parser.TokenFloatValue {
- f, _ := strconv.ParseFloat(val, 64)
- return f
- } else if rt.node.Token.ID == parser.TokenStringValue {
- return rt.node.Token.Val
- } else if val == "true" {
- return true
- } else if val == "false" {
- return false
- } else if val == "null" {
- return nil
- }
- } else if rt.node.Name == parser.NodeObjectValue {
- res := make(map[string]interface{})
- for _, c := range rt.node.Children {
- res[c.Token.Val] = c.Children[0].Runtime.(*valueRuntime).Value()
- }
- return res
- } else if rt.node.Name == parser.NodeListValue {
- res := make([]interface{}, 0)
- for _, c := range rt.node.Children {
- res = append(res, c.Runtime.(*valueRuntime).Value())
- }
- return res
- }
- // Default (e.g. enum type)
- return rt.node.Token.Val
- }
- // Data sorting
- // ============
- /*
- dataSort sorts a list of maps.
- */
- func dataSort(list []map[string]interface{}, attr string, ascending bool) {
- sort.Sort(&DataSlice{list, attr, ascending})
- }
- /*
- DataSlice attaches the methods of sort.Interface to []map[string]interface{},
- sorting in ascending or descending order by a given attribute.
- */
- type DataSlice struct {
- data []map[string]interface{}
- attr string
- ascending bool
- }
- /*
- Len belongs to the sort.Interface.
- */
- func (d DataSlice) Len() int { return len(d.data) }
- /*
- Less belongs to the sort.Interface.
- */
- func (d DataSlice) Less(i, j int) bool {
- ia, ok1 := d.data[i][d.attr]
- ja, ok2 := d.data[j][d.attr]
- if ok1 && ok2 {
- if d.ascending {
- return fmt.Sprint(ia) < fmt.Sprint(ja)
- }
- return fmt.Sprint(ia) > fmt.Sprint(ja)
- }
- return false
- }
- /*
- Swap belongs to the sort.Interface.
- */
- func (d DataSlice) Swap(i, j int) {
- d.data[i], d.data[j] = d.data[j], d.data[i]
- }
|