npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

iotdb-sql-parser

v1.0.1

Published

SQL Parser for IoTDB, built with antlr4, based on dt-sql-parser

Readme

iotdb-sql-parser

NPM version NPM downloads

iotdb-sql-parser 是一个基于 ANTLR4 开发的, 针对大数据领域的 SQL Parser 项目。通过ANTLR4 生成的 Parser、Visitor 和 Listener,我们可以轻松的做到对 SQL 语句的 词法分析(Lexer)、语法分析(Parser)、遍历 AST 节点等功能。

项目来源: 本项目基于 DTStack/dt-sql-parser 修改,专注于 IoTDB SQL 解析功能。

此外,还提供了一些高级功能,例如 SQL 校验自动补全收集表名字段名 等。

已支持的 SQL 类型:

  • IoTDB

提示:当前所有的 SQL Parser 是 Typescript 语言版本,如果有需要,可以尝试编译 Grammar 文件到其他目标语言。

与 MonacoEditor 集成

我们将会提供monaco-iotdb-languages,通过它你可以轻易的将iotdb-sql-parsermonaco-editor集成。

安装

# use npm
npm i iotdb-sql-parser --save

# use yarn
yarn add iotdb-sql-parser

使用

在开始使用前,需要先了解基本用法。iotdb-sql-parser 为不同类型的 SQL 分别提供相应的 SQL 类:

import { IoTDBTreeSQL, IoTDBTableSQL } from 'iotdb-sql-parser';

在使用语法校验,自动补全等功能之前,需要先实例化对应 SQL 类,以 IoTDBTableSQL 为例:

const iotdbTable = new IoTDBTableSQL();

下文中的使用示例将使用 IoTDBTableSQL,其他 SQL 类型的 Parser 使用方式与IoTDBTableSQL 相同。

语法校验(Syntax Validation)

先实例化 SQL 类,然后调用 SQL 实例上的 validate 方法对 SQL 语句进行校验,如果校验失败,则返回一个包含 error 信息的数组。

import { IoTDBTableSQL } from 'iotdb-sql-parser';

const iotdbTable = new IoTDBTableSQL();
const incorrectSql = 'selec id,name from user1;';
const errors = iotdbTable.validate(incorrectSql);

console.log(errors); 

输出:

/*
[
  {
    endCol: 5,
    endLine: 1,
    startCol: 0,
    startLine: 1,
    message: "...“
  }
]
*/

词法分析(Tokenizer)

通过调用 SQL 实例上的 getAllTokens方法,可以对 SQL 语句进行词法分析,获取所有的 Tokens 对象:

import { IoTDBTableSQL } from 'iotdb-sql-parser';

const iotdbTable = new IoTDBTableSQL();
const sql = 'select id,name,sex from user1;'
const tokens = iotdbTable.getAllTokens(sql);

console.log(tokens);

输出:

/*
[
  {
    channel: 0
    column: 0
    line: 1
    source: [SqlLexer, InputStream]
    start: 0
    stop: 5
    tokenIndex: -1
    type: 137
    _text: null
  },
  ...
]
*/

访问者模式(Visitor)

使用 Visitor 模式访问 AST 中的指定节点,并计算出结果:

import { IoTDBTableSQL, RelationalSqlParserVisitor } from 'iotdb-sql-parser';

const iotdbTable = new IoTDBTableSQL();
const sql = `select id, name from user1;`;
const parseTree = iotdbTable.parse(sql);

class MyVisitor extends RelationalSqlParserVisitor<string> {
    defaultResult(): string {
        return '';
    }
    aggregateResult(aggregate: string, nextResult: string): string {
        return aggregate + nextResult;
    }
    visitProgram = (ctx) => {
        return this.visitChildren(ctx);
    };
    visitTableName = (ctx) => {
        return ctx.getText();
    };
}
const visitor = new MyVisitor();
const result = visitor.visit(parseTree);

console.log(result);

输出:

/*
user1
*/

提示:使用 Visitor 模式时,节点的方法名称可以在对应 SQL 目录下的 Visitor 文件中查找

监听器(Listener)

Listener 模式,利用 ANTLR4 提供的 ParseTreeWalker 对象遍历 AST,进入各个节点时调用对应的方法。

import { IoTDBTableSQL, RelationalSqlParserListener } from 'iotdb-sql-parser';

const iotdbTable = new IoTDBTableSQL();
const sql = 'select id, name from user1;';
const parseTree = iotdbTable.parse(sql);

class MyListener extends RelationalSqlParserListener {
    result = '';
    enterTableName = (ctx): void => {
        this.result = ctx.getText();
    };
}

const listener = new MyListener();
iotdbTable.listen(listener, parseTree);

console.log(listener.result)

输出:

/*
user1
*/

SQL 按语句切割

调用 SQL 实例上的 splitSQLByStatement 方法,以 IoTDBTableSQL 为例:

import { IoTDBTableSQL } from 'iotdb-sql-parser';

const iotdbTable = new IoTDBTableSQL();
const sql = 'SHOW TABLES;\nSELECT * FROM tb;';
const sqlSlices = iotdbTable.splitSQLByStatement(sql);

console.log(sqlSlices)

输出:

/*
[
  {
    startIndex: 0,
    endIndex: 11,
    startLine: 1,
    endLine: 1,
    startColumn: 1,
    endColumn: 12,
    text: 'SHOW TABLES;'
  },
  {
    startIndex: 13,
    endIndex: 29,
    startLine: 2,
    endLine: 2,
    startColumn: 1,
    endColumn: 17,
    text: 'SELECT * FROM tb;'
  }
]
*/

自动补全(Code Completion)

在 sql 文本的指定位置上获取自动补全信息,以 IoTDBTableSQL 为例,调用 SQL 实例上的 getSuggestionAtCaretPosition 方法,传入 sql 文本和指定位置的行列号:

下文中有一些关于自动补全位置的补充说明。

  • 获取关键字候选项列表

    import { IoTDBTableSQL } from 'iotdb-sql-parser';
    
    const iotdbTable = new IoTDBTableSQL();
    const sql = 'CREATE ';
    const pos = { lineNumber: 1, column: 16 }; // 最后一个位置
    const keywords = iotdbTable.getSuggestionAtCaretPosition(sql, pos)?.keywords;
    
    console.log(keywords);

    输出:

    /*
    [ 'CATALOG', 'FUNCTION', 'TEMPORARY', 'VIEW', 'DATABASE', 'TABLE' ] 
    */ 
  • 获取语法相关自动补全信息

    import { IoTDBTableSQL } from 'iotdb-sql-parser';
    
    const iotdbTable = new IoTDBTableSQL();
    const sql = 'SELECT * FROM tb';
    const pos = { lineNumber: 1, column: 16 }; // tb 的后面
    const syntaxSuggestions = iotdbTable.getSuggestionAtCaretPosition(sql, pos)?.syntax;
    
    console.log(syntaxSuggestions);

    输出:

    /*
    [
      {
        syntaxContextType: 'table',
        wordRanges: [
          {
            text: 'tb',
            startIndex: 14,
            stopIndex: 15,
            line: 1,
            startColumn: 15,
            stopColumn: 16
          }
        ]
      },
      {
        syntaxContextType: 'view',
        wordRanges: [
          {
            text: 'tb',
            startIndex: 14,
            stopIndex: 15,
            line: 1,
            startColumn: 15,
            stopColumn: 16
          }
        ]
      }
    ]
    */

语法相关自动补全信息返回一个数组,数组中每一项代表该位置可以填写什么语法,比如上例中的输出结果代表该位置可以填写表名或者视图名称。其中 syntaxContextType 是可以补全的语法类型,wordRanges 是已经填写的内容。

获取 SQL 中出现的实体(表名、字段名等)

调用 SQL 实例上的 getAllEntities 方法,传入 sql 文本和指定位置的行列号即可轻松获取。

  import { IoTDBTableSQL } from 'iotdb-sql-parser';

  const iotdbTable = new IoTDBTableSQL();
  const sql = 'SELECT * FROM tb;';
  const pos = { lineNumber: 1, column: 16 }; // tb 的后面
  const entities = iotdbTable.getAllEntities(sql, pos);

  console.log(entities);

输出

/*
  [
    {
      entityContextType: 'table',
      text: 'tb',
      position: {
        line: 1,
        startIndex: 14,
        endIndex: 15,
        startColumn: 15,
        endColumn: 17
      },
      belongStmt: {
        stmtContextType: 'selectStmt',
        position: [Object],
        rootStmt: [Object],
        parentStmt: [Object],
        isContainCaret: true
      },
      relatedEntities: null,
      columns: null,
      isAlias: false,
      origin: null,
      alias: null
    }
  ]
*/

行列号信息不是必传的,如果传了行列号信息,那么收集到的实体中,如果实体位于对应行列号所在的语句下,那么实体的所属的语句对象上会带有 isContainCaret 标识,这在与自动补全功能结合时,可以帮助你快速筛选出需要的实体信息。

获取语义上下文信息

调用 SQL 实例上的 getSemanticContextAtCaretPosition 方法,传入 sql 文本和指定位置的行列号, 例如:

import { IoTDBTableSQL } from 'iotdb-sql-parser';

const iotdbTable = new IoTDBTableSQL();
const sql = 'SELECT * FROM tb;';
const pos = { lineNumber: 1, column: 18 }; // 'tb;' 的后面
const semanticContext = iotdbTable.getSemanticContextAtCaretPosition(sql, pos);

console.log(semanticContext);

输出

/*
{
  isStatementBeginning: true,
}
*/

目前能收集到的语义上下文信息如下,如果有更多的需求,欢迎提issue

  • isStatementBeginning 当前输入位置是否为一条语句的开头

默认情况下,isStatementBeginning 的收集策略为SqlSplitStrategy.STRICT

有两种可选策略:

  • SqlSplitStrategy.STRICT 严格策略, 仅以语句分隔符;作为上一条语句结束的标识
  • SqlSplitStrategy.LOOSE 宽松策略, 以语法解析树为基础分割SQL

两种策略的差异: 如输入SQL为

CREATE TABLE tb (id INT)

SELECT

CREATE语句后未添加分号,那么当获取SELECT后的语义上下文时, 在SqlSplitStrategy.STRICT策略下isStatementBeginningfalse, 因为CREATE语句未以分号结尾,那么会被认为这条语句尚未结束; 在SqlSplitStrategy.LOOSE策略下isStatementBeginningtrue, 因为语法解析树中这条SQL被拆分成了CREATE独立语句与SELECT独立语句。

可以通过第三个options参数设置策略:

iotdbTable.getSemanticContextAtCaretPosition(sql, pos, { splitSqlStrategy: SqlSplitStrategy.LOOSE });

其他 API

  • createLexer 创建一个 Antlr4 Lexer 实例并返回;
  • createParser 创建一个 Antlr4 Parser 实例并返回;
  • parse 解析输入的 sql,并返回解析树;

关于文本位置和文本范围

iotdb-sql-parser 提供的部分 API 的返回结果中包含文本信息,其中关于行号、列数以及索引的范围和起始值可能会带来一些困惑。

索引(index)

索引从 0 开始,在编程领域,索引从 0 开始更符合直觉

index-image

对于一个索引范围,起始索引从 0 开始,以 n-1 结束,如上图中,一个圈定蓝色文本的索引范围应该这样表示:

{
    startIndex: 0,
    endIndex: 3
}

行号(line)

行号(line)从 1 开始

line-image

对于一个圈定多行的范围,行号从 1 开始,以 n 结束,一个圈定第一行和第二行的范围这样表示:

{
    startLine: 1,
    endLine: 2
}

列数(column)

列数也从 1 开始

column-image

将列数类比为编辑器的光标位置会更加容易理解。对于一个圈定多列的范围,列数从 1 开始,以 n+1 结束,如上图中,一个圈定蓝色文本的列数范围这样表示:

{
    startColumn: 1,
    endColumn: 5
}

自动补全功能的 CaretPosition

iotdb-sql-parser 的自动补全功能在设计之初就是为了在编辑器中使用,所以 getSuggestionAtCaretPosition 方法的第二个参数(位置信息)的格式为行列号而不是字符位置索引。这可以让自动补全功能更容易的集成到编辑器中。对于编辑器来说,只需要在特定的时机获取编辑器内的文本内容以及光标位置即可调用 iotdb-sql-parser 的自动补全功能,而不需要任何额外的计算。

但是在一些其他场景下,你可能需要通过转换或者计算来得到自动补全功能所需要的位置信息,那么在此之前,有一些注意事项可能是你需要关心的。

iotdb-sql-parser 的自动补全功能依赖于 antlr4-c3,这是一个很棒的库。iotdb-sql-parser 的自动补全功能只是基于 antlr4-c3 做了一些封装和转换,包括将行列号信息转换成 antlr4-c3 需要的 token 索引,以下图为例:

column-image

将图中的 column 视作为光标位置,这段文本放到编辑器中,会得到 13 个可能的光标位置,而对于 iotdb-sql-parser 来说,这段文本被解析后会生成 4 个 Token。自动补全功能的一个重要策略是:当光标(自动补全位置)还没有完全离开某个 Token 时,iotdb-sql-parser 就认为这个 Token 还没有完成,自动补全功能将会去推断这个 Token 所在的位置可以填什么。

举个例子,如果想要通过自动补全功能知道 SHOW 后面应该填什么, 那么对应的位置信息应该是:

{
    lineNumber: 1,
    column: 6
}

此时,iotdb-sql-parser 会认为 SHOW 已经是一个完整的 Token 了,应该去推断 SHOW 后面可以填什么。如果传入的位置信息中 column 是 5, 那么 iotdb-sql-parser 会认为 SHOW 还没有被完成,进而去推断 SHOW 的位置可以填什么。也即在上图中 column: 5 属于 token: 0column: 6 属于 token: 1

对于编辑器来说,这种策略也更符合直觉。当用户输入了 SHOW 以后,在没有敲击空格键之前,用户大概率还没有输入完成,也许用户想要输入的是 SHOWS 之类的。当用户敲击了空格键,编辑器会认为用户想要输入下一个 Token,是时候询问 iotdb-sql-parser 下一个 Token 位置可以填哪些东西了。

贡献指南

CONTRIBUTING

致谢

本项目基于 DTStack/dt-sql-parser 开发,感谢 DTStack 团队的优秀工作。

许可证

本项目采用 Apache License 2.0 许可证。

本项目包含从 DTStack/dt-sql-parser 派生的代码,原项目采用 MIT 许可证。