You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

527 lines
13 KiB

  1. // Package query provides a parser for a custom query format:
  2. //
  3. // abci.invoice.number=22 AND abci.invoice.owner=Ivan
  4. //
  5. // See query.peg for the grammar, which is a https://en.wikipedia.org/wiki/Parsing_expression_grammar.
  6. // More: https://github.com/PhilippeSigaud/Pegged/wiki/PEG-Basics
  7. //
  8. // It has a support for numbers (integer and floating point), dates and times.
  9. package query
  10. import (
  11. "fmt"
  12. "reflect"
  13. "regexp"
  14. "strconv"
  15. "strings"
  16. "time"
  17. "github.com/tendermint/tendermint/abci/types"
  18. )
  19. var (
  20. numRegex = regexp.MustCompile(`([0-9\.]+)`)
  21. )
  22. // Query holds the query string and the query parser.
  23. type Query struct {
  24. str string
  25. parser *QueryParser
  26. }
  27. // Condition represents a single condition within a query and consists of composite key
  28. // (e.g. "tx.gas"), operator (e.g. "=") and operand (e.g. "7").
  29. type Condition struct {
  30. CompositeKey string
  31. Op Operator
  32. Operand interface{}
  33. }
  34. // New parses the given string and returns a query or error if the string is
  35. // invalid.
  36. func New(s string) (*Query, error) {
  37. p := &QueryParser{Buffer: fmt.Sprintf(`"%s"`, s)}
  38. p.Init()
  39. if err := p.Parse(); err != nil {
  40. return nil, err
  41. }
  42. return &Query{str: s, parser: p}, nil
  43. }
  44. // MustParse turns the given string into a query or panics; for tests or others
  45. // cases where you know the string is valid.
  46. func MustParse(s string) *Query {
  47. q, err := New(s)
  48. if err != nil {
  49. panic(fmt.Sprintf("failed to parse %s: %v", s, err))
  50. }
  51. return q
  52. }
  53. // String returns the original string.
  54. func (q *Query) String() string {
  55. return q.str
  56. }
  57. // Operator is an operator that defines some kind of relation between composite key and
  58. // operand (equality, etc.).
  59. type Operator uint8
  60. const (
  61. // "<="
  62. OpLessEqual Operator = iota
  63. // ">="
  64. OpGreaterEqual
  65. // "<"
  66. OpLess
  67. // ">"
  68. OpGreater
  69. // "="
  70. OpEqual
  71. // "CONTAINS"; used to check if a string contains a certain sub string.
  72. OpContains
  73. // "EXISTS"; used to check if a certain event attribute is present.
  74. OpExists
  75. )
  76. const (
  77. // DateLayout defines a layout for all dates (`DATE date`)
  78. DateLayout = "2006-01-02"
  79. // TimeLayout defines a layout for all times (`TIME time`)
  80. TimeLayout = time.RFC3339
  81. )
  82. // Conditions returns a list of conditions. It returns an error if there is any
  83. // error with the provided grammar in the Query.
  84. func (q *Query) Conditions() ([]Condition, error) {
  85. var (
  86. eventAttr string
  87. op Operator
  88. )
  89. conditions := make([]Condition, 0)
  90. buffer, begin, end := q.parser.Buffer, 0, 0
  91. // tokens must be in the following order: tag ("tx.gas") -> operator ("=") -> operand ("7")
  92. for token := range q.parser.Tokens() {
  93. switch token.pegRule {
  94. case rulePegText:
  95. begin, end = int(token.begin), int(token.end)
  96. case ruletag:
  97. eventAttr = buffer[begin:end]
  98. case rulele:
  99. op = OpLessEqual
  100. case rulege:
  101. op = OpGreaterEqual
  102. case rulel:
  103. op = OpLess
  104. case ruleg:
  105. op = OpGreater
  106. case ruleequal:
  107. op = OpEqual
  108. case rulecontains:
  109. op = OpContains
  110. case ruleexists:
  111. op = OpExists
  112. conditions = append(conditions, Condition{eventAttr, op, nil})
  113. case rulevalue:
  114. // strip single quotes from value (i.e. "'NewBlock'" -> "NewBlock")
  115. valueWithoutSingleQuotes := buffer[begin+1 : end-1]
  116. conditions = append(conditions, Condition{eventAttr, op, valueWithoutSingleQuotes})
  117. case rulenumber:
  118. number := buffer[begin:end]
  119. if strings.ContainsAny(number, ".") { // if it looks like a floating-point number
  120. value, err := strconv.ParseFloat(number, 64)
  121. if err != nil {
  122. err = fmt.Errorf(
  123. "got %v while trying to parse %s as float64 (should never happen if the grammar is correct)",
  124. err, number,
  125. )
  126. return nil, err
  127. }
  128. conditions = append(conditions, Condition{eventAttr, op, value})
  129. } else {
  130. value, err := strconv.ParseInt(number, 10, 64)
  131. if err != nil {
  132. err = fmt.Errorf(
  133. "got %v while trying to parse %s as int64 (should never happen if the grammar is correct)",
  134. err, number,
  135. )
  136. return nil, err
  137. }
  138. conditions = append(conditions, Condition{eventAttr, op, value})
  139. }
  140. case ruletime:
  141. value, err := time.Parse(TimeLayout, buffer[begin:end])
  142. if err != nil {
  143. err = fmt.Errorf(
  144. "got %v while trying to parse %s as time.Time / RFC3339 (should never happen if the grammar is correct)",
  145. err, buffer[begin:end],
  146. )
  147. return nil, err
  148. }
  149. conditions = append(conditions, Condition{eventAttr, op, value})
  150. case ruledate:
  151. value, err := time.Parse("2006-01-02", buffer[begin:end])
  152. if err != nil {
  153. err = fmt.Errorf(
  154. "got %v while trying to parse %s as time.Time / '2006-01-02' (should never happen if the grammar is correct)",
  155. err, buffer[begin:end],
  156. )
  157. return nil, err
  158. }
  159. conditions = append(conditions, Condition{eventAttr, op, value})
  160. }
  161. }
  162. return conditions, nil
  163. }
  164. // Matches returns true if the query matches against any event in the given set
  165. // of events, false otherwise. For each event, a match exists if the query is
  166. // matched against *any* value in a slice of values. An error is returned if
  167. // any attempted event match returns an error.
  168. //
  169. // For example, query "name=John" matches events = {"name": ["John", "Eric"]}.
  170. // More examples could be found in parser_test.go and query_test.go.
  171. func (q *Query) Matches(rawEvents []types.Event) (bool, error) {
  172. if len(rawEvents) == 0 {
  173. return false, nil
  174. }
  175. events := flattenEvents(rawEvents)
  176. var (
  177. eventAttr string
  178. op Operator
  179. )
  180. buffer, begin, end := q.parser.Buffer, 0, 0
  181. // tokens must be in the following order:
  182. // tag ("tx.gas") -> operator ("=") -> operand ("7")
  183. for token := range q.parser.Tokens() {
  184. switch token.pegRule {
  185. case rulePegText:
  186. begin, end = int(token.begin), int(token.end)
  187. case ruletag:
  188. eventAttr = buffer[begin:end]
  189. case rulele:
  190. op = OpLessEqual
  191. case rulege:
  192. op = OpGreaterEqual
  193. case rulel:
  194. op = OpLess
  195. case ruleg:
  196. op = OpGreater
  197. case ruleequal:
  198. op = OpEqual
  199. case rulecontains:
  200. op = OpContains
  201. case ruleexists:
  202. op = OpExists
  203. if strings.Contains(eventAttr, ".") {
  204. // Searching for a full "type.attribute" event.
  205. _, ok := events[eventAttr]
  206. if !ok {
  207. return false, nil
  208. }
  209. } else {
  210. foundEvent := false
  211. loop:
  212. for compositeKey := range events {
  213. if strings.Index(compositeKey, eventAttr) == 0 {
  214. foundEvent = true
  215. break loop
  216. }
  217. }
  218. if !foundEvent {
  219. return false, nil
  220. }
  221. }
  222. case rulevalue:
  223. // strip single quotes from value (i.e. "'NewBlock'" -> "NewBlock")
  224. valueWithoutSingleQuotes := buffer[begin+1 : end-1]
  225. // see if the triplet (event attribute, operator, operand) matches any event
  226. // "tx.gas", "=", "7", { "tx.gas": 7, "tx.ID": "4AE393495334" }
  227. match, err := match(eventAttr, op, reflect.ValueOf(valueWithoutSingleQuotes), events)
  228. if err != nil {
  229. return false, err
  230. }
  231. if !match {
  232. return false, nil
  233. }
  234. case rulenumber:
  235. number := buffer[begin:end]
  236. if strings.ContainsAny(number, ".") { // if it looks like a floating-point number
  237. value, err := strconv.ParseFloat(number, 64)
  238. if err != nil {
  239. err = fmt.Errorf(
  240. "got %v while trying to parse %s as float64 (should never happen if the grammar is correct)",
  241. err, number,
  242. )
  243. return false, err
  244. }
  245. match, err := match(eventAttr, op, reflect.ValueOf(value), events)
  246. if err != nil {
  247. return false, err
  248. }
  249. if !match {
  250. return false, nil
  251. }
  252. } else {
  253. value, err := strconv.ParseInt(number, 10, 64)
  254. if err != nil {
  255. err = fmt.Errorf(
  256. "got %v while trying to parse %s as int64 (should never happen if the grammar is correct)",
  257. err, number,
  258. )
  259. return false, err
  260. }
  261. match, err := match(eventAttr, op, reflect.ValueOf(value), events)
  262. if err != nil {
  263. return false, err
  264. }
  265. if !match {
  266. return false, nil
  267. }
  268. }
  269. case ruletime:
  270. value, err := time.Parse(TimeLayout, buffer[begin:end])
  271. if err != nil {
  272. err = fmt.Errorf(
  273. "got %v while trying to parse %s as time.Time / RFC3339 (should never happen if the grammar is correct)",
  274. err, buffer[begin:end],
  275. )
  276. return false, err
  277. }
  278. match, err := match(eventAttr, op, reflect.ValueOf(value), events)
  279. if err != nil {
  280. return false, err
  281. }
  282. if !match {
  283. return false, nil
  284. }
  285. case ruledate:
  286. value, err := time.Parse("2006-01-02", buffer[begin:end])
  287. if err != nil {
  288. err = fmt.Errorf(
  289. "got %v while trying to parse %s as time.Time / '2006-01-02' (should never happen if the grammar is correct)",
  290. err, buffer[begin:end],
  291. )
  292. return false, err
  293. }
  294. match, err := match(eventAttr, op, reflect.ValueOf(value), events)
  295. if err != nil {
  296. return false, err
  297. }
  298. if !match {
  299. return false, nil
  300. }
  301. }
  302. }
  303. return true, nil
  304. }
  305. // match returns true if the given triplet (attribute, operator, operand) matches
  306. // any value in an event for that attribute. If any match fails with an error,
  307. // that error is returned.
  308. //
  309. // First, it looks up the key in the events and if it finds one, tries to compare
  310. // all the values from it to the operand using the operator.
  311. //
  312. // "tx.gas", "=", "7", {"tx": [{"gas": 7, "ID": "4AE393495334"}]}
  313. func match(attr string, op Operator, operand reflect.Value, events map[string][]string) (bool, error) {
  314. // look up the tag from the query in tags
  315. values, ok := events[attr]
  316. if !ok {
  317. return false, nil
  318. }
  319. for _, value := range values {
  320. // return true if any value in the set of the event's values matches
  321. match, err := matchValue(value, op, operand)
  322. if err != nil {
  323. return false, err
  324. }
  325. if match {
  326. return true, nil
  327. }
  328. }
  329. return false, nil
  330. }
  331. // matchValue will attempt to match a string value against an operator an
  332. // operand. A boolean is returned representing the match result. It will return
  333. // an error if the value cannot be parsed and matched against the operand type.
  334. func matchValue(value string, op Operator, operand reflect.Value) (bool, error) {
  335. switch operand.Kind() {
  336. case reflect.Struct: // time
  337. operandAsTime := operand.Interface().(time.Time)
  338. // try our best to convert value from events to time.Time
  339. var (
  340. v time.Time
  341. err error
  342. )
  343. if strings.ContainsAny(value, "T") {
  344. v, err = time.Parse(TimeLayout, value)
  345. } else {
  346. v, err = time.Parse(DateLayout, value)
  347. }
  348. if err != nil {
  349. return false, fmt.Errorf("failed to convert value %v from event attribute to time.Time: %w", value, err)
  350. }
  351. switch op {
  352. case OpLessEqual:
  353. return (v.Before(operandAsTime) || v.Equal(operandAsTime)), nil
  354. case OpGreaterEqual:
  355. return (v.Equal(operandAsTime) || v.After(operandAsTime)), nil
  356. case OpLess:
  357. return v.Before(operandAsTime), nil
  358. case OpGreater:
  359. return v.After(operandAsTime), nil
  360. case OpEqual:
  361. return v.Equal(operandAsTime), nil
  362. }
  363. case reflect.Float64:
  364. var v float64
  365. operandFloat64 := operand.Interface().(float64)
  366. filteredValue := numRegex.FindString(value)
  367. // try our best to convert value from tags to float64
  368. v, err := strconv.ParseFloat(filteredValue, 64)
  369. if err != nil {
  370. return false, fmt.Errorf("failed to convert value %v from event attribute to float64: %w", filteredValue, err)
  371. }
  372. switch op {
  373. case OpLessEqual:
  374. return v <= operandFloat64, nil
  375. case OpGreaterEqual:
  376. return v >= operandFloat64, nil
  377. case OpLess:
  378. return v < operandFloat64, nil
  379. case OpGreater:
  380. return v > operandFloat64, nil
  381. case OpEqual:
  382. return v == operandFloat64, nil
  383. }
  384. case reflect.Int64:
  385. var v int64
  386. operandInt := operand.Interface().(int64)
  387. filteredValue := numRegex.FindString(value)
  388. // if value looks like float, we try to parse it as float
  389. if strings.ContainsAny(filteredValue, ".") {
  390. v1, err := strconv.ParseFloat(filteredValue, 64)
  391. if err != nil {
  392. return false, fmt.Errorf("failed to convert value %v from event attribute to float64: %w", filteredValue, err)
  393. }
  394. v = int64(v1)
  395. } else {
  396. var err error
  397. // try our best to convert value from tags to int64
  398. v, err = strconv.ParseInt(filteredValue, 10, 64)
  399. if err != nil {
  400. return false, fmt.Errorf("failed to convert value %v from event attribute to int64: %w", filteredValue, err)
  401. }
  402. }
  403. switch op {
  404. case OpLessEqual:
  405. return v <= operandInt, nil
  406. case OpGreaterEqual:
  407. return v >= operandInt, nil
  408. case OpLess:
  409. return v < operandInt, nil
  410. case OpGreater:
  411. return v > operandInt, nil
  412. case OpEqual:
  413. return v == operandInt, nil
  414. }
  415. case reflect.String:
  416. switch op {
  417. case OpEqual:
  418. return value == operand.String(), nil
  419. case OpContains:
  420. return strings.Contains(value, operand.String()), nil
  421. }
  422. default:
  423. return false, fmt.Errorf("unknown kind of operand %v", operand.Kind())
  424. }
  425. return false, nil
  426. }
  427. func flattenEvents(events []types.Event) map[string][]string {
  428. flattened := make(map[string][]string)
  429. for _, event := range events {
  430. if len(event.Type) == 0 {
  431. continue
  432. }
  433. for _, attr := range event.Attributes {
  434. if len(attr.Key) == 0 {
  435. continue
  436. }
  437. compositeEvent := fmt.Sprintf("%s.%s", event.Type, attr.Key)
  438. flattened[compositeEvent] = append(flattened[compositeEvent], attr.Value)
  439. }
  440. }
  441. return flattened
  442. }