selectionset.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  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. if err == nil {
  149. ascending, descending, from, items, last, err = rt.handleOutputArgs(args)
  150. if err == nil {
  151. if key, ok := args["key"]; ok && it == nil {
  152. var node data.Node
  153. // Lookup a single node
  154. if node, err = rt.rtp.FetchNode(rt.rtp.part, fmt.Sprint(key), kind); err == nil && node != nil {
  155. addToRes(node)
  156. }
  157. } else {
  158. matchesRegexMap := make(map[string]*regexp.Regexp)
  159. matchAttrs := make([]string, 0)
  160. // Handle matches expression
  161. matches, matchesOk := args["matches"]
  162. matchesMap, matchesMapOk := matches.(map[string]interface{})
  163. if matchesOk {
  164. if matchesMapOk {
  165. for k, v := range matchesMap {
  166. matchAttrs = append(matchAttrs, k)
  167. if valueList, ok := v.([]interface{}); ok {
  168. stringList := make([]string, 0, len(valueList))
  169. // Shortcut for matching against multiple string values
  170. for _, val := range valueList {
  171. stringList = append(stringList, regexp.QuoteMeta(fmt.Sprint(val)))
  172. }
  173. v = fmt.Sprintf("^(%v)$", strings.Join(stringList, "|"))
  174. }
  175. if re, rerr := regexp.Compile(fmt.Sprint(v)); rerr == nil {
  176. matchesRegexMap[k] = re
  177. } else {
  178. rt.rtp.handleRuntimeError(fmt.Errorf("Regex %s did not compile: %s", v, rerr.Error()),
  179. path, rt.node)
  180. }
  181. }
  182. } else {
  183. rt.rtp.handleRuntimeError(fmt.Errorf("Matches expression is not a map"),
  184. path, rt.node)
  185. }
  186. }
  187. // Lookup a list of nodes
  188. if it == nil {
  189. var kit *graph.NodeKeyIterator
  190. kit, err = rt.rtp.gm.NodeKeyIterator(rt.rtp.part, kind)
  191. if kit != nil {
  192. it = &nodeKeyIteratorWrapper{kind, kit}
  193. }
  194. }
  195. if it != nil && err == nil {
  196. for err == nil && it.HasNext() {
  197. var node data.Node
  198. if err = it.Error(); err == nil {
  199. nkey, nkind := it.Next()
  200. if kind == "" {
  201. // If the kind is not fixed we need to reevaluate the attributes
  202. // to query for every node
  203. attrs, aliasMap, traversalMap = rt.GetPlainFieldsAndAliases(path, nkind)
  204. }
  205. if node, err = rt.rtp.FetchNodePart(rt.rtp.part, nkey,
  206. nkind, append(attrs, matchAttrs...)); err == nil && node != nil {
  207. if matchesOk && !rt.matchNode(node, matchesRegexMap) {
  208. continue
  209. }
  210. err = addToRes(node)
  211. }
  212. }
  213. }
  214. }
  215. }
  216. // Check if the result should be sorted
  217. if err == nil {
  218. if _, aok := args["ascending"]; aok {
  219. dataSort(res, ascending, true)
  220. } else if _, dok := args["descending"]; dok {
  221. dataSort(res, descending, false)
  222. }
  223. }
  224. // Check if the result should be truncated
  225. if last > 0 && last < len(res) {
  226. res = res[len(res)-last:]
  227. }
  228. if from > 0 || items > 0 {
  229. if from >= len(res) {
  230. from = 0
  231. }
  232. if from+items > len(res) {
  233. res = res[from:]
  234. } else {
  235. res = res[from : from+items]
  236. }
  237. }
  238. }
  239. }
  240. rt.rtp.handleRuntimeError(err, path, rt.node)
  241. return res
  242. }
  243. /*
  244. handleOutputModifyingArgs handles arguments which modify the output presentation.
  245. */
  246. func (rt *selectionSetRuntime) handleOutputArgs(args map[string]interface{}) (string, string, int, int, int, error) {
  247. var from, items, last int
  248. var ascending, descending string
  249. var err error
  250. ascendingData, aok := args["ascending"]
  251. descendingData, dok := args["descending"]
  252. if aok && dok {
  253. err = fmt.Errorf("Cannot specify ascending and descending sorting")
  254. } else if aok {
  255. ascending = fmt.Sprint(ascendingData)
  256. } else {
  257. descending = fmt.Sprint(descendingData)
  258. }
  259. if err == nil {
  260. if lastText, ok := args["last"]; ok {
  261. last, err = strconv.Atoi(fmt.Sprint(lastText))
  262. }
  263. }
  264. if err == nil {
  265. if fromText, ok := args["from"]; ok {
  266. from, err = strconv.Atoi(fmt.Sprint(fromText))
  267. }
  268. }
  269. if err == nil {
  270. if itemsText, ok := args["items"]; ok {
  271. items, err = strconv.Atoi(fmt.Sprint(itemsText))
  272. }
  273. }
  274. return ascending, descending, from, items, last, err
  275. }
  276. /*
  277. handleMutationArgs handles node and edge insertion and removal.
  278. */
  279. func (rt *selectionSetRuntime) handleMutationArgs(path []string, args map[string]interface{}, kind string) error {
  280. var err error
  281. if toStore, ok := args["storeNode"]; ok && rt.rtp.CheckWritePermission(path, rt.node) {
  282. toStoreMap, ok := toStore.(map[string]interface{})
  283. if ok {
  284. // Handle mutations of nodes
  285. node := data.NewGraphNodeFromMap(toStoreMap)
  286. if node.Kind() == "" {
  287. node.SetAttr("kind", kind)
  288. }
  289. err = rt.rtp.gm.StoreNode(rt.rtp.part, node)
  290. } else {
  291. rt.rtp.handleRuntimeError(fmt.Errorf("Object required for node attributes and values"),
  292. path, rt.node)
  293. }
  294. }
  295. if toRemove, ok := args["removeNode"]; ok && rt.rtp.CheckWritePermission(path, rt.node) {
  296. toRemoveMap, ok := toRemove.(map[string]interface{})
  297. if ok {
  298. // Handle removal of nodes
  299. node := data.NewGraphNodeFromMap(toRemoveMap)
  300. if node.Kind() == "" {
  301. node.SetAttr("kind", kind)
  302. }
  303. if node.Key() == "" {
  304. var it *graph.NodeKeyIterator
  305. if it, err = rt.rtp.gm.NodeKeyIterator(rt.rtp.part, node.Kind()); err == nil {
  306. var keys []string
  307. for it.HasNext() && err == nil {
  308. keys = append(keys, it.Next())
  309. err = it.Error()
  310. }
  311. if err == nil {
  312. for _, key := range keys {
  313. if err == nil {
  314. _, err = rt.rtp.gm.RemoveNode(rt.rtp.part, key, node.Kind())
  315. }
  316. }
  317. }
  318. }
  319. } else {
  320. _, err = rt.rtp.gm.RemoveNode(rt.rtp.part, node.Key(), node.Kind())
  321. }
  322. } else {
  323. rt.rtp.handleRuntimeError(fmt.Errorf("Object required for node key and kind"),
  324. path, rt.node)
  325. }
  326. }
  327. if toStore, ok := args["storeEdge"]; err == nil && ok && rt.rtp.CheckWritePermission(path, rt.node) {
  328. toStoreMap, ok := toStore.(map[string]interface{})
  329. if ok {
  330. // Handle mutations of edges
  331. node := data.NewGraphEdgeFromNode(data.NewGraphNodeFromMap(toStoreMap))
  332. err = rt.rtp.gm.StoreEdge(rt.rtp.part, node)
  333. } else {
  334. rt.rtp.handleRuntimeError(fmt.Errorf("Object required for edge attributes and values"),
  335. path, rt.node)
  336. }
  337. }
  338. if toRemove, ok := args["removeEdge"]; err == nil && ok && rt.rtp.CheckWritePermission(path, rt.node) {
  339. toRemoveMap, ok := toRemove.(map[string]interface{})
  340. if ok {
  341. // Handle mutations of edges
  342. node := data.NewGraphEdgeFromNode(data.NewGraphNodeFromMap(toRemoveMap))
  343. _, err = rt.rtp.gm.RemoveEdge(rt.rtp.part, node.Key(), node.Kind())
  344. } else {
  345. rt.rtp.handleRuntimeError(fmt.Errorf("Object required for edge key and kind"),
  346. path, rt.node)
  347. }
  348. }
  349. return err
  350. }
  351. /*
  352. matchNode matches a given node against a given node template. Returns true if
  353. the template matches, false otherwise.
  354. */
  355. func (rt *selectionSetRuntime) matchNode(node data.Node, nodeTemplate map[string]*regexp.Regexp) bool {
  356. nodeData := node.Data()
  357. for k, v := range nodeTemplate {
  358. // Check if the match query should be negated
  359. negate := false
  360. if strings.HasPrefix(k, "not_") {
  361. k = k[4:]
  362. negate = true
  363. }
  364. mapAttr, ok := nodeData[k]
  365. if !ok {
  366. return false // Attribute does not exist
  367. }
  368. if negate {
  369. if v.MatchString(fmt.Sprint(mapAttr)) {
  370. return false // Attribute is the same
  371. }
  372. } else {
  373. if !v.MatchString(fmt.Sprint(mapAttr)) {
  374. return false // Attribute is not the same
  375. }
  376. }
  377. }
  378. return true
  379. }
  380. /*
  381. traversal captures all required data for a traversal during node lookup.
  382. */
  383. type traversal struct {
  384. spec string
  385. args map[string]interface{}
  386. selectionSetRuntime *selectionSetRuntime
  387. }
  388. /*
  389. fragmentRuntime is the common interface for all fragment runtimes.
  390. */
  391. type fragmentRuntime interface {
  392. TypeCondition() string
  393. SelectionSet() *parser.ASTNode
  394. }
  395. /*
  396. GetPlainFieldsAndAliases returns all fields as a list of node attributes, a map of
  397. aliases to names and a map from aliases to traversals.
  398. */
  399. func (rt *selectionSetRuntime) GetPlainFieldsAndAliases(path []string, kind string) (
  400. []string, map[string]string, map[string]*traversal) {
  401. errMultiFields := make([]string, 0)
  402. resList := []string{"key", "kind"}
  403. resMap := make(map[string]string)
  404. traversalMap := make(map[string]*traversal)
  405. fieldList := append(rt.node.Children[:0:0], rt.node.Children...) // Copy into new slice
  406. for i := 0; i < len(fieldList); i++ {
  407. var lastChild *parser.ASTNode
  408. c := fieldList[i]
  409. if len(c.Children) > 0 {
  410. lastChild = c.Children[len(c.Children)-1]
  411. }
  412. // Check for skip and include directive
  413. if rt.skipField(path, c) {
  414. continue
  415. }
  416. if c.Name == parser.NodeField {
  417. // Handle simple fields
  418. field := c.Runtime.(*fieldRuntime)
  419. if _, ok := resMap[field.Alias()]; ok {
  420. // Alias was used before
  421. if stringutil.IndexOf(field.Alias(), errMultiFields) == -1 {
  422. errMultiFields = append(errMultiFields, field.Alias())
  423. }
  424. continue
  425. }
  426. // Map alias to name and process the field
  427. resMap[field.Alias()] = field.Name()
  428. if lastChild.Name == parser.NodeSelectionSet {
  429. args := field.Arguments()
  430. // Handle traversals
  431. if spec, ok := args["traverse"]; ok {
  432. traversalMap[field.Alias()] = &traversal{
  433. spec: fmt.Sprint(spec),
  434. args: args,
  435. selectionSetRuntime: field.SelectionSetRuntime(),
  436. }
  437. } else {
  438. // Shortcut to take the name as the traversal kind
  439. traversalMap[field.Alias()] = &traversal{
  440. spec: fmt.Sprintf(":::%v", field.Name()),
  441. args: args,
  442. selectionSetRuntime: field.SelectionSetRuntime(),
  443. }
  444. }
  445. } else if stringutil.IndexOf(field.Name(), resList) == -1 {
  446. // Handle normal attribute lookup
  447. resList = append(resList, field.Name())
  448. }
  449. } else if c.Name == parser.NodeFragmentSpread || c.Name == parser.NodeInlineFragment {
  450. var fd fragmentRuntime
  451. if c.Name == parser.NodeFragmentSpread {
  452. // Lookup fragment spreads
  453. fd = rt.rtp.fragments[c.Token.Val]
  454. } else {
  455. // Construct inline fragments
  456. fd = c.Runtime.(*inlineFragmentDefinitionRuntime)
  457. }
  458. if fd.TypeCondition() != kind {
  459. // Type condition was not met - just skip the fragment
  460. continue
  461. }
  462. ss := fd.SelectionSet()
  463. fieldList = append(fieldList, ss.Children...)
  464. }
  465. }
  466. if len(errMultiFields) > 0 {
  467. for _, name := range errMultiFields {
  468. rt.rtp.handleRuntimeError(fmt.Errorf(
  469. "Field identifier %s used multiple times", name),
  470. path, rt.node)
  471. }
  472. }
  473. return resList, resMap, traversalMap
  474. }
  475. /*
  476. skipField checks if a given field has a skip or include directive and returns
  477. if the directive excludes the field.
  478. */
  479. func (rt *selectionSetRuntime) skipField(path []string, node *parser.ASTNode) bool {
  480. for _, c := range node.Children {
  481. if c.Name == parser.NodeDirectives {
  482. for _, directive := range c.Children {
  483. rt := directive.Runtime.(*argumentExpressionRuntime)
  484. name := rt.Name()
  485. args := rt.Arguments()
  486. if name == "skip" || name == "include" {
  487. if cond, ok := args["if"]; ok {
  488. if name == "skip" {
  489. skip, _ := strconv.ParseBool(fmt.Sprint(cond))
  490. return skip
  491. }
  492. include, _ := strconv.ParseBool(fmt.Sprint(cond))
  493. return !include
  494. }
  495. rt.rtp.handleRuntimeError(fmt.Errorf(
  496. "Directive %s is missing the 'if' argument", name), path, c)
  497. }
  498. }
  499. }
  500. }
  501. return false
  502. }
  503. // ArgumentExpression Runtime
  504. // ==========================
  505. /*
  506. Runtime for expressions with arguments.
  507. */
  508. type argumentExpressionRuntime struct {
  509. *invalidRuntime
  510. rtp *GraphQLRuntimeProvider
  511. node *parser.ASTNode
  512. }
  513. /*
  514. argumentExpressionRuntimeInst returns a new runtime component instance.
  515. */
  516. func argumentExpressionRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  517. return &argumentExpressionRuntime{&invalidRuntime{rtp, node}, rtp, node}
  518. }
  519. /*
  520. Name returns the name of this field.
  521. */
  522. func (rt *argumentExpressionRuntime) Name() string {
  523. if rt.node.Children[0].Name == parser.NodeAlias {
  524. return rt.node.Children[1].Token.Val
  525. }
  526. return rt.node.Children[0].Token.Val
  527. }
  528. /*
  529. Arguments returns all arguments of the field as a map.
  530. */
  531. func (rt *argumentExpressionRuntime) Arguments() map[string]interface{} {
  532. res := make(map[string]interface{})
  533. for _, c := range rt.node.Children {
  534. if c.Name == parser.NodeArguments {
  535. for _, a := range c.Children {
  536. res[a.Children[0].Token.Val] = a.Children[1].Runtime.(*valueRuntime).Value()
  537. }
  538. }
  539. }
  540. return res
  541. }
  542. // Field Runtime
  543. // =============
  544. /*
  545. Runtime for Fields.
  546. */
  547. type fieldRuntime struct {
  548. *argumentExpressionRuntime
  549. rtp *GraphQLRuntimeProvider
  550. node *parser.ASTNode
  551. }
  552. /*
  553. fieldRuntimeInst returns a new runtime component instance.
  554. */
  555. func fieldRuntimeInst(rtp *GraphQLRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  556. return &fieldRuntime{&argumentExpressionRuntime{&invalidRuntime{rtp, node},
  557. rtp, node}, rtp, node}
  558. }
  559. /*
  560. Alias returns the alias of this field.
  561. */
  562. func (rt *fieldRuntime) Alias() string {
  563. return rt.node.Children[0].Token.Val
  564. }
  565. /*
  566. SelectionSetRuntime returns the SelectionSet runtime of this field.
  567. */
  568. func (rt *fieldRuntime) SelectionSetRuntime() *selectionSetRuntime {
  569. res, _ := rt.node.Children[len(rt.node.Children)-1].Runtime.(*selectionSetRuntime)
  570. return res
  571. }