where.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  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/eliasdb/eql/parser"
  17. "devt.de/krotik/eliasdb/graph/data"
  18. )
  19. /*
  20. CondRuntime is a component of a condition which can be evaluated
  21. with a node and an edge.
  22. */
  23. type CondRuntime interface {
  24. /*
  25. CondEval evaluates this condition runtime element.
  26. */
  27. CondEval(node data.Node, edge data.Edge) (interface{}, error)
  28. }
  29. /*
  30. Abstract runtime for condition components
  31. */
  32. type whereItemRuntime struct {
  33. rtp *eqlRuntimeProvider
  34. astNode *parser.ASTNode
  35. }
  36. /*
  37. Validate this node and all its child nodes.
  38. */
  39. func (rt *whereItemRuntime) Validate() error {
  40. return rt.rtp.newRuntimeError(ErrInvalidConstruct, rt.astNode.Name, rt.astNode)
  41. }
  42. /*
  43. Eval evaluate this condition component.
  44. */
  45. func (rt *whereItemRuntime) Eval() (interface{}, error) {
  46. return nil, rt.rtp.newRuntimeError(ErrInvalidConstruct, rt.astNode.Name, rt.astNode)
  47. }
  48. /*
  49. valOp executes an operation on two abstract values.
  50. */
  51. func (rt *whereItemRuntime) valOp(node data.Node, edge data.Edge, op func(interface{}, interface{}) interface{}) (interface{}, error) {
  52. res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)
  53. if err != nil {
  54. return nil, err
  55. }
  56. res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)
  57. if err != nil {
  58. return nil, err
  59. }
  60. return op(res1, res2), nil
  61. }
  62. /*
  63. stringOp executes an operation on two strings.
  64. */
  65. func (rt *whereItemRuntime) stringOp(node data.Node, edge data.Edge, op func(string, string) interface{}) (interface{}, error) {
  66. res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)
  67. if err != nil {
  68. return nil, err
  69. }
  70. res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)
  71. if err != nil {
  72. return nil, err
  73. }
  74. return op(fmt.Sprint(res1), fmt.Sprint(res2)), nil
  75. }
  76. /*
  77. regexOp executes an operation on a string and a regex.
  78. */
  79. func (rt *whereItemRuntime) regexOp(node data.Node, edge data.Edge, op func(string, *regexp.Regexp) interface{}) (interface{}, error) {
  80. res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)
  81. if err != nil {
  82. return nil, err
  83. }
  84. res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)
  85. if err != nil {
  86. return nil, err
  87. }
  88. // Try to compile the regex
  89. res2String := fmt.Sprint(res2)
  90. regexp, err := regexp.Compile(res2String)
  91. if err != nil {
  92. return nil, rt.rtp.newRuntimeError(ErrNotARegex,
  93. fmt.Sprintf("%#v - %s", res2String, err.Error()), rt.astNode.Children[1])
  94. }
  95. return op(fmt.Sprint(res1), regexp), nil
  96. }
  97. /*
  98. numOp executes an operation on two number values.
  99. */
  100. func (rt *whereItemRuntime) numOp(node data.Node, edge data.Edge, op func(float64, float64) interface{}) (interface{}, error) {
  101. res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)
  102. if err != nil {
  103. return nil, err
  104. }
  105. res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)
  106. if err != nil {
  107. return nil, err
  108. }
  109. errDetail := func(tokenVal string, opVal string) string {
  110. if tokenVal == opVal {
  111. return opVal
  112. }
  113. return tokenVal + "=" + opVal
  114. }
  115. // Parse the values to numbers
  116. res1Str := fmt.Sprint(res1)
  117. res1Num, err := strconv.ParseFloat(res1Str, 64)
  118. if err != nil {
  119. return nil, rt.rtp.newRuntimeError(ErrNotANumber, errDetail(rt.astNode.Children[0].Token.Val, res1Str), rt.astNode.Children[0])
  120. }
  121. res2Str := fmt.Sprint(res2)
  122. res2Num, err := strconv.ParseFloat(res2Str, 64)
  123. if err != nil {
  124. return nil, rt.rtp.newRuntimeError(ErrNotANumber, errDetail(rt.astNode.Children[1].Token.Val, res2Str), rt.astNode.Children[1])
  125. }
  126. return op(res1Num, res2Num), nil
  127. }
  128. /*
  129. listOp executes a list operation on a single value and a list.
  130. */
  131. func (rt *whereItemRuntime) listOp(node data.Node, edge data.Edge, op func(interface{}, []interface{}) interface{}) (interface{}, error) {
  132. res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)
  133. if err != nil {
  134. return nil, err
  135. }
  136. res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)
  137. if err != nil {
  138. return nil, err
  139. }
  140. errDetail := func(tokenVal string, opVal string) string {
  141. if tokenVal == opVal {
  142. return opVal
  143. }
  144. return tokenVal + "=" + opVal
  145. }
  146. // Parse right value to a list
  147. res2List, ok := res2.([]interface{})
  148. if !ok {
  149. return nil, rt.rtp.newRuntimeError(ErrNotAList, errDetail(rt.astNode.Children[1].Token.Val, fmt.Sprint(res2)), rt.astNode.Children[1])
  150. }
  151. return op(res1, res2List), nil
  152. }
  153. /*
  154. boolOp executes an operation on two boolean values. Can optionally try a
  155. short circuit operation.
  156. */
  157. func (rt *whereItemRuntime) boolOp(node data.Node, edge data.Edge, op func(bool, bool) interface{},
  158. scop func(bool) interface{}) (interface{}, error) {
  159. res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)
  160. if err != nil {
  161. return nil, err
  162. }
  163. if len(rt.astNode.Children) == 1 {
  164. // Special case for "not" operation
  165. return op(toBool(res1), false), nil
  166. }
  167. // Try short circuit
  168. res1bool := toBool(res1)
  169. if scop != nil {
  170. if ret := scop(res1bool); ret != nil {
  171. return ret, nil
  172. }
  173. }
  174. res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)
  175. if err != nil {
  176. return nil, err
  177. }
  178. return op(res1bool, toBool(res2)), nil
  179. }
  180. /*
  181. toBool is a helper function to turn any value into a boolean.
  182. */
  183. func toBool(res interface{}) bool {
  184. switch res := res.(type) {
  185. default:
  186. return res != nil
  187. case bool:
  188. return res
  189. case float64:
  190. return res > 0
  191. case string:
  192. // Try to convert the string into a number
  193. num, err := strconv.ParseFloat(res, 64)
  194. if err == nil {
  195. return num > 0
  196. }
  197. return res != ""
  198. }
  199. }
  200. func equals(res1 interface{}, res2 interface{}) bool {
  201. // Try to convert the string into a number
  202. num1, err := strconv.ParseFloat(fmt.Sprint(res1), 64)
  203. if err == nil {
  204. num2, err := strconv.ParseFloat(fmt.Sprint(res2), 64)
  205. if err == nil {
  206. return num1 == num2
  207. }
  208. }
  209. return fmt.Sprintf("%v", res1) == fmt.Sprintf("%v", res2)
  210. }
  211. // Where runtime
  212. // =============
  213. /*
  214. Runtime for where
  215. */
  216. type whereRuntime struct {
  217. rtp *eqlRuntimeProvider
  218. astNode *parser.ASTNode
  219. specIndex int // Index of this traversal in the traversals array
  220. }
  221. /*
  222. whereRuntimeInst returns a new runtime component instance.
  223. */
  224. func whereRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  225. return &whereRuntime{rtp, node, 0}
  226. }
  227. /*
  228. Validate this node and all its child nodes.
  229. */
  230. func (rt *whereRuntime) Validate() error {
  231. var visitChildren func(astNode *parser.ASTNode) error
  232. visitChildren = func(astNode *parser.ASTNode) error {
  233. // Determine which values should be interpreted as node attributes
  234. if astNode.Name == parser.NodeVALUE {
  235. val := astNode.Token.Val
  236. lcval := strings.ToLower(val)
  237. valRuntime, ok := astNode.Runtime.(*valueRuntime)
  238. if !ok {
  239. return astNode.Runtime.Validate()
  240. }
  241. if strings.HasPrefix(lcval, "eattr:") {
  242. valRuntime.condVal = val[6:]
  243. valRuntime.isNodeAttrValue = false
  244. valRuntime.isEdgeAttrValue = true
  245. } else if strings.HasPrefix(lcval, "attr:") {
  246. valRuntime.condVal = val[5:]
  247. valRuntime.isNodeAttrValue = true
  248. valRuntime.isEdgeAttrValue = false
  249. } else if strings.HasPrefix(lcval, "val:") {
  250. valRuntime.condVal = val[4:]
  251. valRuntime.isNodeAttrValue = false
  252. valRuntime.isEdgeAttrValue = false
  253. } else {
  254. valRuntime.condVal = val
  255. valRuntime.isNodeAttrValue = rt.rtp.ni.IsValidAttr(val)
  256. valRuntime.isEdgeAttrValue = false
  257. // Check if we have a nested value
  258. if strings.Contains(val, ".") {
  259. nestedValuePath := strings.Split(val, ".")
  260. if rt.rtp.ni.IsValidAttr(nestedValuePath[0]) {
  261. valRuntime.condVal = nestedValuePath[0]
  262. valRuntime.nestedValuePath = nestedValuePath
  263. valRuntime.isNodeAttrValue = true
  264. }
  265. }
  266. }
  267. // Make sure attributes are queried
  268. if valRuntime.isNodeAttrValue {
  269. rt.rtp.attrsNodes[rt.specIndex][valRuntime.condVal] = ""
  270. } else if valRuntime.isEdgeAttrValue {
  271. rt.rtp.attrsEdges[rt.specIndex][valRuntime.condVal] = ""
  272. }
  273. }
  274. for _, child := range astNode.Children {
  275. if err := visitChildren(child); err != nil {
  276. return err
  277. }
  278. }
  279. return nil
  280. }
  281. return visitChildren(rt.astNode)
  282. }
  283. /*
  284. Eval evaluates the where clause a
  285. */
  286. func (rt *whereRuntime) Eval() (interface{}, error) {
  287. return nil, rt.rtp.newRuntimeError(ErrInvalidConstruct, rt.astNode.Name, rt.astNode)
  288. }
  289. /*
  290. CondEval evaluates this condition runtime element.
  291. */
  292. func (rt *whereRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  293. res, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)
  294. return toBool(res), err
  295. }
  296. // Where related runtimes
  297. // ======================
  298. /*
  299. Equal runtime
  300. */
  301. type equalRuntime struct {
  302. *whereItemRuntime
  303. }
  304. /*
  305. equalRuntimeInst returns a new runtime component instance.
  306. */
  307. func equalRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  308. return &equalRuntime{&whereItemRuntime{rtp, node}}
  309. }
  310. /*
  311. Evaluate this condition runtime element.
  312. */
  313. func (rt *equalRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  314. return rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return equals(res1, res2) })
  315. }
  316. /*
  317. CondEval evaluates this condition runtime element.
  318. */
  319. type notEqualRuntime struct {
  320. *whereItemRuntime
  321. }
  322. /*
  323. notEqualRuntimeInst returns a new runtime component instance.
  324. */
  325. func notEqualRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  326. return &notEqualRuntime{&whereItemRuntime{rtp, node}}
  327. }
  328. /*
  329. CondEval evaluates this condition runtime element.
  330. */
  331. func (rt *notEqualRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  332. return rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return !equals(res1, res2) })
  333. }
  334. /*
  335. Less than runtime
  336. */
  337. type lessThanRuntime struct {
  338. *whereItemRuntime
  339. }
  340. /*
  341. lessThanRuntimeInst returns a new runtime component instance.
  342. */
  343. func lessThanRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  344. return &lessThanRuntime{&whereItemRuntime{rtp, node}}
  345. }
  346. /*
  347. CondEval evaluates this condition runtime element.
  348. */
  349. func (rt *lessThanRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  350. ret, err := rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 < res2 })
  351. if err != nil {
  352. // Do a simple string ordering
  353. ret, err = rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return fmt.Sprint(res1) < fmt.Sprint(res2) })
  354. }
  355. return ret, err
  356. }
  357. /*
  358. Less than equals runtime
  359. */
  360. type lessThanEqualsRuntime struct {
  361. *whereItemRuntime
  362. }
  363. /*
  364. lessThanEqualsRuntimeInst returns a new runtime component instance.
  365. */
  366. func lessThanEqualsRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  367. return &lessThanEqualsRuntime{&whereItemRuntime{rtp, node}}
  368. }
  369. /*
  370. CondEval evaluates this condition runtime element.
  371. */
  372. func (rt *lessThanEqualsRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  373. ret, err := rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 <= res2 })
  374. if err != nil {
  375. // Do a simple string ordering
  376. ret, err = rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return fmt.Sprint(res1) <= fmt.Sprint(res2) })
  377. }
  378. return ret, err
  379. }
  380. /*
  381. Greater than runtime
  382. */
  383. type greaterThanRuntime struct {
  384. *whereItemRuntime
  385. }
  386. /*
  387. greaterThanRuntimeInst returns a new runtime component instance.
  388. */
  389. func greaterThanRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  390. return &greaterThanRuntime{&whereItemRuntime{rtp, node}}
  391. }
  392. /*
  393. CondEval evaluates this condition runtime element.
  394. */
  395. func (rt *greaterThanRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  396. ret, err := rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 > res2 })
  397. if err != nil {
  398. // Do a simple string ordering
  399. ret, err = rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return fmt.Sprint(res1) > fmt.Sprint(res2) })
  400. }
  401. return ret, err
  402. }
  403. /*
  404. Greater than equals runtime
  405. */
  406. type greaterThanEqualsRuntime struct {
  407. *whereItemRuntime
  408. }
  409. /*
  410. greaterThanEqualsRuntimeInst returns a new runtime component instance.
  411. */
  412. func greaterThanEqualsRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  413. return &greaterThanEqualsRuntime{&whereItemRuntime{rtp, node}}
  414. }
  415. /*
  416. CondEval evaluates this condition runtime element.
  417. */
  418. func (rt *greaterThanEqualsRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  419. ret, err := rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 >= res2 })
  420. if err != nil {
  421. // Do a simple string ordering
  422. ret, err = rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return fmt.Sprint(res1) >= fmt.Sprint(res2) })
  423. }
  424. return ret, err
  425. }
  426. /*
  427. And runtime
  428. */
  429. type andRuntime struct {
  430. *whereItemRuntime
  431. }
  432. /*
  433. andRuntimeInst returns a new runtime component instance.
  434. */
  435. func andRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  436. return &andRuntime{&whereItemRuntime{rtp, node}}
  437. }
  438. /*
  439. CondEval evaluates this condition runtime element.
  440. */
  441. func (rt *andRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  442. return rt.boolOp(node, edge, func(res1 bool, res2 bool) interface{} { return res1 && res2 },
  443. func(res1 bool) interface{} {
  444. if !res1 {
  445. return false
  446. }
  447. return nil
  448. })
  449. }
  450. /*
  451. Or runtime
  452. */
  453. type orRuntime struct {
  454. *whereItemRuntime
  455. }
  456. /*
  457. orRuntimeInst returns a new runtime component instance.
  458. */
  459. func orRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  460. return &orRuntime{&whereItemRuntime{rtp, node}}
  461. }
  462. /*
  463. CondEval evaluates this condition runtime element.
  464. */
  465. func (rt *orRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  466. return rt.boolOp(node, edge, func(res1 bool, res2 bool) interface{} { return res1 || res2 },
  467. func(res1 bool) interface{} {
  468. if res1 {
  469. return true
  470. }
  471. return nil
  472. })
  473. }
  474. /*
  475. Not runtime
  476. */
  477. type notRuntime struct {
  478. *whereItemRuntime
  479. }
  480. /*
  481. notRuntimeInst returns a new runtime component instance.
  482. */
  483. func notRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  484. return &notRuntime{&whereItemRuntime{rtp, node}}
  485. }
  486. /*
  487. CondEval evaluates this condition runtime element.
  488. */
  489. func (rt *notRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  490. return rt.boolOp(node, edge, func(res1 bool, res2 bool) interface{} { return !res1 }, nil)
  491. }
  492. /*
  493. Plus runtime
  494. */
  495. type plusRuntime struct {
  496. *whereItemRuntime
  497. }
  498. /*
  499. plusRuntimeInst returns a new runtime component instance.
  500. */
  501. func plusRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  502. return &plusRuntime{&whereItemRuntime{rtp, node}}
  503. }
  504. /*
  505. CondEval evaluates this condition runtime element.
  506. */
  507. func (rt *plusRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  508. return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 + res2 })
  509. }
  510. /*
  511. Minus runtime
  512. */
  513. type minusRuntime struct {
  514. *whereItemRuntime
  515. }
  516. /*
  517. minusRuntimeInst returns a new runtime component instance.
  518. */
  519. func minusRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  520. return &minusRuntime{&whereItemRuntime{rtp, node}}
  521. }
  522. /*
  523. CondEval evaluates this condition runtime element.
  524. */
  525. func (rt *minusRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  526. return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 - res2 })
  527. }
  528. /*
  529. Times runtime
  530. */
  531. type timesRuntime struct {
  532. *whereItemRuntime
  533. }
  534. /*
  535. timesRuntimeInst returns a new runtime component instance.
  536. */
  537. func timesRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  538. return &timesRuntime{&whereItemRuntime{rtp, node}}
  539. }
  540. /*
  541. CondEval evaluates this condition runtime element.
  542. */
  543. func (rt *timesRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  544. return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 * res2 })
  545. }
  546. /*
  547. Div runtime
  548. */
  549. type divRuntime struct {
  550. *whereItemRuntime
  551. }
  552. /*
  553. divRuntimeInst returns a new runtime component instance.
  554. */
  555. func divRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  556. return &divRuntime{&whereItemRuntime{rtp, node}}
  557. }
  558. /*
  559. CondEval evaluates this condition runtime element.
  560. */
  561. func (rt *divRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  562. return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 / res2 })
  563. }
  564. /*
  565. ModInt runtime
  566. */
  567. type modIntRuntime struct {
  568. *whereItemRuntime
  569. }
  570. /*
  571. modIntRuntimeInst returns a new runtime component instance.
  572. */
  573. func modIntRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  574. return &modIntRuntime{&whereItemRuntime{rtp, node}}
  575. }
  576. /*
  577. CondEval evaluates this condition runtime element.
  578. */
  579. func (rt *modIntRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  580. return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return int(int(res1) % int(res2)) })
  581. }
  582. /*
  583. DivInt runtime
  584. */
  585. type divIntRuntime struct {
  586. *whereItemRuntime
  587. }
  588. /*
  589. divIntRuntimeInst returns a new runtime component instance.
  590. */
  591. func divIntRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  592. return &divIntRuntime{&whereItemRuntime{rtp, node}}
  593. }
  594. /*
  595. CondEval evaluates this condition runtime element.
  596. */
  597. func (rt *divIntRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  598. return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return int(int(res1) / int(res2)) })
  599. }
  600. /*
  601. In runtime
  602. */
  603. type inRuntime struct {
  604. *whereItemRuntime
  605. }
  606. /*
  607. inRuntimeInst returns a new runtime component instance.
  608. */
  609. func inRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  610. return &inRuntime{&whereItemRuntime{rtp, node}}
  611. }
  612. /*
  613. CondEval evaluates this condition runtime element.
  614. */
  615. func (rt *inRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  616. return rt.listOp(node, edge, func(res1 interface{}, res2 []interface{}) interface{} {
  617. for _, item := range res2 {
  618. if equals(res1, item) {
  619. return true
  620. }
  621. }
  622. return false
  623. })
  624. }
  625. /*
  626. Not in runtime
  627. */
  628. type notInRuntime struct {
  629. *whereItemRuntime
  630. }
  631. /*
  632. notInRuntimeInst returns a new runtime component instance.
  633. */
  634. func notInRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  635. return &notInRuntime{&whereItemRuntime{rtp, node}}
  636. }
  637. /*
  638. CondEval evaluates this condition runtime element.
  639. */
  640. func (rt *notInRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  641. return rt.listOp(node, edge, func(res1 interface{}, res2 []interface{}) interface{} {
  642. for _, item := range res2 {
  643. if equals(res1, item) {
  644. return false
  645. }
  646. }
  647. return true
  648. })
  649. }
  650. /*
  651. Like runtime
  652. */
  653. type likeRuntime struct {
  654. compiledRegex *regexp.Regexp // Quick lookup of the compiled regex if it is a constant
  655. *whereItemRuntime
  656. }
  657. /*
  658. likeRuntimeInst returns a new runtime component instance.
  659. */
  660. func likeRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  661. return &likeRuntime{nil, &whereItemRuntime{rtp, node}}
  662. }
  663. /*
  664. CondEval evaluates this condition runtime element.
  665. */
  666. func (rt *likeRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  667. // Check for constant regexp
  668. if valRT, ok := rt.astNode.Children[1].Runtime.(*valueRuntime); ok {
  669. if !valRT.isNodeAttrValue && !valRT.isEdgeAttrValue {
  670. // Given regex is a constant and only needs to be compiled once
  671. val, _ := valRT.CondEval(node, edge)
  672. valStr := fmt.Sprint(val)
  673. regexp, err := regexp.Compile(valStr)
  674. if err != nil {
  675. return nil, rt.rtp.newRuntimeError(ErrNotARegex,
  676. fmt.Sprintf("%#v - %s", valStr, err.Error()), rt.astNode.Children[1])
  677. }
  678. rt.compiledRegex = regexp
  679. }
  680. }
  681. if rt.compiledRegex == nil {
  682. return rt.regexOp(node, edge, func(res1 string, res2 *regexp.Regexp) interface{} { return res2.MatchString(res1) })
  683. }
  684. return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return rt.compiledRegex.MatchString(res1) })
  685. }
  686. /*
  687. Contains runtime
  688. */
  689. type containsRuntime struct {
  690. *whereItemRuntime
  691. }
  692. /*
  693. containsRuntimeInst returns a new runtime component instance.
  694. */
  695. func containsRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  696. return &containsRuntime{&whereItemRuntime{rtp, node}}
  697. }
  698. /*
  699. CondEval evaluates this condition runtime element.
  700. */
  701. func (rt *containsRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  702. return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return strings.Contains(res1, res2) })
  703. }
  704. /*
  705. Contains not runtime
  706. */
  707. type containsNotRuntime struct {
  708. *whereItemRuntime
  709. }
  710. /*
  711. containsNotRuntimeInst returns a new runtime component instance.
  712. */
  713. func containsNotRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  714. return &containsNotRuntime{&whereItemRuntime{rtp, node}}
  715. }
  716. /*
  717. CondEval evaluates this condition runtime element.
  718. */
  719. func (rt *containsNotRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  720. return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return !strings.Contains(res1, res2) })
  721. }
  722. /*
  723. Begins with runtime
  724. */
  725. type beginsWithRuntime struct {
  726. *whereItemRuntime
  727. }
  728. /*
  729. beginsWithRuntimeInst returns a new runtime component instance.
  730. */
  731. func beginsWithRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  732. return &beginsWithRuntime{&whereItemRuntime{rtp, node}}
  733. }
  734. /*
  735. CondEval evaluates this condition runtime element.
  736. */
  737. func (rt *beginsWithRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  738. return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return strings.HasPrefix(res1, res2) })
  739. }
  740. /*
  741. Ends with runtime
  742. */
  743. type endsWithRuntime struct {
  744. *whereItemRuntime
  745. }
  746. /*
  747. endsWithRuntimeInst returns a new runtime component instance.
  748. */
  749. func endsWithRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  750. return &endsWithRuntime{&whereItemRuntime{rtp, node}}
  751. }
  752. /*
  753. CondEval evaluates this condition runtime element.
  754. */
  755. func (rt *endsWithRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {
  756. return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return strings.HasSuffix(res1, res2) })
  757. }