rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
132 lines • 5.21 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OperatorTokenReader = void 0;
const BaseTokenReader_1 = require("./BaseTokenReader");
const Lexeme_1 = require("../models/Lexeme");
const charLookupTable_1 = require("../utils/charLookupTable");
const KeywordParser_1 = require("../parsers/KeywordParser");
const KeywordTrie_1 = require("../models/KeywordTrie");
const trie = new KeywordTrie_1.KeywordTrie([
// binary
["and"],
["or"],
["is"],
["is", "not"],
["is", "distinct", "from"],
["is", "not", "distinct", "from"],
["like"],
["in"],
["exists"],
["between"],
["not", "like"],
["not", "in"],
["not", "exists"],
["not", "between"],
["escape"], // e.g. '10% OFF on all items' like '10\%%' escape '\'
["uescape"], // e.g. U&'d!0061t!+000061' uescape '!'
["similar"], // e.g. substring('abcdef' similar '%#"cd#"%' escape '#')
["placing"], // e.g. overlay('abcdef' placing 'cd' from 3 for 2)
// unary
["not"],
// unary - trim
["both"],
["leading"],
["trailing"],
["both", "from"], // Postgres
["leading", "from"], // Postgres
["trailing", "from"], // Postgres
// unary - extract
["year", "from"],
["month", "from"],
["day", "from"],
["hour", "from"],
["minute", "from"],
["second", "from"],
["dow", "from"],
["doy", "from"],
["isodow", "from"],
["quarter", "from"],
["week", "from"],
["epoch", "from"],
["at", "time", "zone"],
// The following are not considered operators.
// ["from"], can be used as an operator only within the substring function, but it cannot be distinguished from the Form Clause. This will be resolved with a dedicated substring parser.
// ["for"], can be used as an operator only within the substring function, but it cannot be distinguished from the For Clause. This will be resolved with a dedicated substring parser.
]);
// Typed literal format
const operatorOrTypeTrie = new KeywordTrie_1.KeywordTrie([
["date"],
["time"],
["timestamp"],
["timestamptz"], // timestamp with time zone
["timetz"], // time with time zone
["interval"],
["boolean"],
["integer"],
["bigint"],
["smallint"],
["numeric"],
["decimal"],
["real"],
["double", "precision"],
["double", "precision"],
["character", "varying"],
["time", "without", "time", "zone"],
["time", "with", "time", "zone"],
["timestamp", "without", "time", "zone"],
["timestamp", "with", "time", "zone"],
]);
const keywordParser = new KeywordParser_1.KeywordParser(trie);
const operatorOrTypeParser = new KeywordParser_1.KeywordParser(operatorOrTypeTrie);
// Indicates the token may also represent a type (e.g., 'interval')
const MAYBE_TYPE = true;
class OperatorTokenReader extends BaseTokenReader_1.BaseTokenReader {
tryRead(previous) {
if (this.isEndOfInput()) {
return null;
}
/*
NOTE:
Asterisks could potentially be wildcard identifiers,
but since they're indistinguishable at this stage, they're treated as Operators at the token level.
The Parser needs to determine whether they are appropriate Operators or Identifiers.
*/
const char = this.input[this.position];
if (charLookupTable_1.CharLookupTable.isOperatorSymbol(char)) {
const start = this.position;
while (this.canRead() && charLookupTable_1.CharLookupTable.isOperatorSymbol(this.input[this.position])) {
// check for `--` and `/*` comments
if (this.canRead(1)) {
const current = this.input[this.position];
if (current === '-' && this.input[this.position + 1] === '-') {
break;
}
else if (current === '/' && this.input[this.position + 1] === '*') {
break; // end of operator
}
}
this.position++;
}
const resut = this.input.slice(start, this.position);
return this.createLexeme(Lexeme_1.TokenType.Operator, resut);
}
// Logical operators
let result = operatorOrTypeParser.parse(this.input, this.position);
if (result !== null) {
// Special handling for typed literal format.
// Treated as an operator in cases like `interval '2 days'`,
// but can also be used as a type in expressions like `'1 month'::interval`,
// so we return it as both Operator and Type.
this.position = result.newPosition;
return this.createLexeme(Lexeme_1.TokenType.Operator | Lexeme_1.TokenType.Type | Lexeme_1.TokenType.Identifier, result.keyword);
}
result = keywordParser.parse(this.input, this.position);
if (result !== null) {
this.position = result.newPosition;
return this.createLexeme(Lexeme_1.TokenType.Operator, result.keyword);
}
return null;
}
}
exports.OperatorTokenReader = OperatorTokenReader;
//# sourceMappingURL=OperatorTokenReader.js.map