rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
215 lines • 6.49 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CommandTokenReader = exports.commandKeywordTrie = exports.joinkeywordParser = void 0;
const BaseTokenReader_1 = require("./BaseTokenReader");
const Lexeme_1 = require("../models/Lexeme");
const KeywordTrie_1 = require("../models/KeywordTrie");
const KeywordParser_1 = require("../parsers/KeywordParser");
// Commands are those that require a dedicated parser.
// Keywords composed of multiple words are also considered commands.
// The exception is "type". Since types can be user-defined and cannot be accurately identified, they are treated as Identifiers.
const joinTrie = new KeywordTrie_1.KeywordTrie([
["join"],
["inner", "join"],
["cross", "join"],
["left", "join"],
["left", "outer", "join"],
["right", "join"],
["right", "outer", "join"],
["full", "join"],
["full", "outer", "join"],
["natural", "join"],
["natural", "inner", "join"],
["natural", "left", "join"],
["natural", "left", "outer", "join"],
["natural", "right", "join"],
["natural", "right", "outer", "join"],
["natural", "full", "join"],
["natural", "full", "outer", "join"],
// LATERAL JOIN patterns
["lateral", "join"],
["lateral", "inner", "join"],
["lateral", "left", "join"],
["lateral", "left", "outer", "join"],
]);
const keywordTrie = new KeywordTrie_1.KeywordTrie([
["with"],
["recursive"],
["materialized"],
["not", "materialized"],
["select"],
["from"],
["distinct"],
["distinct", "on"],
["where"],
["group", "by"],
["having"],
["order", "by"],
["limit"],
["offset"],
["fetch"],
["first"],
["next"],
["row"],
["row", "only"],
["rows", "only"],
["percent"],
["percent", "with", "ties"],
// for
["for"],
["update"],
["share"],
["key", "share"],
["no", "key", "update"],
// set operations
["union"],
["union", "all"],
["intersect"],
["intersect", "all"],
["except"],
["except", "all"],
// window functions
["window"],
["over"],
["partition", "by"],
["range"],
["rows"],
["groups"],
// aggregate functions with WITHIN GROUP
["within", "group"],
// table functions with WITH ORDINALITY
["with", "ordinality"],
// window frame
["current", "row"],
["unbounded", "preceding"],
["unbounded", "following"],
["preceding"],
["following"],
// table join commands
["on"],
["using"],
["lateral"],
// case
["case"],
["case", "when"],
["when"],
["then"],
["else"],
["end"],
// others
["insert", "into"],
["update"],
["delete", "from"],
["merge", "into"],
["matched"],
["not", "matched"],
["not", "matched", "by", "source"],
["not", "matched", "by", "target"],
["update", "set"],
["if", "not", "exists"],
["if", "exists"],
["do", "nothing"],
["insert", "default", "values"],
["values"],
["set"],
["returning"],
["create", "table"],
["create", "temporary", "table"],
["alter", "table"],
["drop", "table"],
["drop", "index"],
["drop", "constraint"],
["create", "index"],
["create", "unique", "index"],
["add"],
["add", "constraint"],
["constraint"],
["primary", "key"],
["unique"],
["unique", "key"],
["foreign", "key"],
["references"],
["check"],
["default"],
["not", "null"],
["null"],
["generated", "always"],
["generated", "always", "as", "identity"],
["generated", "by", "default"],
["generated", "by", "default", "as", "identity"],
["identity"],
["collate"],
["deferrable"],
["not", "deferrable"],
["initially", "immediate"],
["initially", "deferred"],
["match"],
["match", "full"],
["match", "partial"],
["match", "simple"],
["not", "valid"],
["on", "delete"],
["on", "update"],
["cascade"],
["restrict"],
["no", "action"],
["set", "null"],
["set", "default"],
["include"],
["only"],
["concurrently"],
["tablespace"],
["tablesample"],
// cast
["as"],
// odrder
["asc"],
["desc"],
["nulls", "first"],
["nulls", "last"],
]);
exports.commandKeywordTrie = keywordTrie;
const keywordParser = new KeywordParser_1.KeywordParser(keywordTrie);
exports.joinkeywordParser = new KeywordParser_1.KeywordParser(joinTrie);
class CommandTokenReader extends BaseTokenReader_1.BaseTokenReader {
tryRead(previous) {
if (this.isEndOfInput()) {
return null;
}
const keywordJoin = exports.joinkeywordParser.parse(this.input, this.position);
if (keywordJoin !== null) {
this.position = keywordJoin.newPosition;
return this.createLexeme(Lexeme_1.TokenType.Command, keywordJoin.keyword);
}
// Check for keyword identifiers
const keyword = keywordParser.parse(this.input, this.position);
if (keyword !== null) {
this.position = keyword.newPosition;
const lexeme = this.createLexeme(Lexeme_1.TokenType.Command, keyword.keyword, keyword.comments);
// Add positioned comments if comments exist (convert from keyword parser comments)
if (keyword.comments && keyword.comments.length > 0) {
lexeme.positionedComments = [{
position: 'after',
comments: keyword.comments
}];
}
return lexeme;
}
// check hint clause
if (this.canRead(2) && this.input[this.position] === '/' && this.input[this.position + 1] === '*' && this.input[this.position + 2] === '+') {
this.position += 3;
const start = this.position;
while (this.position + 1 < this.input.length) {
if (this.input[this.position] === '*' && this.input[this.position + 1] === '/') {
this.position += 2;
return this.createLexeme(Lexeme_1.TokenType.Command, '/*+ ' + this.input.slice(start, this.position - 2).trim() + ' */');
}
this.position++;
}
throw new Error(`Block comment is not closed. position: ${this.position}`);
}
return null;
}
}
exports.CommandTokenReader = CommandTokenReader;
//# sourceMappingURL=CommandTokenReader.js.map