selectionset.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  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. "regexp"
  14. "strconv"
  15. "strings"
  16. "devt.de/krotik/common/lang/graphql/parser"
  17. "devt.de/krotik/common/stringutil"
  18. "devt.de/krotik/eliasdb/graph"
  19. "devt.de/krotik/eliasdb/graph/data"
  20. )
  21. // SelectionSet Runtime
  22. // ====================
  23. /*
  24. Runtime for SelectionSets.
  25. */
  26. type selectionSetRuntime struct {
  27. *invalidRuntime
  28. rtp *GraphQLRuntimeProvider
  29. node *parser.ASTNode
  30. }
  31. /*
  32. selectionSetRuntimeInst returns a new runtime component instance.
  33. */
  34. func selectionSetRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  35. return &selectionSetRuntime{&invalidRuntime{rtp, node}, rtp, node}
  36. }
  37. /*
  38. Eval evaluate this runtime component.
  39. */
  40. func (rt *selectionSetRuntime) Eval() (map[string]interface{}, error) {
  41. var err error
  42. // Build result data
  43. res := make(map[string]interface{})
  44. for _, c := range rt.node.Children {
  45. // Lookup nodes
  46. if c.Name == parser.NodeField {
  47. field := c.Runtime.(*fieldRuntime)
  48. if field.Name() == "__schema" {
  49. // We have an introspection query - handle this one in a special way
  50. res[field.Alias()] = field.SelectionSetRuntime().ProcessIntrospection()
  51. } else if field.SelectionSetRuntime() != nil {
  52. nodes := field.SelectionSetRuntime().ProcessNodes([]string{field.Alias()},
  53. field.Name(), field.Arguments(), nil)
  54. res[field.Alias()] = nodes
  55. }
  56. }
  57. }
  58. return res, err
  59. }
  60. /*
  61. nodeIterator is an object which can iterate over nodes.
  62. */
  63. type nodeIterator interface {
  64. Next() (string, string)
  65. HasNext() bool
  66. Error() error
  67. }
  68. /*
  69. nodeKeyIteratorWrapper wraps around a normal node key iterator.
  70. */
  71. type nodeKeyIteratorWrapper struct {
  72. kind string
  73. *graph.NodeKeyIterator
  74. }
  75. func (ni *nodeKeyIteratorWrapper) Next() (string, string) {
  76. return ni.NodeKeyIterator.Next(), ni.kind
  77. }
  78. /*
  79. traversalIterator contains a traversal result.
  80. */
  81. type traversalIterator struct {
  82. index int
  83. nodeList []data.Node
  84. }
  85. func (ti *traversalIterator) Next() (string, string) {
  86. next := ti.nodeList[ti.index]
  87. ti.index++
  88. return next.Key(), next.Kind()
  89. }
  90. func (ti *traversalIterator) HasNext() bool {
  91. return ti.index < len(ti.nodeList)
  92. }
  93. func (ti *traversalIterator) Error() error {
  94. return nil
  95. }
  96. func (rt *selectionSetRuntime) checkArgs(path []string, args map[string]interface{}) {
  97. knownArgs := []string{"key", "matches", "traverse", "storeNode",
  98. "storeEdge", "removeNode", "removeEdge", "ascending", "descending",
  99. "from", "items", "last"}
  100. for arg := range args {
  101. if stringutil.IndexOf(arg, knownArgs) == -1 {
  102. rt.rtp.handleRuntimeError(fmt.Errorf("Unknown argument: %s", arg),
  103. path, rt.node)
  104. }
  105. }
  106. }
  107. /*
  108. ProcessNodes uses the selection set to lookup/store nodes. Kind is not set during a
  109. traversal.
  110. */
  111. func (rt *selectionSetRuntime) ProcessNodes(path []string, kind string,
  112. args map[string]interface{}, it nodeIterator) []map[string]interface{} {
  113. var from, items, last int
  114. var ascending, descending string
  115. var err error
  116. res := make([]map[string]interface{}, 0)
  117. // Get only the attributes which were specified
  118. attrs, aliasMap, traversalMap := rt.GetPlainFieldsAndAliases(path, kind)
  119. addToRes := func(node data.Node) error {
  120. var err error
  121. r := make(map[string]interface{})
  122. for alias, attr := range aliasMap {
  123. if err == nil {
  124. if traversal, ok := traversalMap[alias]; ok {
  125. nodes, _, err := rt.rtp.gm.TraverseMulti(rt.rtp.part,
  126. node.Key(), node.Kind(), traversal.spec, false)
  127. if err == nil {
  128. data.NodeSort(nodes)
  129. r[alias] = traversal.selectionSetRuntime.ProcessNodes(
  130. append(path, traversal.spec), "", traversal.args,
  131. &traversalIterator{0, nodes})
  132. }
  133. } else {
  134. r[alias] = node.Attr(attr)
  135. }
  136. }
  137. }
  138. if err == nil {
  139. res = append(res, r)
  140. }
  141. return err
  142. }
  143. // Check arguments
  144. rt.checkArgs(path, args)
  145. if it == nil {
  146. err = rt.handleMutationArgs(path, args, kind)
  147. }
  148. ascending, descending, from, items, last, err = rt.handleOutputArgs(args)
  149. if err == nil {
  150. if key, ok := args["key"]; ok && it == nil {
  151. var node data.Node
  152. // Lookup a single node
  153. if node, err = rt.rtp.FetchNode(rt.rtp.part, fmt.Sprint(key), kind); err == nil && node != nil {
  154. addToRes(node)
  155. }
  156. } else {
  157. matchesRegexMap := make(map[string]*regexp.Regexp)
  158. matchAttrs := make([]string, 0)
  159. // Handle matches expression
  160. matches, matchesOk := args["matches"]
  161. matchesMap, matchesMapOk := matches.(map[string]interface{})
  162. if matchesOk {
  163. if matchesMapOk {
  164. for k, v := range matchesMap {
  165. matchAttrs = append(matchAttrs, k)
  166. if re, rerr := regexp.Compile(fmt.Sprint(v)); rerr == nil {
  167. matchesRegexMap[k] = re
  168. } else {
  169. rt.rtp.handleRuntimeError(fmt.Errorf("Regex %s did not compile: %s", v, rerr.Error()),
  170. path, rt.node)
  171. }
  172. }
  173. } else {
  174. rt.rtp.handleRuntimeError(fmt.Errorf("Matches expression is not a map"),
  175. path, rt.node)
  176. }
  177. }
  178. // Lookup a list of nodes
  179. if it == nil {
  180. var kit *graph.NodeKeyIterator
  181. kit, err = rt.rtp.gm.NodeKeyIterator(rt.rtp.part, kind)
  182. if kit != nil {
  183. it = &nodeKeyIteratorWrapper{kind, kit}
  184. }
  185. }
  186. if it != nil && err == nil {
  187. for err == nil && it.HasNext() {
  188. var node data.Node
  189. if err = it.Error(); err == nil {
  190. nkey, nkind := it.Next()
  191. if kind == "" {
  192. // If the kind is not fixed we need to reevaluate the attributes
  193. // to query for every node
  194. attrs, aliasMap, traversalMap = rt.GetPlainFieldsAndAliases(path, nkind)
  195. }
  196. if node, err = rt.rtp.FetchNodePart(rt.rtp.part, nkey,
  197. nkind, append(attrs, matchAttrs...)); err == nil && node != nil {
  198. if matchesOk && !rt.matchNode(node, matchesRegexMap) {
  199. continue
  200. }
  201. err = addToRes(node)
  202. }
  203. }
  204. }
  205. }
  206. }
  207. // Check if the result should be sorted
  208. if err == nil {
  209. if _, aok := args["ascending"]; aok {
  210. dataSort(res, ascending, true)
  211. } else if _, dok := args["descending"]; dok {
  212. dataSort(res, descending, false)
  213. }
  214. }
  215. // Check if the result should be truncated
  216. if last > 0 && last < len(res) {
  217. res = res[len(res)-last:]
  218. }
  219. if from > 0 || items > 0 {
  220. if from >= len(res) {
  221. from = 0
  222. }
  223. if from+items > len(res) {
  224. res = res[from:]
  225. } else {
  226. res = res[from : from+items]
  227. }
  228. }
  229. }
  230. rt.rtp.handleRuntimeError(err, path, rt.node)
  231. return res
  232. }
  233. /*
  234. handleOutputModifyingArgs handles arguments which modify the output presentation.
  235. */
  236. func (rt *selectionSetRuntime) handleOutputArgs(args map[string]interface{}) (string, string, int, int, int, error) {
  237. var from, items, last int
  238. var ascending, descending string
  239. var err error
  240. ascendingData, aok := args["ascending"]
  241. descendingData, dok := args["descending"]
  242. if aok && dok {
  243. err = fmt.Errorf("Cannot specify ascending and descending sorting")
  244. } else if aok {
  245. ascending = fmt.Sprint(ascendingData)
  246. } else {
  247. descending = fmt.Sprint(descendingData)
  248. }
  249. if err == nil {
  250. if lastText, ok := args["last"]; ok {
  251. last, err = strconv.Atoi(fmt.Sprint(lastText))
  252. }
  253. }
  254. if err == nil {
  255. if fromText, ok := args["from"]; ok {
  256. from, err = strconv.Atoi(fmt.Sprint(fromText))
  257. }
  258. }
  259. if err == nil {
  260. if itemsText, ok := args["items"]; ok {
  261. items, err = strconv.Atoi(fmt.Sprint(itemsText))
  262. }
  263. }
  264. return ascending, descending, from, items, last, err
  265. }
  266. /*
  267. handleMutationArgs handles node and edge insertion and removal.
  268. */
  269. func (rt *selectionSetRuntime) handleMutationArgs(path []string, args map[string]interface{}, kind string) error {
  270. var err error
  271. if toStore, ok := args["storeNode"]; ok && rt.rtp.CheckWritePermission(path, rt.node) {
  272. toStoreMap, ok := toStore.(map[string]interface{})
  273. if ok {
  274. // Handle mutations of nodes
  275. node := data.NewGraphNodeFromMap(toStoreMap)
  276. if node.Kind() == "" {
  277. node.SetAttr("kind", kind)
  278. }
  279. err = rt.rtp.gm.StoreNode(rt.rtp.part, node)
  280. } else {
  281. rt.rtp.handleRuntimeError(fmt.Errorf("Object required for node attributes and values"),
  282. path, rt.node)
  283. }
  284. }
  285. if toRemove, ok := args["removeNode"]; ok && rt.rtp.CheckWritePermission(path, rt.node) {
  286. toRemoveMap, ok := toRemove.(map[string]interface{})
  287. if ok {
  288. // Handle removal of nodes
  289. node := data.NewGraphNodeFromMap(toRemoveMap)
  290. if node.Kind() == "" {
  291. node.SetAttr("kind", kind)
  292. }
  293. _, err = rt.rtp.gm.RemoveNode(rt.rtp.part, node.Key(), node.Kind())
  294. } else {
  295. rt.rtp.handleRuntimeError(fmt.Errorf("Object required for node key and kind"),
  296. path, rt.node)
  297. }
  298. }
  299. if toStore, ok := args["storeEdge"]; err == nil && ok && rt.rtp.CheckWritePermission(path, rt.node) {
  300. toStoreMap, ok := toStore.(map[string]interface{})
  301. if ok {
  302. // Handle mutations of edges
  303. node := data.NewGraphEdgeFromNode(data.NewGraphNodeFromMap(toStoreMap))
  304. err = rt.rtp.gm.StoreEdge(rt.rtp.part, node)
  305. } else {
  306. rt.rtp.handleRuntimeError(fmt.Errorf("Object required for edge attributes and values"),
  307. path, rt.node)
  308. }
  309. }
  310. if toRemove, ok := args["removeEdge"]; err == nil && ok && rt.rtp.CheckWritePermission(path, rt.node) {
  311. toRemoveMap, ok := toRemove.(map[string]interface{})
  312. if ok {
  313. // Handle mutations of edges
  314. node := data.NewGraphEdgeFromNode(data.NewGraphNodeFromMap(toRemoveMap))
  315. _, err = rt.rtp.gm.RemoveEdge(rt.rtp.part, node.Key(), node.Kind())
  316. } else {
  317. rt.rtp.handleRuntimeError(fmt.Errorf("Object required for edge key and kind"),
  318. path, rt.node)
  319. }
  320. }
  321. return err
  322. }
  323. /*
  324. matchNode matches a given node against a given node template. Returns true if
  325. the template matches, false otherwise.
  326. */
  327. func (rt *selectionSetRuntime) matchNode(node data.Node, nodeTemplate map[string]*regexp.Regexp) bool {
  328. nodeData := node.Data()
  329. for k, v := range nodeTemplate {
  330. // Check if the match query should be negated
  331. negate := false
  332. if strings.HasPrefix(k, "not_") {
  333. k = k[4:]
  334. negate = true
  335. }
  336. mapAttr, ok := nodeData[k]
  337. if !ok {
  338. return false // Attribute does not exist
  339. }
  340. if negate {
  341. if v.MatchString(fmt.Sprint(mapAttr)) {
  342. return false // Attribute is the same
  343. }
  344. } else {
  345. if !v.MatchString(fmt.Sprint(mapAttr)) {
  346. return false // Attribute is not the same
  347. }
  348. }
  349. }
  350. return true
  351. }
  352. /*
  353. traversal captures all required data for a traversal during node lookup.
  354. */
  355. type traversal struct {
  356. spec string
  357. args map[string]interface{}
  358. selectionSetRuntime *selectionSetRuntime
  359. }
  360. /*
  361. fragmentRuntime is the common interface for all fragment runtimes.
  362. */
  363. type fragmentRuntime interface {
  364. TypeCondition() string
  365. SelectionSet() *parser.ASTNode
  366. }
  367. /*
  368. GetPlainFieldsAndAliases returns all fields as a list of node attributes, a map of
  369. aliases to names and a map from aliases to traversals.
  370. */
  371. func (rt *selectionSetRuntime) GetPlainFieldsAndAliases(path []string, kind string) (
  372. []string, map[string]string, map[string]*traversal) {
  373. errMultiFields := make([]string, 0)
  374. resList := []string{"key", "kind"}
  375. resMap := make(map[string]string)
  376. traversalMap := make(map[string]*traversal)
  377. fieldList := append(rt.node.Children[:0:0], rt.node.Children...) // Copy into new slice
  378. for i := 0; i < len(fieldList); i++ {
  379. var lastChild *parser.ASTNode
  380. c := fieldList[i]
  381. if len(c.Children) > 0 {
  382. lastChild = c.Children[len(c.Children)-1]
  383. }
  384. // Check for skip and include directive
  385. if rt.skipField(path, c) {
  386. continue
  387. }
  388. if c.Name == parser.NodeField {
  389. // Handle simple fields
  390. field := c.Runtime.(*fieldRuntime)
  391. if _, ok := resMap[field.Alias()]; ok {
  392. // Alias was used before
  393. if stringutil.IndexOf(field.Alias(), errMultiFields) == -1 {
  394. errMultiFields = append(errMultiFields, field.Alias())
  395. }
  396. continue
  397. }
  398. // Map alias to name and process the field
  399. resMap[field.Alias()] = field.Name()
  400. if lastChild.Name == parser.NodeSelectionSet {
  401. args := field.Arguments()
  402. // Handle traversals
  403. if spec, ok := args["traverse"]; ok {
  404. traversalMap[field.Alias()] = &traversal{
  405. spec: fmt.Sprint(spec),
  406. args: args,
  407. selectionSetRuntime: field.SelectionSetRuntime(),
  408. }
  409. } else {
  410. rt.rtp.handleRuntimeError(fmt.Errorf(
  411. "Traversal argument is missing"), path, c)
  412. }
  413. } else if stringutil.IndexOf(field.Name(), resList) == -1 {
  414. // Handle normal attribute lookup
  415. resList = append(resList, field.Name())
  416. }
  417. } else if c.Name == parser.NodeFragmentSpread || c.Name == parser.NodeInlineFragment {
  418. var fd fragmentRuntime
  419. if c.Name == parser.NodeFragmentSpread {
  420. // Lookup fragment spreads
  421. fd = rt.rtp.fragments[c.Token.Val]
  422. } else {
  423. // Construct inline fragments
  424. fd = c.Runtime.(*inlineFragmentDefinitionRuntime)
  425. }
  426. if fd.TypeCondition() != kind {
  427. // Type condition was not met - just skip the fragment
  428. continue
  429. }
  430. ss := fd.SelectionSet()
  431. fieldList = append(fieldList, ss.Children...)
  432. }
  433. }
  434. if len(errMultiFields) > 0 {
  435. for _, name := range errMultiFields {
  436. rt.rtp.handleRuntimeError(fmt.Errorf(
  437. "Field identifier %s used multiple times", name),
  438. path, rt.node)
  439. }
  440. }
  441. return resList, resMap, traversalMap
  442. }
  443. /*
  444. skipField checks if a given field has a skip or include directive and returns
  445. if the directive excludes the field.
  446. */
  447. func (rt *selectionSetRuntime) skipField(path []string, node *parser.ASTNode) bool {
  448. for _, c := range node.Children {
  449. if c.Name == parser.NodeDirectives {
  450. for _, directive := range c.Children {
  451. rt := directive.Runtime.(*argumentExpressionRuntime)
  452. name := rt.Name()
  453. args := rt.Arguments()
  454. if name == "skip" || name == "include" {
  455. if cond, ok := args["if"]; ok {
  456. if name == "skip" {
  457. skip, _ := strconv.ParseBool(fmt.Sprint(cond))
  458. return skip
  459. }
  460. include, _ := strconv.ParseBool(fmt.Sprint(cond))
  461. return !include
  462. }
  463. rt.rtp.handleRuntimeError(fmt.Errorf(
  464. "Directive %s is missing the 'if' argument", name), path, c)
  465. }
  466. }
  467. }
  468. }
  469. return false
  470. }
  471. // ArgumentExpression Runtime
  472. // ==========================
  473. /*
  474. Runtime for expressions with arguments.
  475. */
  476. type argumentExpressionRuntime struct {
  477. *invalidRuntime
  478. rtp *GraphQLRuntimeProvider
  479. node *parser.ASTNode
  480. }
  481. /*
  482. argumentExpressionRuntimeInst returns a new runtime component instance.
  483. */
  484. func argumentExpressionRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  485. return &argumentExpressionRuntime{&invalidRuntime{rtp, node}, rtp, node}
  486. }
  487. /*
  488. Name returns the name of this field.
  489. */
  490. func (rt *argumentExpressionRuntime) Name() string {
  491. if rt.node.Children[0].Name == parser.NodeAlias {
  492. return rt.node.Children[1].Token.Val
  493. }
  494. return rt.node.Children[0].Token.Val
  495. }
  496. /*
  497. Arguments returns all arguments of the field as a map.
  498. */
  499. func (rt *argumentExpressionRuntime) Arguments() map[string]interface{} {
  500. res := make(map[string]interface{})
  501. for _, c := range rt.node.Children {
  502. if c.Name == parser.NodeArguments {
  503. for _, a := range c.Children {
  504. res[a.Children[0].Token.Val] = a.Children[1].Runtime.(*valueRuntime).Value()
  505. }
  506. }
  507. }
  508. return res
  509. }
  510. // Field Runtime
  511. // =============
  512. /*
  513. Runtime for Fields.
  514. */
  515. type fieldRuntime struct {
  516. *argumentExpressionRuntime
  517. rtp *GraphQLRuntimeProvider
  518. node *parser.ASTNode
  519. }
  520. /*
  521. fieldRuntimeInst returns a new runtime component instance.
  522. */
  523. func fieldRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  524. return &fieldRuntime{&argumentExpressionRuntime{&invalidRuntime{rtp, node},
  525. rtp, node}, rtp, node}
  526. }
  527. /*
  528. Alias returns the alias of this field.
  529. */
  530. func (rt *fieldRuntime) Alias() string {
  531. return rt.node.Children[0].Token.Val
  532. }
  533. /*
  534. SelectionSetRuntime returns the SelectionSet runtime of this field.
  535. */
  536. func (rt *fieldRuntime) SelectionSetRuntime() *selectionSetRuntime {
  537. res, _ := rt.node.Children[len(rt.node.Children)-1].Runtime.(*selectionSetRuntime)
  538. return res
  539. }