runtime.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  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. "fmt"
  13. "devt.de/krotik/common/errorutil"
  14. "devt.de/krotik/common/lang/graphql/parser"
  15. "devt.de/krotik/eliasdb/graph"
  16. )
  17. // Runtime definition
  18. // ==================
  19. /*
  20. Instance function for runtime components
  21. */
  22. type runtimeInst func(*GraphQLRuntimeProvider, *parser.ASTNode) parser.Runtime
  23. /*
  24. Runtime map for runtime components
  25. */
  26. var runtimeProviderMap = map[string]runtimeInst{
  27. parser.NodeEOF: invalidRuntimeInst,
  28. parser.NodeDocument: documentRuntimeInst,
  29. parser.NodeExecutableDefinition: executableDefinitionRuntimeInst,
  30. parser.NodeFragmentDefinition: fragmentDefinitionRuntimeInst,
  31. parser.NodeInlineFragment: inlineFragmentDefinitionRuntimeInst,
  32. parser.NodeOperationDefinition: operationDefinitionRuntimeInst,
  33. parser.NodeSelectionSet: selectionSetRuntimeInst,
  34. parser.NodeField: fieldRuntimeInst,
  35. parser.NodeDirective: argumentExpressionRuntimeInst,
  36. parser.NodeObjectValue: valueRuntimeInst,
  37. parser.NodeValue: valueRuntimeInst,
  38. parser.NodeDefaultValue: valueRuntimeInst,
  39. parser.NodeEnumValue: valueRuntimeInst,
  40. parser.NodeListValue: valueRuntimeInst,
  41. parser.NodeVariable: valueRuntimeInst,
  42. }
  43. // General runtime provider
  44. // ========================
  45. /*
  46. QueryType is a know GraphQL query type
  47. */
  48. type QueryType string
  49. /*
  50. All known query types
  51. */
  52. const (
  53. QueryTypeQuery QueryType = "query"
  54. QueryTypeMutation = "mutation"
  55. QueryTypeSubscription = "subscription"
  56. )
  57. /*
  58. GraphQLRuntimeProvider defines the main interpreter
  59. datastructure and all functions for general evaluation.
  60. */
  61. type GraphQLRuntimeProvider struct {
  62. Name string // Name to identify the input
  63. QueryType QueryType // Query type (query, mutation, subscription)
  64. OperationName string // Name of operation to execute
  65. VariableValues map[string]interface{} // Values of variables
  66. ErrorKeys []string // List of error hashes (used for deduplication)
  67. Errors []*RuntimeError // List of errors
  68. ErrorPaths [][]string // List of error paths
  69. part string // Graph partition to query
  70. gm *graph.Manager // GraphManager to operate on
  71. callbackHandler SubscriptionCallbackHandler // Subscription callback handler for updates
  72. subscriptionHandler *subscriptionHandler // Subscription handler forwarding event is the callback object
  73. readOnly bool // Flag if only read operations are allowed
  74. operation *parser.ASTNode // Operation to execute
  75. fragments map[string]*fragmentDefinitionRuntime // Fragment definitions
  76. }
  77. /*
  78. NewGraphQLRuntimeProvider creates a new GraphQLRuntimeProvider object.
  79. */
  80. func NewGraphQLRuntimeProvider(name string, part string, gm *graph.Manager,
  81. op string, vars map[string]interface{}, callbackHandler SubscriptionCallbackHandler,
  82. readOnly bool) *GraphQLRuntimeProvider {
  83. return &GraphQLRuntimeProvider{name, "", op, vars, []string{}, []*RuntimeError{},
  84. [][]string{}, part, gm, callbackHandler, nil, readOnly, nil,
  85. make(map[string]*fragmentDefinitionRuntime)}
  86. }
  87. /*
  88. CheckWritePermission checks if the current query is allowed to modify data.
  89. Returns true if data can be modified.
  90. */
  91. func (rtp *GraphQLRuntimeProvider) CheckWritePermission(path []string, node *parser.ASTNode) bool {
  92. if rtp.readOnly {
  93. rtp.handleRuntimeError(fmt.Errorf("Can only perform read operations"),
  94. path, node)
  95. return false
  96. }
  97. if rtp.QueryType != QueryTypeMutation {
  98. rtp.handleRuntimeError(fmt.Errorf("Operation must be a mutation to modify data"),
  99. path, node)
  100. return false
  101. }
  102. return true
  103. }
  104. /*
  105. Initialise data structures.
  106. */
  107. func (rtp *GraphQLRuntimeProvider) init() error {
  108. rtp.QueryType = ""
  109. rtp.operation = nil
  110. return nil
  111. }
  112. /*
  113. Runtime returns a runtime component for a given ASTNode.
  114. */
  115. func (rtp *GraphQLRuntimeProvider) Runtime(node *parser.ASTNode) parser.Runtime {
  116. if pinst, ok := runtimeProviderMap[node.Name]; ok {
  117. return pinst(rtp, node)
  118. }
  119. return invalidRuntimeInst(rtp, node)
  120. }
  121. /*
  122. TraverseAST traverses the AST starting with a given root and executes a given
  123. visitor function on each node. An accumulator is given to track state. A path
  124. is given to track selection sets.
  125. */
  126. func (rtp *GraphQLRuntimeProvider) TraverseAST(root *parser.ASTNode,
  127. visitor func(*parser.ASTNode)) {
  128. visitor(root)
  129. for _, child := range root.Children {
  130. rtp.TraverseAST(child, visitor)
  131. }
  132. }
  133. // Document Runtime
  134. // ================
  135. type documentRuntime struct {
  136. rtp *GraphQLRuntimeProvider
  137. node *parser.ASTNode
  138. }
  139. /*
  140. documentRuntimeInst creates a new document runtime instance.
  141. */
  142. func documentRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  143. return &documentRuntime{rtp, node}
  144. }
  145. /*
  146. Validate and reset this runtime component and all its child components.
  147. */
  148. func (rt *documentRuntime) Validate() error {
  149. err := rt.rtp.init()
  150. for _, c := range rt.node.Children {
  151. if err == nil {
  152. err = c.Runtime.Validate()
  153. }
  154. }
  155. if rt.rtp.operation == nil {
  156. // We didn't find an operation to execute
  157. if rt.rtp.OperationName == "" {
  158. err = rt.rtp.newFatalRuntimeError(ErrMissingOperation,
  159. "No executable expression found", rt.node)
  160. } else {
  161. err = rt.rtp.newFatalRuntimeError(ErrMissingOperation,
  162. fmt.Sprintf("Operation %s not found", rt.rtp.OperationName), rt.node)
  163. }
  164. }
  165. if err == nil && rt.rtp.QueryType == "" {
  166. rt.rtp.QueryType = QueryTypeQuery
  167. }
  168. if err == nil {
  169. // Check variables - types are not checked
  170. ort := rt.rtp.operation.Runtime.(*operationDefinitionRuntime)
  171. declared, defaultValues, _ := ort.DeclaredVariables()
  172. // Build up variable values
  173. vals := rt.rtp.VariableValues
  174. rt.rtp.VariableValues = make(map[string]interface{})
  175. for _, name := range declared {
  176. val, ok := vals[name]
  177. if ok {
  178. rt.rtp.VariableValues[name] = val
  179. } else {
  180. rt.rtp.VariableValues[name] = defaultValues[name]
  181. }
  182. }
  183. }
  184. if err == nil {
  185. // Collect fragment definitions
  186. rt.rtp.TraverseAST(rt.node, func(n *parser.ASTNode) {
  187. if err == nil && n.Name == parser.NodeFragmentDefinition {
  188. fr := n.Runtime.(*fragmentDefinitionRuntime)
  189. if _, ok := rt.rtp.fragments[fr.Name()]; ok {
  190. err = rt.rtp.newFatalRuntimeError(ErrAmbiguousDefinition,
  191. fmt.Sprintf("Fragment %s defined multiple times",
  192. fr.Name()), rt.node)
  193. }
  194. if err == nil {
  195. rt.rtp.fragments[fr.Name()] = fr
  196. }
  197. }
  198. })
  199. if err == nil {
  200. // Validate that all fragment spreads can be resolved
  201. rt.rtp.TraverseAST(rt.node, func(n *parser.ASTNode) {
  202. if err == nil && n.Name == parser.NodeFragmentSpread {
  203. name := n.Token.Val
  204. if _, ok := rt.rtp.fragments[name]; !ok {
  205. err = rt.rtp.newFatalRuntimeError(ErrInvalidConstruct,
  206. fmt.Sprintf("Fragment %s is not defined",
  207. name), rt.node)
  208. }
  209. }
  210. })
  211. }
  212. }
  213. return err
  214. }
  215. /*
  216. Eval evaluate this runtime component.
  217. */
  218. func (rt *documentRuntime) Eval() (map[string]interface{}, error) {
  219. var err error
  220. // First validate the query and reset the runtime provider datastructures
  221. if rt.rtp.QueryType == "" {
  222. if err = rt.Validate(); err != nil {
  223. return nil, err
  224. }
  225. }
  226. // Validate must have found the query type and the operation to execute
  227. errorutil.AssertTrue(rt.rtp.QueryType != "", "Unknown querytype")
  228. errorutil.AssertTrue(rt.rtp.operation != nil, "Unknown operation")
  229. if rt.rtp.QueryType == QueryTypeSubscription && rt.rtp.callbackHandler != nil {
  230. rt.rtp.InitSubscription(rt)
  231. }
  232. return rt.rtp.operation.Runtime.Eval()
  233. }
  234. // ExecutableDefinition Runtime
  235. // ============================
  236. type executableDefinitionRuntime struct {
  237. *invalidRuntime
  238. rtp *GraphQLRuntimeProvider
  239. node *parser.ASTNode
  240. }
  241. /*
  242. executableDefinitionRuntimeInst creates a new document runtime instance.
  243. */
  244. func executableDefinitionRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  245. return &executableDefinitionRuntime{&invalidRuntime{rtp, node}, rtp, node}
  246. }
  247. /*
  248. Validate and reset this runtime component and all its child components.
  249. */
  250. func (rt *executableDefinitionRuntime) Validate() error {
  251. if rt.rtp.operation == nil {
  252. // Choose an operation to execute
  253. if rt.node.Children[0].Name == parser.NodeOperationDefinition {
  254. if rt.rtp.OperationName == "" {
  255. // No operation name defined - take the first available operation
  256. rt.rtp.operation = rt.node.Children[0]
  257. // Check the operation type
  258. if rt.node.Children[0].Children[0].Name == parser.NodeOperationType {
  259. if rt.node.Children[0].Children[0].Token.Val == "mutation" {
  260. rt.rtp.QueryType = QueryTypeMutation
  261. } else if rt.node.Children[0].Children[0].Token.Val == "subscription" {
  262. rt.rtp.QueryType = QueryTypeSubscription
  263. }
  264. }
  265. } else {
  266. // If an operation name is defined we must not have a query shorthand
  267. if rt.node.Children[0].Children[0].Name == parser.NodeOperationType {
  268. name := rt.node.Children[0].Children[1].Token.Val
  269. if rt.rtp.OperationName == name {
  270. // We found the operation to execture
  271. if rt.node.Children[0].Children[0].Name == parser.NodeOperationType {
  272. // See what type it is
  273. if rt.node.Children[0].Children[0].Token.Val == "mutation" {
  274. rt.rtp.QueryType = QueryTypeMutation
  275. } else if rt.node.Children[0].Children[0].Token.Val == "subscription" {
  276. rt.rtp.QueryType = QueryTypeSubscription
  277. }
  278. }
  279. rt.rtp.operation = rt.node.Children[0]
  280. }
  281. }
  282. }
  283. }
  284. }
  285. return nil
  286. }
  287. // OperationDefinition Runtime
  288. // ============================
  289. type operationDefinitionRuntime struct {
  290. *invalidRuntime
  291. rtp *GraphQLRuntimeProvider
  292. node *parser.ASTNode
  293. }
  294. /*
  295. operationDefinitionRuntimeInst creates a new operation definition runtime instance.
  296. */
  297. func operationDefinitionRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  298. return &operationDefinitionRuntime{&invalidRuntime{rtp, node}, rtp, node}
  299. }
  300. /*
  301. Eval evaluate this runtime component.
  302. */
  303. func (rt *operationDefinitionRuntime) Eval() (map[string]interface{}, error) {
  304. res := make(map[string]interface{})
  305. // Execute the selection set
  306. data, err := rt.node.Children[len(rt.node.Children)-1].Runtime.Eval()
  307. res["data"] = data
  308. // Collect errors
  309. resErr := make([]map[string]interface{}, 0)
  310. for i, rterr := range rt.rtp.Errors {
  311. resErr = append(resErr, map[string]interface{}{
  312. "message": rterr.Detail,
  313. "locations": []map[string]interface{}{
  314. {
  315. "line": rterr.Line,
  316. "column": rterr.Pos,
  317. },
  318. },
  319. "path": rt.rtp.ErrorPaths[i],
  320. })
  321. }
  322. if len(resErr) > 0 {
  323. // Only add errors if there are any (@spec 7.1.2)
  324. res["errors"] = resErr
  325. }
  326. return res, err
  327. }
  328. /*
  329. DeclaredVariables returns all declared variables as list and their default
  330. values (if defined) and their type as maps.
  331. */
  332. func (rt *operationDefinitionRuntime) DeclaredVariables() ([]string, map[string]interface{}, map[string]string) {
  333. declared := make([]string, 0)
  334. defValues := make(map[string]interface{})
  335. types := make(map[string]string)
  336. for _, c := range rt.node.Children {
  337. if c.Name == parser.NodeVariableDefinitions {
  338. for _, vardef := range c.Children {
  339. name := vardef.Children[0].Token.Val
  340. declared = append(declared, name)
  341. if len(vardef.Children) > 2 {
  342. defValues[name] = vardef.Children[2].Runtime.(*valueRuntime).Value()
  343. }
  344. types[name] = vardef.Children[1].Token.Val
  345. }
  346. }
  347. }
  348. return declared, defValues, types
  349. }
  350. // FragmentDefinition Runtime
  351. // ==========================
  352. type fragmentDefinitionRuntime struct {
  353. *invalidRuntime
  354. rtp *GraphQLRuntimeProvider
  355. node *parser.ASTNode
  356. }
  357. /*
  358. fragmentDefinitionRuntimeInst creates a new fragment definition runtime instance.
  359. */
  360. func fragmentDefinitionRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  361. return &fragmentDefinitionRuntime{&invalidRuntime{rtp, node}, rtp, node}
  362. }
  363. /*
  364. Name returns the name of the fragment definition.
  365. */
  366. func (rt *fragmentDefinitionRuntime) Name() string {
  367. return rt.node.Children[0].Token.Val
  368. }
  369. /*
  370. TypeCondition returns the type condition of the fragment definition.
  371. */
  372. func (rt *fragmentDefinitionRuntime) TypeCondition() string {
  373. return rt.node.Children[1].Token.Val
  374. }
  375. /*
  376. SelectionSet returns the selection set of the fragment definition.
  377. */
  378. func (rt *fragmentDefinitionRuntime) SelectionSet() *parser.ASTNode {
  379. return rt.node.Children[len(rt.node.Children)-1]
  380. }
  381. // InlineFragmentDefinition Runtime
  382. // ================================
  383. type inlineFragmentDefinitionRuntime struct {
  384. *invalidRuntime
  385. rtp *GraphQLRuntimeProvider
  386. node *parser.ASTNode
  387. }
  388. /*
  389. fragmentDefinitionRuntimeInst creates a new inline fragment definition runtime instance.
  390. */
  391. func inlineFragmentDefinitionRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  392. return &inlineFragmentDefinitionRuntime{&invalidRuntime{rtp, node}, rtp, node}
  393. }
  394. /*
  395. TypeCondition returns the type condition of the inline fragment definition.
  396. */
  397. func (rt *inlineFragmentDefinitionRuntime) TypeCondition() string {
  398. return rt.node.Children[0].Token.Val
  399. }
  400. /*
  401. SelectionSet returns the selection set of the inline fragment definition.
  402. */
  403. func (rt *inlineFragmentDefinitionRuntime) SelectionSet() *parser.ASTNode {
  404. return rt.node.Children[len(rt.node.Children)-1]
  405. }