flink-sql-language-server
Version:
A LSP-based language server for Apache Flink SQL
226 lines (225 loc) • 8.85 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeEdgesByNodeId = exports.addFromCreateContext = exports.ignoreInsertSource = exports.FlinkStructureListener = exports.StructureNodeTypeEnum = void 0;
const lsp = __importStar(require("vscode-languageserver"));
const protocol_translation_1 = require("../protocol-translation");
const utils_1 = require("../utils");
var StructureNodeTypeEnum;
(function (StructureNodeTypeEnum) {
StructureNodeTypeEnum["SINK"] = "sink";
StructureNodeTypeEnum["SINK_DB"] = "sink_db";
StructureNodeTypeEnum["SOURCE"] = "source";
StructureNodeTypeEnum["SOURCE_DB"] = "source_db";
StructureNodeTypeEnum["DIM"] = "dim";
StructureNodeTypeEnum["SNAPSHOT"] = "snapshot";
StructureNodeTypeEnum["VIEW"] = "view";
StructureNodeTypeEnum["SELECT"] = "select";
StructureNodeTypeEnum["FILTER"] = "filter";
StructureNodeTypeEnum["GROUP"] = "group";
StructureNodeTypeEnum["UNION"] = "union";
StructureNodeTypeEnum["EXCEPT"] = "except";
StructureNodeTypeEnum["INTERSECT"] = "intersect";
StructureNodeTypeEnum["JOIN"] = "join";
StructureNodeTypeEnum["TOP_N"] = "top_n";
StructureNodeTypeEnum["CORRELATE"] = "correlate";
StructureNodeTypeEnum["UD_TF"] = "ud_tf";
StructureNodeTypeEnum["CEP"] = "cep";
})(StructureNodeTypeEnum = exports.StructureNodeTypeEnum || (exports.StructureNodeTypeEnum = {}));
class FlinkStructureListener {
constructor(document) {
this.document = document;
this.nodes = [];
this.edges = [];
this.id = 0;
this.originalText = document.getText();
}
getId() {
this.id++;
return this.id;
}
addStructureNode(ctx, type, customName) {
if (!ctx.stop) {
return;
}
const range = lsp.Range.create(this.document.positionAt(ctx.start.startIndex), this.document.positionAt(ctx.stop.stopIndex + 1));
const newNode = {
id: this.getId(),
name: customName ?? this.document.getText(range).trim(),
type,
range
};
this.nodes.forEach(node => {
if ((0, protocol_translation_1.rangeInRange)(this.document, node.range, newNode.range)) {
const distance = (0, protocol_translation_1.rangeDistance)(this.document, node.range, newNode.range);
const existingEdges = this.edges.filter(e => e.to === newNode.id);
if (existingEdges.length === 0) {
this.edges.push({ from: node.id, to: newNode.id, distance });
}
else {
let minDistance = Infinity;
let directEdge;
existingEdges.forEach(edge => {
if (distance < edge.distance && minDistance > edge.distance) {
minDistance = edge.distance;
directEdge = edge;
}
});
if (directEdge) {
const index = this.edges.findIndex(e => e === directEdge);
this.edges.splice(index, 1);
this.edges.push({ from: node.id, to: newNode.id, distance });
}
}
}
});
this.nodes.push(newNode);
}
getNodes() {
return this.nodes;
}
getEdges() {
return this.edges.map(edge => ({
from: edge.from,
to: edge.to
}));
}
enterInsert(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.SINK);
}
enterQuery(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.SELECT);
}
enterWhere(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.FILTER);
}
enterGroupBy(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.GROUP);
}
enterOrderBy(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.TOP_N);
}
enterMatchRecognize(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.CEP);
}
enterMapQuery(ctx) {
if (ctx.UNION()) {
this.addStructureNode(ctx, StructureNodeTypeEnum.UNION);
}
else if (ctx.INTERSECT()) {
this.addStructureNode(ctx, StructureNodeTypeEnum.INTERSECT);
}
else if (ctx.EXCEPT()) {
this.addStructureNode(ctx, StructureNodeTypeEnum.EXCEPT);
}
}
enterMapTable(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.JOIN);
}
enterTableReference(ctx) {
if (ctx.tablePrimary().tableSource()?.tableDim()) {
this.addStructureNode(ctx, StructureNodeTypeEnum.DIM);
}
}
enterTableSource(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.SOURCE);
}
enterTableLateral(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.UD_TF);
}
enterCommaTable(ctx) {
if (ctx.tableExpr().tableReference().tablePrimary().tableSource()?.tableDim()) {
this.addStructureNode(ctx, StructureNodeTypeEnum.CORRELATE);
}
else {
this.addStructureNode(ctx, StructureNodeTypeEnum.JOIN);
}
}
enterAsTable(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.SOURCE);
}
enterCreateTable(ctx) {
if (ctx.asTable()) {
this.addStructureNode(ctx, StructureNodeTypeEnum.SINK);
}
}
enterAsDatabase(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.SOURCE_DB);
}
enterCreateDatabase(ctx) {
if (ctx.asDatabase()) {
this.addStructureNode(ctx, StructureNodeTypeEnum.SINK_DB);
}
}
enterCreateView(ctx) {
this.addStructureNode(ctx, StructureNodeTypeEnum.VIEW, ctx.view().text.trim());
}
}
exports.FlinkStructureListener = FlinkStructureListener;
function ignoreInsertSource(nodes, edges) {
for (let i = 0; i < edges.length; i++) {
const edge = edges[i];
const fromNode = nodes.find(node => node.id === edge.from);
const toNode = nodes.find(node => node.id === edge.to);
if (!fromNode || !toNode) {
return { nodes, edges };
}
if (fromNode.type === StructureNodeTypeEnum.SINK && toNode.type === StructureNodeTypeEnum.SOURCE) {
const newEdges = [...edges];
newEdges.splice(i, 1);
return { edges: newEdges, nodes: nodes.filter(n => n.id !== toNode.id) };
}
}
return { nodes, edges };
}
exports.ignoreInsertSource = ignoreInsertSource;
function addFromCreateContext(nodes, edges) {
const viewNodes = nodes.filter(node => node.type === StructureNodeTypeEnum.VIEW);
if (viewNodes.length > 0) {
nodes.forEach(node => {
if (node.type === StructureNodeTypeEnum.SOURCE) {
const matchedViewNode = viewNodes.find(view => view.name === node.name);
if (matchedViewNode) {
const sourceEdge = edges.find(edge => edge.to === node.id);
if (sourceEdge) {
const newEdge = {
from: sourceEdge.from,
to: matchedViewNode.id
};
(0, utils_1.removeElement)(node, nodes);
edges = removeEdgesByNodeId([node.id], [...edges]);
edges.push(newEdge);
}
}
}
});
}
return { nodes, edges };
}
exports.addFromCreateContext = addFromCreateContext;
function removeEdgesByNodeId(ids, edges) {
return edges.filter(edge => !ids.includes(edge.to) && !ids.includes(edge.from));
}
exports.removeEdgesByNodeId = removeEdgesByNodeId;
;