run_test.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. from pathlib import Path
  2. import sys
  3. import time
  4. from watchdog.observers import Observer
  5. from watchdog.events import FileSystemEventHandler
  6. from watchdog.events import LoggingEventHandler
  7. import asyncio.subprocess as subprocess
  8. import asyncio
  9. from watchfiles import awatch, watch
  10. from termcolor import colored
  11. from datetime import datetime
  12. import orjson
  13. import os
  14. async def assert_sql(sql, target):
  15. p = await subprocess.create_subprocess_exec(
  16. "xmake",
  17. "run",
  18. "sql-parser",
  19. sql,
  20. stdout=subprocess.PIPE,
  21. stderr=subprocess.PIPE,
  22. )
  23. stdout, stderr = await asyncio.wait_for(p.communicate(), timeout=5)
  24. if b"error" in stdout:
  25. print(stdout.decode("utf-8"))
  26. print(datetime.now(), "-" * 40)
  27. print(f'other: {colored(stderr.decode("utf-8"), "yellow")}')
  28. assert False, "sql-parser error"
  29. try:
  30. output = orjson.loads(stdout)
  31. except Exception as e:
  32. output = {"error": e, "output": stdout.decode("utf-8")}
  33. open("/tmp/temp/test.py", "wb").write(
  34. f'"{sql}"\n\n'.encode("utf-8")
  35. + orjson.dumps(output, option=orjson.OPT_INDENT_2)
  36. + (b"\n\n" + stderr).replace(b"\n", b"\n# ")
  37. )
  38. assert (
  39. output == target
  40. ), f"""{colored("sql-parser error", "red")}
  41. input: {colored(sql, "yellow")}
  42. expect: {colored(target, "green")}
  43. actual: {colored(output, "red")}
  44. other: {colored(stderr.decode("utf-8"), "yellow")}
  45. """
  46. async def assert_sqls():
  47. await assert_sql(
  48. "create table asd;", [{"type": "create_table", "table_name": "asd", "cols": []}]
  49. )
  50. await assert_sql(
  51. "create table tb (col1 INT, col2 string, col3 FLOAT);",
  52. [
  53. {
  54. "type": "create_table",
  55. "table_name": "tb",
  56. "cols": [
  57. {
  58. "type": "create_column",
  59. "column_name": "col1",
  60. "data_type": "INT",
  61. "primary_key": False,
  62. },
  63. {
  64. "type": "create_column",
  65. "column_name": "col2",
  66. "data_type": "string",
  67. "primary_key": False,
  68. },
  69. {
  70. "type": "create_column",
  71. "column_name": "col3",
  72. "data_type": "FLOAT",
  73. "primary_key": False,
  74. },
  75. ],
  76. }
  77. ],
  78. )
  79. await assert_sql(
  80. """
  81. create table tb1 (
  82. col1 int primary key,
  83. col2 FLOAT
  84. );
  85. """,
  86. [
  87. {
  88. "type": "create_table",
  89. "table_name": "tb1",
  90. "cols": [
  91. {
  92. "type": "create_column",
  93. "column_name": "col1",
  94. "data_type": "int",
  95. "primary_key": True,
  96. },
  97. {
  98. "type": "create_column",
  99. "column_name": "col2",
  100. "data_type": "FLOAT",
  101. "primary_key": False,
  102. },
  103. ],
  104. }
  105. ],
  106. )
  107. await assert_sql(
  108. """
  109. create table tb2 (
  110. x float,
  111. y int,
  112. z int
  113. );
  114. """,
  115. [
  116. {
  117. "type": "create_table",
  118. "table_name": "tb2",
  119. "cols": [
  120. {
  121. "type": "create_column",
  122. "column_name": "x",
  123. "data_type": "float",
  124. "primary_key": False,
  125. },
  126. {
  127. "type": "create_column",
  128. "column_name": "y",
  129. "data_type": "int",
  130. "primary_key": False,
  131. },
  132. {
  133. "type": "create_column",
  134. "column_name": "z",
  135. "data_type": "int",
  136. "primary_key": False,
  137. },
  138. ],
  139. }
  140. ],
  141. )
  142. await assert_sql(
  143. """insert into tb1 values (1, 'foo');""",
  144. [
  145. {
  146. "type": "insert",
  147. "table_name": "tb1",
  148. "values": [
  149. {"type": "int", "value": 1},
  150. {"type": "string", "value": "'foo'"},
  151. ],
  152. }
  153. ],
  154. )
  155. await assert_sql(
  156. """insert into tb1 values (2, 'foo', 'zxc', 1234.234);""",
  157. [
  158. {
  159. "type": "insert",
  160. "table_name": "tb1",
  161. "values": [
  162. {"type": "int", "value": 2},
  163. {"type": "string", "value": "'foo'"},
  164. {"type": "string", "value": "'zxc'"},
  165. {"type": "float", "value": 1234.234},
  166. ],
  167. }
  168. ],
  169. )
  170. await assert_sql(
  171. "update tb1 set col1=3, col4=4 where col1=2 and col2=4;",
  172. [
  173. {
  174. "type": "update",
  175. "table_name": "tb1",
  176. "set": [
  177. {
  178. "type": "assign_const",
  179. "left": {"type": "identifier", "value": "col1"},
  180. "right": {"type": "int", "value": 3},
  181. },
  182. {
  183. "type": "assign_const",
  184. "left": {"type": "identifier", "value": "col4"},
  185. "right": {"type": "int", "value": 4},
  186. },
  187. ],
  188. "where": {
  189. "type": "且",
  190. "left": {
  191. "type": "相等",
  192. "left": {"type": "identifier", "value": "col1"},
  193. "right": {"type": "int", "value": 2},
  194. },
  195. "right": {
  196. "type": "相等",
  197. "left": {"type": "identifier", "value": "col2"},
  198. "right": {"type": "int", "value": 4},
  199. },
  200. },
  201. }
  202. ],
  203. )
  204. await assert_sql(
  205. "update tb1 set col1=3, col4=4 where not not not col1=2 and col2=4 or col3=col2;",
  206. [
  207. {
  208. "type": "update",
  209. "table_name": "tb1",
  210. "set": [
  211. {
  212. "type": "assign_const",
  213. "left": {"type": "identifier", "value": "col1"},
  214. "right": {"type": "int", "value": 3},
  215. },
  216. {
  217. "type": "assign_const",
  218. "left": {"type": "identifier", "value": "col4"},
  219. "right": {"type": "int", "value": 4},
  220. },
  221. ],
  222. "where": {
  223. "type": "或",
  224. "left": {
  225. "type": "且",
  226. "left": {
  227. "type": "非",
  228. "left": {
  229. "type": "非",
  230. "left": {
  231. "type": "非",
  232. "left": {
  233. "type": "相等",
  234. "left": {"type": "identifier", "value": "col1"},
  235. "right": {"type": "int", "value": 2},
  236. },
  237. },
  238. },
  239. },
  240. "right": {
  241. "type": "相等",
  242. "left": {"type": "identifier", "value": "col2"},
  243. "right": {"type": "int", "value": 4},
  244. },
  245. },
  246. "right": {
  247. "type": "相等",
  248. "left": {"type": "identifier", "value": "col3"},
  249. "right": {"type": "identifier", "value": "col2"},
  250. },
  251. },
  252. }
  253. ],
  254. )
  255. await assert_sql(
  256. "delete from tb1 where c1 = 1 and c2= 3 or c3=3;",
  257. [
  258. {
  259. "type": "delete",
  260. "table_name": "tb1",
  261. "where": {
  262. "type": "或",
  263. "left": {
  264. "left": {
  265. "type": "相等",
  266. "left": {"type": "identifier", "value": "c1"},
  267. "right": {"type": "int", "value": 1},
  268. },
  269. "type": "且",
  270. "right": {
  271. "type": "相等",
  272. "left": {"type": "identifier", "value": "c2"},
  273. "right": {"type": "int", "value": 3},
  274. },
  275. },
  276. "right": {
  277. "type": "相等",
  278. "left": {"type": "identifier", "value": "c3"},
  279. "right": {"type": "int", "value": 3},
  280. },
  281. },
  282. }
  283. ],
  284. )
  285. await assert_sql(
  286. "delete from tb1 where c1 = 1 and (c2= 3 or c3=3) or (c4='asd');",
  287. [
  288. {
  289. "type": "delete",
  290. "table_name": "tb1",
  291. "where": {
  292. "type": "或",
  293. "left": {
  294. "type": "且",
  295. "left": {
  296. "type": "相等",
  297. "left": {"type": "identifier", "value": "c1"},
  298. "right": {"type": "int", "value": 1},
  299. },
  300. "right": {
  301. "type": "或",
  302. "left": {
  303. "type": "相等",
  304. "left": {"type": "identifier", "value": "c2"},
  305. "right": {"type": "int", "value": 3},
  306. },
  307. "right": {
  308. "type": "相等",
  309. "left": {"type": "identifier", "value": "c3"},
  310. "right": {"type": "int", "value": 3},
  311. },
  312. },
  313. },
  314. "right": {
  315. "type": "相等",
  316. "left": {"type": "identifier", "value": "c4"},
  317. "right": {"type": "string", "value": "'asd'"},
  318. },
  319. },
  320. }
  321. ],
  322. )
  323. await assert_sql(
  324. "select * from t2;",
  325. [
  326. {
  327. "type": "select",
  328. "select_cols": [{"type": "select_all_column"}],
  329. "table_name": "t2",
  330. "where": {},
  331. }
  332. ],
  333. )
  334. await assert_sql(
  335. "select c2 as t from t2 where col1>2;",
  336. [
  337. {
  338. "type": "select",
  339. "select_cols": [
  340. {
  341. "type": "select_column",
  342. "target": {"type": "identifier", "value": "c2"},
  343. "alias": "t",
  344. }
  345. ],
  346. "table_name": "t2",
  347. "where": {
  348. "type": "大于",
  349. "left": {"type": "identifier", "value": "col1"},
  350. "right": {"type": "int", "value": 2},
  351. },
  352. }
  353. ],
  354. )
  355. await assert_sql(
  356. """SELECT Sname FROM Student WHERE Sno IN (1,2) and c in (3, 4, 5);""",
  357. [
  358. {
  359. "type": "select",
  360. "select_cols": [
  361. {
  362. "type": "select_column",
  363. "target": {"type": "identifier", "value": "Sname"},
  364. }
  365. ],
  366. "table_name": "Student",
  367. "where": {
  368. "type": "且",
  369. "left": {
  370. "type": "包含于",
  371. "left": {"type": "identifier", "value": "Sno"},
  372. "right": [
  373. {"type": "int", "value": 1},
  374. {"type": "int", "value": 2},
  375. ],
  376. },
  377. "right": {
  378. "type": "包含于",
  379. "left": {"type": "identifier", "value": "c"},
  380. "right": [
  381. {"type": "int", "value": 3},
  382. {"type": "int", "value": 4},
  383. {"type": "int", "value": 5},
  384. ],
  385. },
  386. },
  387. }
  388. ],
  389. )
  390. await assert_sql(
  391. """SELECT Student.Sname
  392. FROM Student
  393. WHERE Sno IN (
  394. SELECT Sno
  395. FROM SC
  396. WHERE SC.Cno='81003'
  397. );
  398. """,
  399. [
  400. {
  401. "type": "select",
  402. "select_cols": [
  403. {
  404. "type": "select_column",
  405. "target": {
  406. "type": "table_field",
  407. "table": "Student",
  408. "field": "Sname",
  409. },
  410. }
  411. ],
  412. "table_name": "Student",
  413. "where": {
  414. "type": "包含于",
  415. "left": {"type": "identifier", "value": "Sno"},
  416. "right": {
  417. "type": "select",
  418. "select_cols": [
  419. {
  420. "type": "select_column",
  421. "target": {"type": "identifier", "value": "Sno"},
  422. }
  423. ],
  424. "table_name": "SC",
  425. "where": {
  426. "type": "相等",
  427. "left": {
  428. "type": "table_field",
  429. "table": "SC",
  430. "field": "Cno",
  431. },
  432. "right": {"type": "string", "value": "'81003'"},
  433. },
  434. },
  435. },
  436. }
  437. ],
  438. )
  439. await assert_sql(
  440. """
  441. select Student.Sname
  442. from Student join SC
  443. on Student.Sno=SC.Sno
  444. where SC.Cno='81003';
  445. """,
  446. [
  447. {
  448. "type": "select",
  449. "select_cols": [
  450. {
  451. "type": "select_column",
  452. "target": {
  453. "type": "table_field",
  454. "table": "Student",
  455. "field": "Sname",
  456. },
  457. }
  458. ],
  459. "table_name": "Student",
  460. "join_options": {
  461. "type": "join_options",
  462. "join_with": {"type": "identifier", "value": "SC"},
  463. "on": {
  464. "type": "相等",
  465. "left": {
  466. "type": "table_field",
  467. "table": "Student",
  468. "field": "Sno",
  469. },
  470. "right": {"type": "table_field", "table": "SC", "field": "Sno"},
  471. },
  472. },
  473. "where": {
  474. "type": "相等",
  475. "left": {"type": "table_field", "table": "SC", "field": "Cno"},
  476. "right": {"type": "string", "value": "'81003'"},
  477. },
  478. }
  479. ],
  480. )
  481. await assert_sql(
  482. """
  483. select Student.Sname
  484. from Student join SC
  485. on Student.Sno=SC.Sno
  486. and SC.Cno='81003';
  487. """,
  488. [
  489. {
  490. "type": "select",
  491. "select_cols": [
  492. {
  493. "type": "select_column",
  494. "target": {
  495. "type": "table_field",
  496. "table": "Student",
  497. "field": "Sname",
  498. },
  499. }
  500. ],
  501. "table_name": "Student",
  502. "join_options": {
  503. "type": "join_options",
  504. "join_with": {"type": "identifier", "value": "SC"},
  505. "on": {
  506. "type": "且",
  507. "left": {
  508. "type": "相等",
  509. "left": {
  510. "type": "table_field",
  511. "table": "Student",
  512. "field": "Sno",
  513. },
  514. "right": {
  515. "type": "table_field",
  516. "table": "SC",
  517. "field": "Sno",
  518. },
  519. },
  520. "right": {
  521. "type": "相等",
  522. "left": {
  523. "type": "table_field",
  524. "table": "SC",
  525. "field": "Cno",
  526. },
  527. "right": {"type": "string", "value": "'81003'"},
  528. },
  529. },
  530. },
  531. "where": {},
  532. }
  533. ],
  534. )
  535. async def on_modified(event):
  536. p = await subprocess.create_subprocess_shell(
  537. "xmake", stdout=subprocess.PIPE, stderr=subprocess.PIPE
  538. )
  539. stdout, _ = await p.communicate()
  540. if b"error" in stdout:
  541. print(stdout.decode("utf-8"))
  542. print(datetime.now(), "-" * 40)
  543. return
  544. try:
  545. await assert_sqls()
  546. except Exception as e:
  547. print(e)
  548. else:
  549. print(datetime.now(), colored("all tests right!", "green"))
  550. async def restart():
  551. async for _ in awatch(__file__):
  552. print("restart")
  553. os.execl("/bin/python", Path(__file__).as_posix(), Path(__file__).as_posix())
  554. async def watch_src():
  555. async for changes in awatch("src"):
  556. print(datetime.now(), "re run...")
  557. await asyncio.wait_for(on_modified(changes), 10)
  558. async def main():
  559. try:
  560. await assert_sqls()
  561. except Exception as e:
  562. print(e)
  563. await asyncio.gather(restart(), watch_src())
  564. if __name__ == "__main__":
  565. asyncio.run(main())