str_func_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. // Copyright 2021 EMQ Technologies Co., Ltd.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package operator
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "github.com/lf-edge/ekuiper/internal/conf"
  19. "github.com/lf-edge/ekuiper/internal/topo/context"
  20. "github.com/lf-edge/ekuiper/internal/xsql"
  21. "github.com/lf-edge/ekuiper/pkg/cast"
  22. "reflect"
  23. "strings"
  24. "testing"
  25. )
  26. func TestStrFunc_Apply1(t *testing.T) {
  27. var tests = []struct {
  28. sql string
  29. data *xsql.Tuple
  30. result []map[string]interface{}
  31. }{
  32. {
  33. sql: "SELECT concat(a, b, c) AS a FROM test",
  34. data: &xsql.Tuple{
  35. Emitter: "test",
  36. Message: xsql.Message{
  37. "a": "mya",
  38. "b": "myb",
  39. "c": "myc",
  40. },
  41. },
  42. result: []map[string]interface{}{{
  43. "a": "myamybmyc",
  44. }},
  45. },
  46. {
  47. sql: "SELECT concat(a, d, b, c) AS a FROM test",
  48. data: &xsql.Tuple{
  49. Emitter: "test",
  50. Message: xsql.Message{
  51. "a": "mya",
  52. "b": "myb",
  53. "c": "myc",
  54. },
  55. },
  56. result: []map[string]interface{}{{
  57. "a": "myamybmyc",
  58. }},
  59. },
  60. {
  61. sql: "SELECT endswith(a, b) AS a FROM test",
  62. data: &xsql.Tuple{
  63. Emitter: "test",
  64. Message: xsql.Message{
  65. "a": "mya",
  66. "b": "myb",
  67. "c": "myc",
  68. },
  69. },
  70. result: []map[string]interface{}{{
  71. "a": false,
  72. }},
  73. },
  74. {
  75. sql: "SELECT endswith(a, b) AS a FROM test",
  76. data: &xsql.Tuple{
  77. Emitter: "test",
  78. Message: xsql.Message{
  79. "a": "mya",
  80. "b": "ya",
  81. "c": "myc",
  82. },
  83. },
  84. result: []map[string]interface{}{{
  85. "a": true,
  86. }},
  87. },
  88. {
  89. sql: "SELECT endswith(a, d) AS a FROM test",
  90. data: &xsql.Tuple{
  91. Emitter: "test",
  92. Message: xsql.Message{
  93. "a": "mya",
  94. "b": "ya",
  95. "c": "myc",
  96. },
  97. },
  98. result: []map[string]interface{}{{
  99. "a": false,
  100. }},
  101. },
  102. {
  103. sql: "SELECT format_time(a, \"yyyy-MM-dd T HH:mm:ss\") AS a FROM test",
  104. data: &xsql.Tuple{
  105. Emitter: "test",
  106. Message: xsql.Message{
  107. "a": cast.TimeFromUnixMilli(1568854515000),
  108. "b": "ya",
  109. "c": "myc",
  110. },
  111. },
  112. result: []map[string]interface{}{{
  113. "a": "2019-09-19 T 00:55:15",
  114. }},
  115. },
  116. {
  117. sql: "SELECT format_time(meta(created) * 1000, \"yyyy-MM-dd T HH:mm:ss\") AS time FROM test",
  118. data: &xsql.Tuple{
  119. Emitter: "test",
  120. Message: xsql.Message{
  121. "a": "hello",
  122. "b": "ya",
  123. "c": "myc",
  124. },
  125. Metadata: xsql.Metadata{
  126. "created": 1.62000273e+09,
  127. },
  128. },
  129. result: []map[string]interface{}{{
  130. "time": "2021-05-03 T 00:45:30",
  131. }},
  132. },
  133. {
  134. sql: "SELECT format_time(d, \"yyyy-MM-dd T HH:mm:ss\") AS time FROM test",
  135. data: &xsql.Tuple{
  136. Emitter: "test",
  137. Message: xsql.Message{
  138. "a": "hello",
  139. "b": "ya",
  140. "c": "myc",
  141. },
  142. },
  143. result: []map[string]interface{}{{}},
  144. },
  145. {
  146. sql: "SELECT indexof(a, \"a\") AS a FROM test",
  147. data: &xsql.Tuple{
  148. Emitter: "test",
  149. Message: xsql.Message{
  150. "a": "mya",
  151. "b": "ya",
  152. "c": "myc",
  153. },
  154. },
  155. result: []map[string]interface{}{{
  156. "a": float64(2),
  157. }},
  158. },
  159. {
  160. sql: "SELECT indexof(d, \"a\") AS a FROM test",
  161. data: &xsql.Tuple{
  162. Emitter: "test",
  163. Message: xsql.Message{
  164. "a": "mya",
  165. "b": "ya",
  166. "c": "myc",
  167. },
  168. },
  169. result: []map[string]interface{}{{
  170. "a": float64(-1),
  171. }},
  172. },
  173. {
  174. sql: "SELECT length(a) AS a FROM test",
  175. data: &xsql.Tuple{
  176. Emitter: "test",
  177. Message: xsql.Message{
  178. "a": "中国",
  179. "b": "ya",
  180. "c": "myc",
  181. },
  182. },
  183. result: []map[string]interface{}{{
  184. "a": float64(2),
  185. }},
  186. },
  187. {
  188. sql: "SELECT length(c) AS a FROM test",
  189. data: &xsql.Tuple{
  190. Emitter: "test",
  191. Message: xsql.Message{
  192. "a": "中国",
  193. "b": "ya",
  194. "c": "myc",
  195. },
  196. },
  197. result: []map[string]interface{}{{
  198. "a": float64(3),
  199. }},
  200. },
  201. {
  202. sql: "SELECT length(d) AS a FROM test",
  203. data: &xsql.Tuple{
  204. Emitter: "test",
  205. Message: xsql.Message{
  206. "a": "中国",
  207. "b": "ya",
  208. "c": "myc",
  209. },
  210. },
  211. result: []map[string]interface{}{{
  212. "a": float64(0),
  213. }},
  214. },
  215. {
  216. sql: "SELECT lower(a) AS a FROM test",
  217. data: &xsql.Tuple{
  218. Emitter: "test",
  219. Message: xsql.Message{
  220. "a": "NYCNicks",
  221. "b": "ya",
  222. "c": "myc",
  223. },
  224. },
  225. result: []map[string]interface{}{{
  226. "a": "nycnicks",
  227. }},
  228. },
  229. {
  230. sql: "SELECT lower(d) AS a FROM test",
  231. data: &xsql.Tuple{
  232. Emitter: "test",
  233. Message: xsql.Message{
  234. "a": "NYCNicks",
  235. "b": "ya",
  236. "c": "myc",
  237. },
  238. },
  239. result: []map[string]interface{}{{}},
  240. },
  241. {
  242. sql: "SELECT lpad(a, 2) AS a FROM test",
  243. data: &xsql.Tuple{
  244. Emitter: "test",
  245. Message: xsql.Message{
  246. "a": "NYCNicks",
  247. "b": "ya",
  248. "c": "myc",
  249. },
  250. },
  251. result: []map[string]interface{}{{
  252. "a": " NYCNicks",
  253. }},
  254. },
  255. {
  256. sql: "SELECT ltrim(a) AS a FROM test",
  257. data: &xsql.Tuple{
  258. Emitter: "test",
  259. Message: xsql.Message{
  260. "a": " \ttrimme\n ",
  261. "b": "ya",
  262. "c": "myc",
  263. },
  264. },
  265. result: []map[string]interface{}{{
  266. "a": "trimme\n ",
  267. }},
  268. },
  269. {
  270. sql: "SELECT numbytes(a) AS a FROM test",
  271. data: &xsql.Tuple{
  272. Emitter: "test",
  273. Message: xsql.Message{
  274. "a": "中国",
  275. "b": "ya",
  276. "c": "myc",
  277. },
  278. },
  279. result: []map[string]interface{}{{
  280. "a": float64(6),
  281. }},
  282. },
  283. {
  284. sql: "SELECT numbytes(b) AS a FROM test",
  285. data: &xsql.Tuple{
  286. Emitter: "test",
  287. Message: xsql.Message{
  288. "a": "中国",
  289. "b": "ya",
  290. "c": "myc",
  291. },
  292. },
  293. result: []map[string]interface{}{{
  294. "a": float64(2),
  295. }},
  296. },
  297. {
  298. sql: "SELECT regexp_matches(a,\"foo.*\") AS a FROM test",
  299. data: &xsql.Tuple{
  300. Emitter: "test",
  301. Message: xsql.Message{
  302. "a": "seafood",
  303. "b": "ya",
  304. "c": "myc",
  305. },
  306. },
  307. result: []map[string]interface{}{{
  308. "a": true,
  309. }},
  310. },
  311. {
  312. sql: "SELECT regexp_matches(b,\"foo.*\") AS a FROM test",
  313. data: &xsql.Tuple{
  314. Emitter: "test",
  315. Message: xsql.Message{
  316. "a": "seafood",
  317. "b": "ya",
  318. "c": "myc",
  319. },
  320. },
  321. result: []map[string]interface{}{{
  322. "a": false,
  323. }},
  324. },
  325. {
  326. sql: "SELECT regexp_matches(d,\"foo.*\") AS a FROM test",
  327. data: &xsql.Tuple{
  328. Emitter: "test",
  329. Message: xsql.Message{
  330. "a": "seafood",
  331. "b": "ya",
  332. "c": "myc",
  333. },
  334. },
  335. result: []map[string]interface{}{{
  336. "a": false,
  337. }},
  338. },
  339. {
  340. sql: "SELECT regexp_replace(a,\"a(x*)b\", \"REP\") AS a FROM test",
  341. data: &xsql.Tuple{
  342. Emitter: "test",
  343. Message: xsql.Message{
  344. "a": "-ab-axxb-",
  345. "b": "ya",
  346. "c": "myc",
  347. },
  348. },
  349. result: []map[string]interface{}{{
  350. "a": "-REP-REP-",
  351. }},
  352. },
  353. {
  354. sql: "SELECT regexp_replace(a,\"a(x*)b\", d) AS a FROM test",
  355. data: &xsql.Tuple{
  356. Emitter: "test",
  357. Message: xsql.Message{
  358. "a": "-ab-axxb-",
  359. "b": "ya",
  360. "c": "myc",
  361. },
  362. },
  363. result: []map[string]interface{}{{}},
  364. },
  365. {
  366. sql: "SELECT regexp_substr(a,\"foo.*\") AS a FROM test",
  367. data: &xsql.Tuple{
  368. Emitter: "test",
  369. Message: xsql.Message{
  370. "a": "seafood",
  371. "b": "ya",
  372. "c": "myc",
  373. },
  374. },
  375. result: []map[string]interface{}{{
  376. "a": "food",
  377. }},
  378. },
  379. {
  380. sql: "SELECT regexp_substr(d,\"foo.*\") AS a FROM test",
  381. data: &xsql.Tuple{
  382. Emitter: "test",
  383. Message: xsql.Message{
  384. "a": "seafood",
  385. "b": "ya",
  386. "c": "myc",
  387. },
  388. },
  389. result: []map[string]interface{}{{}},
  390. },
  391. {
  392. sql: "SELECT rpad(a, 3) AS a FROM test",
  393. data: &xsql.Tuple{
  394. Emitter: "test",
  395. Message: xsql.Message{
  396. "a": "NYCNicks",
  397. "b": "ya",
  398. "c": "myc",
  399. },
  400. },
  401. result: []map[string]interface{}{{
  402. "a": "NYCNicks ",
  403. }},
  404. },
  405. {
  406. sql: "SELECT rtrim(a) AS a FROM test",
  407. data: &xsql.Tuple{
  408. Emitter: "test",
  409. Message: xsql.Message{
  410. "a": " \ttrimme\n ",
  411. "b": "ya",
  412. "c": "myc",
  413. },
  414. },
  415. result: []map[string]interface{}{{
  416. "a": " \ttrimme",
  417. }},
  418. },
  419. {
  420. sql: "SELECT substring(a, 3) AS a FROM test",
  421. data: &xsql.Tuple{
  422. Emitter: "test",
  423. Message: xsql.Message{
  424. "a": "NYCNicks",
  425. "b": "ya",
  426. "c": "myc",
  427. },
  428. },
  429. result: []map[string]interface{}{{
  430. "a": "Nicks",
  431. }},
  432. },
  433. {
  434. sql: "SELECT substring(a, 3, 5) AS a FROM test",
  435. data: &xsql.Tuple{
  436. Emitter: "test",
  437. Message: xsql.Message{
  438. "a": "NYCNicks",
  439. "b": "ya",
  440. "c": "myc",
  441. },
  442. },
  443. result: []map[string]interface{}{{
  444. "a": "Ni",
  445. }},
  446. },
  447. {
  448. sql: "SELECT substring(a, 3, 100) AS a FROM test",
  449. data: &xsql.Tuple{
  450. Emitter: "test",
  451. Message: xsql.Message{
  452. "a": "NYCNicks",
  453. "b": "ya",
  454. "c": "myc",
  455. },
  456. },
  457. result: []map[string]interface{}{{
  458. "a": "Nicks",
  459. }},
  460. },
  461. {
  462. sql: "SELECT substring(a, 88, 100) AS a FROM test",
  463. data: &xsql.Tuple{
  464. Emitter: "test",
  465. Message: xsql.Message{
  466. "a": "NYCNicks",
  467. "b": "ya",
  468. "c": "myc",
  469. },
  470. },
  471. result: []map[string]interface{}{{
  472. "a": "",
  473. }},
  474. },
  475. {
  476. sql: "SELECT substring(a, 100) AS a FROM test",
  477. data: &xsql.Tuple{
  478. Emitter: "test",
  479. Message: xsql.Message{
  480. "a": "NYCNicks",
  481. "b": "ya",
  482. "c": "myc",
  483. },
  484. },
  485. result: []map[string]interface{}{{
  486. "a": "",
  487. }},
  488. },
  489. {
  490. sql: "SELECT substring(a, 100) AS a FROM test",
  491. data: &xsql.Tuple{
  492. Emitter: "test",
  493. Message: xsql.Message{
  494. "a": "NYCNicks",
  495. "b": "ya",
  496. "c": "myc",
  497. },
  498. },
  499. result: []map[string]interface{}{{
  500. "a": "",
  501. }},
  502. },
  503. {
  504. sql: "SELECT substring(d, 3, 100) AS bc FROM test",
  505. data: &xsql.Tuple{
  506. Emitter: "test",
  507. Message: xsql.Message{
  508. "a": "NYCNicks",
  509. "b": "ya",
  510. "c": "myc",
  511. },
  512. },
  513. result: []map[string]interface{}{{}},
  514. },
  515. {
  516. sql: "SELECT endswith(a, b) AS a FROM test",
  517. data: &xsql.Tuple{
  518. Emitter: "test",
  519. Message: xsql.Message{
  520. "a": "mya",
  521. "b": "ya",
  522. "c": "myc",
  523. },
  524. },
  525. result: []map[string]interface{}{{
  526. "a": true,
  527. }},
  528. },
  529. {
  530. sql: "SELECT endswith(a, c) AS a FROM test",
  531. data: &xsql.Tuple{
  532. Emitter: "test",
  533. Message: xsql.Message{
  534. "a": "mya",
  535. "b": "ya",
  536. "c": "myc",
  537. },
  538. },
  539. result: []map[string]interface{}{{
  540. "a": false,
  541. }},
  542. },
  543. {
  544. sql: "SELECT endswith(d, c) AS a FROM test",
  545. data: &xsql.Tuple{
  546. Emitter: "test",
  547. Message: xsql.Message{
  548. "a": "mya",
  549. "b": "ya",
  550. "c": "myc",
  551. },
  552. },
  553. result: []map[string]interface{}{{
  554. "a": false,
  555. }},
  556. },
  557. {
  558. sql: "SELECT trim(a) AS a FROM test",
  559. data: &xsql.Tuple{
  560. Emitter: "test",
  561. Message: xsql.Message{
  562. "a": " \ttrimme\n ",
  563. "b": "ya",
  564. "c": "myc",
  565. },
  566. },
  567. result: []map[string]interface{}{{
  568. "a": "trimme",
  569. }},
  570. },
  571. {
  572. sql: "SELECT upper(a) AS a FROM test",
  573. data: &xsql.Tuple{
  574. Emitter: "test",
  575. Message: xsql.Message{
  576. "a": "NYCNicks",
  577. "b": "ya",
  578. "c": "myc",
  579. },
  580. },
  581. result: []map[string]interface{}{{
  582. "a": "NYCNICKS",
  583. }},
  584. },
  585. {
  586. sql: `SELECT split_value(a,"/",0) AS a FROM test1`,
  587. data: &xsql.Tuple{
  588. Emitter: "test",
  589. Message: xsql.Message{
  590. "a": "test/device001/message",
  591. },
  592. },
  593. result: []map[string]interface{}{{
  594. "a": "test",
  595. }},
  596. },
  597. {
  598. sql: `SELECT split_value(a,"/",1) AS a FROM test1`,
  599. data: &xsql.Tuple{
  600. Emitter: "test",
  601. Message: xsql.Message{
  602. "a": "test/device001/message",
  603. },
  604. },
  605. result: []map[string]interface{}{{
  606. "a": "device001",
  607. }},
  608. },
  609. {
  610. sql: `SELECT split_value(a,"/",2) AS a FROM test1`,
  611. data: &xsql.Tuple{
  612. Emitter: "test",
  613. Message: xsql.Message{
  614. "a": "test/device001/message",
  615. },
  616. },
  617. result: []map[string]interface{}{{
  618. "a": "message",
  619. }},
  620. },
  621. {
  622. sql: `SELECT split_value(d,"/",2) AS a FROM test1`,
  623. data: &xsql.Tuple{
  624. Emitter: "test",
  625. Message: xsql.Message{
  626. "a": "test/device001/message",
  627. },
  628. },
  629. result: []map[string]interface{}{{}},
  630. },
  631. {
  632. sql: `SELECT split_value(a,"/",0) AS a, split_value(a,"/",3) AS b FROM test1`,
  633. data: &xsql.Tuple{
  634. Emitter: "test",
  635. Message: xsql.Message{
  636. "a": "/test/device001/message",
  637. },
  638. },
  639. result: []map[string]interface{}{{
  640. "a": "",
  641. "b": "message",
  642. }},
  643. },
  644. }
  645. fmt.Printf("The test bucket size is %d.\n\n", len(tests))
  646. contextLogger := conf.Log.WithField("rule", "TestStrFunc_Apply1")
  647. ctx := context.WithValue(context.Background(), context.LoggerKey, contextLogger)
  648. for i, tt := range tests {
  649. stmt, err := xsql.NewParser(strings.NewReader(tt.sql)).Parse()
  650. if err != nil || stmt == nil {
  651. t.Errorf("parse sql %s error %v", tt.sql, err)
  652. }
  653. pp := &ProjectOp{Fields: stmt.Fields}
  654. fv, afv := xsql.NewFunctionValuersForOp(nil)
  655. result := pp.Apply(ctx, tt.data, fv, afv)
  656. var mapRes []map[string]interface{}
  657. if v, ok := result.([]byte); ok {
  658. err := json.Unmarshal(v, &mapRes)
  659. if err != nil {
  660. t.Errorf("Failed to parse the input into map.\n")
  661. continue
  662. }
  663. //fmt.Printf("%t\n", mapRes["kuiper_field_0"])
  664. if !reflect.DeepEqual(tt.result, mapRes) {
  665. t.Errorf("%d. %q\n\nresult mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.sql, tt.result, mapRes)
  666. }
  667. } else {
  668. t.Errorf("%d. The returned result is not type of []byte\n", i)
  669. }
  670. }
  671. }