A work-in-progress SQL parser written in TypeScript
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

parser.test.ts 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /* tslint:disable:no-unused-expression */
  2. import { expect } from "chai";
  3. import * as AST from "../src/ast";
  4. import { isError } from "../src/error";
  5. import Lexer from "../src/lexer";
  6. import Parser from "../src/parser";
  7. const parse = (source: string): AST.Statement[] => {
  8. const tokens = new Lexer(source).scan();
  9. if (isError(tokens)) {
  10. throw tokens.message;
  11. } else {
  12. const tree = new Parser(tokens).parse();
  13. if (isError(tree)) {
  14. throw tree.message;
  15. }
  16. return tree;
  17. }
  18. };
  19. describe("Parser", () => {
  20. it("should parse a number selection", () => {
  21. const tree = parse("select 5");
  22. expect(tree).to.deep.equal([
  23. new AST.SelectStatement({
  24. arguments: [new AST.Number(5)],
  25. }),
  26. ]);
  27. });
  28. it("should parse a multiple number selection", () => {
  29. const tree = parse("select 5, 6");
  30. expect(tree).to.deep.equal([
  31. new AST.SelectStatement({
  32. arguments: [new AST.Number(5), new AST.Number(6)],
  33. }),
  34. ]);
  35. });
  36. it("should parse a selection of identifiers", () => {
  37. const tree = parse("select a, b");
  38. expect(tree).to.deep.equal([
  39. new AST.SelectStatement({
  40. arguments: [new AST.Identifier("a"), new AST.Identifier("b")],
  41. }),
  42. ]);
  43. });
  44. it("should parse a selection of identifiers and numbers", () => {
  45. const tree = parse("select a, 5");
  46. expect(tree).to.deep.equal([
  47. new AST.SelectStatement({
  48. arguments: [new AST.Identifier("a"), new AST.Number(5)],
  49. }),
  50. ]);
  51. });
  52. it("should parse the from of a selection", () => {
  53. const tree = parse("select a from t");
  54. expect(tree).to.deep.equal([
  55. new AST.SelectStatement({
  56. arguments: [new AST.Identifier("a")],
  57. from: new AST.Identifier("t"),
  58. }),
  59. ]);
  60. });
  61. it("should parse aliases", () => {
  62. const tree = parse("select a as b");
  63. expect(tree).to.deep.equal([
  64. new AST.SelectStatement({
  65. arguments: [
  66. new AST.Alias(new AST.Identifier("a"), new AST.Identifier("b")),
  67. ],
  68. }),
  69. ]);
  70. });
  71. it("should parse aliases as from targets", () => {
  72. const tree = parse("select a from t as u");
  73. expect(tree).to.deep.equal([
  74. new AST.SelectStatement({
  75. arguments: [new AST.Identifier("a")],
  76. from: new AST.Alias(new AST.Identifier("t"), new AST.Identifier("u")),
  77. }),
  78. ]);
  79. });
  80. it("should not allow a number as a from target", () => {
  81. const fn = () => parse("select 1 from 2");
  82. expect(fn).to.throw("Unexpected token: { kind: NUMBER, value: 2 }");
  83. });
  84. it("should parse a where with a number", () => {
  85. const tree = parse("select a from b where 1");
  86. expect(tree).to.deep.equal([
  87. new AST.SelectStatement({
  88. arguments: [new AST.Identifier("a")],
  89. from: new AST.Identifier("b"),
  90. where: new AST.Number(1),
  91. }),
  92. ]);
  93. });
  94. it("should parse a where with an identifier", () => {
  95. const tree = parse("select a from b where c");
  96. expect(tree).to.deep.equal([
  97. new AST.SelectStatement({
  98. arguments: [new AST.Identifier("a")],
  99. from: new AST.Identifier("b"),
  100. where: new AST.Identifier("c"),
  101. }),
  102. ]);
  103. });
  104. it("should parse a where with an equality", () => {
  105. const tree = parse("select a from b where c = d");
  106. expect(tree).to.deep.equal([
  107. new AST.SelectStatement({
  108. arguments: [new AST.Identifier("a")],
  109. from: new AST.Identifier("b"),
  110. where: new AST.Binary({
  111. left: new AST.Identifier("c"),
  112. right: new AST.Identifier("d"),
  113. type: AST.BinaryExpressionTypes.EQUALITY,
  114. }),
  115. }),
  116. ]);
  117. });
  118. it("should parse a where with an addition", () => {
  119. const tree = parse("select a from b where c + d");
  120. expect(tree).to.deep.equal([
  121. new AST.SelectStatement({
  122. arguments: [new AST.Identifier("a")],
  123. from: new AST.Identifier("b"),
  124. where: new AST.Binary({
  125. left: new AST.Identifier("c"),
  126. right: new AST.Identifier("d"),
  127. type: AST.BinaryExpressionTypes.ADDITION,
  128. }),
  129. }),
  130. ]);
  131. });
  132. it("should parse a where with a subtraction", () => {
  133. const tree = parse("select a from b where c - d");
  134. expect(tree).to.deep.equal([
  135. new AST.SelectStatement({
  136. arguments: [new AST.Identifier("a")],
  137. from: new AST.Identifier("b"),
  138. where: new AST.Binary({
  139. left: new AST.Identifier("c"),
  140. right: new AST.Identifier("d"),
  141. type: AST.BinaryExpressionTypes.SUBTRACTION,
  142. }),
  143. }),
  144. ]);
  145. });
  146. it("should parse a where with a multiplication", () => {
  147. const tree = parse("select a from b where c * d");
  148. expect(tree).to.deep.equal([
  149. new AST.SelectStatement({
  150. arguments: [new AST.Identifier("a")],
  151. from: new AST.Identifier("b"),
  152. where: new AST.Binary({
  153. left: new AST.Identifier("c"),
  154. right: new AST.Identifier("d"),
  155. type: AST.BinaryExpressionTypes.MULTIPLICATION,
  156. }),
  157. }),
  158. ]);
  159. });
  160. it("should parse a where with a division", () => {
  161. const tree = parse("select a from b where c / d");
  162. expect(tree).to.deep.equal([
  163. new AST.SelectStatement({
  164. arguments: [new AST.Identifier("a")],
  165. from: new AST.Identifier("b"),
  166. where: new AST.Binary({
  167. left: new AST.Identifier("c"),
  168. right: new AST.Identifier("d"),
  169. type: AST.BinaryExpressionTypes.DIVISION,
  170. }),
  171. }),
  172. ]);
  173. });
  174. it("should parse a where with a complex binary expression", () => {
  175. const tree = parse("select a from b where c + d = e");
  176. expect(tree).to.deep.equal([
  177. new AST.SelectStatement({
  178. arguments: [new AST.Identifier("a")],
  179. from: new AST.Identifier("b"),
  180. where: new AST.Binary({
  181. left: new AST.Binary({
  182. left: new AST.Identifier("c"),
  183. right: new AST.Identifier("d"),
  184. type: AST.BinaryExpressionTypes.ADDITION,
  185. }),
  186. right: new AST.Identifier("e"),
  187. type: AST.BinaryExpressionTypes.EQUALITY,
  188. }),
  189. }),
  190. ]);
  191. });
  192. it("should parse a where with a boolean expression", () => {
  193. const tree = parse("select a from b where c and d");
  194. expect(tree).to.deep.equal([
  195. new AST.SelectStatement({
  196. arguments: [new AST.Identifier("a")],
  197. from: new AST.Identifier("b"),
  198. where: new AST.Binary({
  199. left: new AST.Identifier("c"),
  200. right: new AST.Identifier("d"),
  201. type: AST.BinaryExpressionTypes.AND,
  202. }),
  203. }),
  204. ]);
  205. });
  206. it("should parse chained ANDs", () => {
  207. const tree = parse("select a from b where c and d and e");
  208. expect(tree).to.deep.equal([
  209. new AST.SelectStatement({
  210. arguments: [new AST.Identifier("a")],
  211. from: new AST.Identifier("b"),
  212. where: new AST.Binary({
  213. left: new AST.Binary({
  214. left: new AST.Identifier("c"),
  215. right: new AST.Identifier("d"),
  216. type: AST.BinaryExpressionTypes.AND,
  217. }),
  218. right: new AST.Identifier("e"),
  219. type: AST.BinaryExpressionTypes.AND,
  220. }),
  221. }),
  222. ]);
  223. });
  224. it("should parse chained ORs", () => {
  225. const tree = parse("select a from b where c or d or e");
  226. expect(tree).to.deep.equal([
  227. new AST.SelectStatement({
  228. arguments: [new AST.Identifier("a")],
  229. from: new AST.Identifier("b"),
  230. where: new AST.Binary({
  231. left: new AST.Binary({
  232. left: new AST.Identifier("c"),
  233. right: new AST.Identifier("d"),
  234. type: AST.BinaryExpressionTypes.OR,
  235. }),
  236. right: new AST.Identifier("e"),
  237. type: AST.BinaryExpressionTypes.OR,
  238. }),
  239. }),
  240. ]);
  241. });
  242. it("should parse backticked column names", () => {
  243. const tree = parse("select `a` from b");
  244. expect(tree).to.deep.equal([
  245. new AST.SelectStatement({
  246. arguments: [new AST.Backtick(new AST.Identifier("a"))],
  247. from: new AST.Identifier("b"),
  248. }),
  249. ]);
  250. });
  251. it("should not allow unbalanced backticks", () => {
  252. const fn = () => parse("select `a from b");
  253. expect(fn).to.throw("Unexpected token: { kind: FROM }");
  254. });
  255. it("should parse backticked FROM targets", () => {
  256. const tree = parse("select a from `b`");
  257. expect(tree).to.deep.equal([
  258. new AST.SelectStatement({
  259. arguments: [new AST.Identifier("a")],
  260. from: new AST.Backtick(new AST.Identifier("b")),
  261. }),
  262. ]);
  263. });
  264. it("should parse backticked aliases", () => {
  265. const tree = parse("select a as `b`");
  266. expect(tree).to.deep.equal([
  267. new AST.SelectStatement({
  268. arguments: [new AST.Alias(new AST.Identifier("a"), new AST.Backtick(new AST.Identifier("b")))],
  269. }),
  270. ]);
  271. });
  272. it("should parse backticked aliases", () => {
  273. const tree = parse("select a as `b`");
  274. expect(tree).to.deep.equal([
  275. new AST.SelectStatement({
  276. arguments: [new AST.Alias(new AST.Identifier("a"), new AST.Backtick(new AST.Identifier("b")))],
  277. }),
  278. ]);
  279. });
  280. it("should parse backticked where operands", () => {
  281. const tree = parse("select a where `b` = `c`");
  282. expect(tree).to.deep.equal([
  283. new AST.SelectStatement({
  284. arguments: [new AST.Identifier("a")],
  285. where: new AST.Binary({
  286. left: new AST.Backtick(new AST.Identifier("b")),
  287. right: new AST.Backtick(new AST.Identifier("c")),
  288. type: AST.BinaryExpressionTypes.EQUALITY,
  289. }),
  290. }),
  291. ]);
  292. });
  293. it("should parse expressions as select arguments", () => {
  294. const tree = parse("select a = b");
  295. expect(tree).to.deep.equal([
  296. new AST.SelectStatement({
  297. arguments: [
  298. new AST.Binary({
  299. left: new AST.Identifier("a"),
  300. right: new AST.Identifier("b"),
  301. type: AST.BinaryExpressionTypes.EQUALITY,
  302. }),
  303. ],
  304. }),
  305. ]);
  306. });
  307. it("should parse dot operators", () => {
  308. const tree = parse("select a.b");
  309. expect(tree).to.deep.equal([
  310. new AST.SelectStatement({
  311. arguments: [
  312. new AST.Binary({
  313. left: new AST.Identifier("a"),
  314. right: new AST.Identifier("b"),
  315. type: AST.BinaryExpressionTypes.DOT,
  316. }),
  317. ],
  318. }),
  319. ]);
  320. });
  321. it("should parse parens", () => {
  322. const tree = parse("select a * (b + c)");
  323. expect(tree).to.deep.equal([
  324. new AST.SelectStatement({
  325. arguments: [
  326. new AST.Binary({
  327. left: new AST.Identifier("a"),
  328. right: new AST.Binary({
  329. left: new AST.Identifier("b"),
  330. right: new AST.Identifier("c"),
  331. type: AST.BinaryExpressionTypes.ADDITION,
  332. }),
  333. type: AST.BinaryExpressionTypes.MULTIPLICATION,
  334. }),
  335. ],
  336. }),
  337. ]);
  338. });
  339. it("should parse a parenthesized SELECT as a FROM target", () => {
  340. const tree = parse("select a from (select b)");
  341. expect(tree).to.deep.equal([
  342. new AST.SelectStatement({
  343. arguments: [
  344. new AST.Identifier("a"),
  345. ],
  346. from: new AST.SelectStatement({
  347. arguments: [new AST.Identifier("b")],
  348. }),
  349. }),
  350. ]);
  351. });
  352. it("should allow aliases on subselects", () => {
  353. const tree = parse("select a from (select b) as c");
  354. expect(tree).to.deep.equal([
  355. new AST.SelectStatement({
  356. arguments: [
  357. new AST.Identifier("a"),
  358. ],
  359. from: new AST.Alias(
  360. new AST.SelectStatement({
  361. arguments: [new AST.Identifier("b")],
  362. }),
  363. new AST.Identifier("c"),
  364. ),
  365. }),
  366. ]);
  367. });
  368. it("should parse SELECT *", () => {
  369. const tree = parse("select *");
  370. expect(tree).to.deep.equal([
  371. new AST.SelectStatement({
  372. arguments: [
  373. new AST.Star(),
  374. ],
  375. }),
  376. ]);
  377. });
  378. it("should parse * on the right hand side of a dot in a SELECT", () => {
  379. const tree = parse("select a.*");
  380. expect(tree).to.deep.equal([
  381. new AST.SelectStatement({
  382. arguments: [
  383. new AST.Binary({
  384. left: new AST.Identifier("a"),
  385. right: new AST.Star(),
  386. type: AST.BinaryExpressionTypes.DOT,
  387. }),
  388. ],
  389. }),
  390. ]);
  391. });
  392. it("should parse * on the right of a dot where the left is a backtick", () => {
  393. const tree = parse("select `a`.*");
  394. expect(tree).to.deep.equal([
  395. new AST.SelectStatement({
  396. arguments: [
  397. new AST.Binary({
  398. left: new AST.Backtick(new AST.Identifier("a")),
  399. right: new AST.Star(),
  400. type: AST.BinaryExpressionTypes.DOT,
  401. }),
  402. ],
  403. }),
  404. ]);
  405. });
  406. it("should not allow stars in arithmetic operations", () => {
  407. expect(() => parse("select 1 + *")).to.throw("Unexpected token: { kind: STAR }");
  408. expect(() => parse("select 1 + a.*")).to.throw("Unexpected token: { kind: STAR }");
  409. expect(() => parse("select * + 1")).to.throw("Unexpected token: { kind: PLUS }");
  410. expect(() => parse("select a.* + b.*")).to.throw("Unexpected token: { kind: PLUS }");
  411. expect(() => parse("select a from b where c.*")).to.throw("Unexpected token: { kind: STAR }");
  412. });
  413. });