@ 点击之家/ 数据类型分隔器
一个小的自成一体的 TypeScript 文库,用于解析一个 ClickHouse 数据类型
字符串 (以下列类型发送: RowBinaryWithNamesAndTypes,比如说.
Array(Nullable(UInt64)), (中文(简体) ), Tuple(a UInt8, b String), (中文(简体) ), Enum8('a' = 1), (中文(简体) ),
Decimal(10, 2)变成JSON AST.
这是C++的忠实端口 chdt 图书馆(见 ./reference-cpp-extracted-parser, (中文(简体) ),
它本身是从服务器提取的 ParserDataType
(单位:千美元)src/Parsers/ParserDataType.cpp) (中文(简体) ). 它已经 无运行时间依赖关系 - 仅限
节点.js标准库. 它的JSON 映射了数据类型的子树
冻结 EXPLAIN AST json = 1 文档(格式) 版本 2),因此其输出为 a
与服务器生成的相匹配的即时 字节相同 转到 C++
整个测试表的输出量.
安装并构建
npm install @clickhouse/datatype-parser
使用量
图书馆 :
import { parseDataType, toJSON } from "@clickhouse/datatype-parser";
const r = parseDataType("Tuple(a UInt8, b String)");
if (r.ok()) {
console.log(toJSON(r.ast!)); // pretty (2-space) JSON
console.log(toJSON(r.ast!, -1)); // compact JSON
} else {
console.error(r.error!.message, r.error!.position);
}
辅助
Tuple(
id UInt64,
name LowCardinality(String),
price Decimal(18, 4),
ts DateTime64(9, 'UTC'),
tags Array(LowCardinality(Nullable(String))),
attrs Map(String, Array(Nullable(Int32))),
status Enum8('active' = 1, 'closed' = -2),
coords Array(Tuple(Float64, Float64)),
meta Nested(k String, v UInt32),
fixed FixedString(16),
dyn Dynamic(max_types = 8),
variant Variant(UInt64, String, Array(UInt8)),
raw Object('json')
)
{
"type": "TupleDataType",
"name": "Tuple",
"arguments": [
{
"type": "DataType",
"name": "UInt64"
},
{
"type": "DataType",
"name": "LowCardinality",
"arguments": [
{
"type": "DataType",
"name": "String"
}
]
},
{
"type": "DataType",
"name": "Decimal",
"arguments": [
{
"type": "Literal",
"value_type": "UInt64",
"value": "18"
},
{
"type": "Literal",
"value_type": "UInt64",
"value": "4"
}
]
},
{
"type": "DataType",
"name": "DateTime64",
"arguments": [
{
"type": "Literal",
"value_type": "UInt64",
"value": "9"
},
{
"type": "Literal",
"value_type": "String",
"value": "UTC"
}
]
},
{
"type": "DataType",
"name": "Array",
"arguments": [
{
"type": "DataType",
"name": "LowCardinality",
"arguments": [
{
"type": "DataType",
"name": "Nullable",
"arguments": [
{
"type": "DataType",
"name": "String"
}
]
}
]
}
]
},
{
"type": "DataType",
"name": "Map",
"arguments": [
{
"type": "DataType",
"name": "String"
},
{
"type": "DataType",
"name": "Array",
"arguments": [
{
"type": "DataType",
"name": "Nullable",
"arguments": [
{
"type": "DataType",
"name": "Int32"
}
]
}
]
}
]
},
{
"type": "EnumDataType",
"name": "Enum8",
"values": [
{
"name": "active",
"value": 1
},
{
"name": "closed",
"value": -2
}
]
},
{
"type": "DataType",
"name": "Array",
"arguments": [
{
"type": "TupleDataType",
"name": "Tuple",
"arguments": [
{
"type": "DataType",
"name": "Float64"
},
{
"type": "DataType",
"name": "Float64"
}
]
}
]
},
{
"type": "DataType",
"name": "Nested",
"arguments": [
{
"type": "NameTypePair",
"name": "k",
"data_type": {
"type": "DataType",
"name": "String"
}
},
{
"type": "NameTypePair",
"name": "v",
"data_type": {
"type": "DataType",
"name": "UInt32"
}
}
]
},
{
"type": "DataType",
"name": "FixedString",
"arguments": [
{
"type": "Literal",
"value_type": "UInt64",
"value": "16"
}
]
},
{
"type": "DataType",
"name": "Dynamic",
"arguments": [
{
"type": "Function",
"name": "equals",
"is_operator": true,
"arguments": [
{
"type": "Identifier",
"name": "max_types"
},
{
"type": "Literal",
"value_type": "UInt64",
"value": "8"
}
]
}
]
},
{
"type": "DataType",
"name": "Variant",
"arguments": [
{
"type": "DataType",
"name": "UInt64"
},
{
"type": "DataType",
"name": "String"
},
{
"type": "DataType",
"name": "Array",
"arguments": [
{
"type": "DataType",
"name": "UInt8"
}
]
}
]
},
{
"type": "DataType",
"name": "Object",
"arguments": [
{
"type": "Literal",
"value_type": "String",
"value": "json"
}
]
}
],
"element_names": [
"id",
"name",
"price",
"ts",
"tags",
"attrs",
"status",
"coords",
"meta",
"fixed",
"dyn",
"variant",
"raw"
]
}
版式
模块结构跟踪 C++ 源 :
| 类型脚本 | 移植自( C++) | 角色 |
|---|---|---|
src/ast.ts | include/chdt/ast.h | aST 节点形状 + makeNode 工厂 |
src/lexer.ts | src/lexer.{h,cpp} | 专用的标识器 |
src/parser.ts | src/parser.cpp + 键 parser.h | 页:1 ParserDataType::parseImpl 端口 |
src/json.ts | src/json.cpp | 字节忠实的 JSON 序列器 |
src/index.ts | —— 说 | 公共枪管 |
Lexer 和 parser 故意保存原始控制流, 分支
命令、 助手姓名和 pos 保存/恢复点。 几个签名被更改了
其中C++使用外参数(std::string &: parseIdentifier 财务报告和审定财务报表
decodeQuoted 返回小结果对象.
发展
npm install
npm run build # emits dist/ (JS + .d.ts)
npm run typecheck # tsc --noEmit
输出形状
节点类型和槽匹配服务器(格式 v2) :
type | 插槽 |
|---|---|
DataType | name, (中文(简体) ), arguments? (如果类型有) (...)(中文(简体) ) |
EnumDataType | name, (中文(简体) ), values (数目 { name, value }(中文(简体) ) |
TupleDataType | name, (中文(简体) ), arguments?, (中文(简体) ), element_names? (名称为tuples) |
NameTypePair | name, (中文(简体) ), data_type 联合国 Nested(...) 要素) |
Literal | value_type, (中文(简体) ), value (64位英寸作为JSON弦) |
Function | name, (中文(简体) ), is_operator?, (中文(简体) ), arguments (例如:. max_types=5(中文(简体) ) |
Identifier | name, (中文(简体) ), name_parts? |
覆盖范围
支持的: 有字格的缩写为: scalars, 参数类型 :Decimal, (中文(简体) ),
FixedString, (中文(简体) ), DateTime64,.),巢型rg (Array, (中文(简体) ), Map, (中文(简体) ), Nullable, (中文(简体) ),
LowCardinality, (中文(简体) ), Variant(......),(说明) EnumDataType· ;
自动分配 + 通用 DataType),取名/无名/混合的 tu,, Nested, (中文(简体) ),
Dynamic(max_types = N)遗产 Object('json')标准
多词别名( e)DOUBLE PRECISION, (中文(简体) ), CHAR VARYING, (中文(简体) ), INT SIGNED(中文(简体) ).
故意不支持 (解析器返回一个明显的错误):
AggregateFunction编号 :SimpleAggregateFunction需要函数表达 解析服务器到达这里 .- 新建
JSON(...)对象参数语法( e)JSON(a.b UInt32, SKIP x)) (中文(简体) ). 裸体JSON遗产Object('json')精细.
测试
npm test # node:test: unit suite + snapshot corpus — NO clickhouse needed
npm run test:unsupported # asserts the deferred types are rejected
npm test 需求 没有 clickhouse 二进制 它完全反对
检查的固定装置 :
- 单位 (单位:千美元)
test/parser.test.ts)——将具有代表性的AST形状和所有 故意拒绝. - 简介 (单位:千美元)
test/snapshot.test.ts)——适用于每类test/cases.txt(356和计数),比较分析器的JSON 与入帐静态 真实服务器的快照data_type树下, 在test/snapshots/(一个)<sha1>.json(每个查询). 因为一个快照只有在 服务器接受类型 财务报告和审定财务报表 那个解剖师和它相符 "解剖师" 意思是"parser == 服务器".
重新生成/ 扩展快照包
从真正的服务器上捕捉到的快照 update_snapshots.ts,哪个
需要一个 clickhouse 二进制从
https://github.com/peter-leonov-ch/ ClickHouse/pull/1 (英语) (AST格式的更改)
此解析镜像存在于 PR; 股票构建将不匹配 :
npm run snapshot:update -- --clickhouse /path/to/clickhouse
它验证每类在 test/cases.txt 加上任何单位 test/candidates.txt
(额外类型的种子列表),只保留服务器接受的种子和
解析器匹配, 附加新保存者到 cases.txt,每个保存时写一个快照
查询,和孤儿。 输入服务器拒绝的或解析器有差异的地方
已删除并列入 test/snapshots_report.txt (从未默默地添加).
还有一个实时比较,可以跳过快照并询问服务器 直接, 有用时延时 :
npm run test:oracle -- --clickhouse /path/to/clickhouse
确认该实体是真实的(没有发明类型)
预告与服务器相比 解析器 (单位:千美元)ParserDataType页:1
图书馆的镜像 还要确认,所有类型的官司
是一个 真实 ClickHouse 类型——不仅在战术上造型良好——有一个
检查一下 即时 使用任何控股运行的服务器(无)
需要 AST-JSON 支持; 在 HTTP 接口上 :
npm run validate:live -- --url http://localhost:8124/
它运行 CREATE TEMPORARY TABLE _probe (c <TYPE>) (会议范围,无)
因此,未知类型
家庭失败 UNKNOWN_TYPE. 截至最近运行, 347/356 即时反应
而0是出乎意料的。 。 。 .
其余9个列于 test/non_instantiable.txt: 键入解析器
接受(并且其AST与服务器的解析器匹配)但服务器的 类型
工厂 后来拒绝——例如部分拖倒命名(Tuple(a UInt8, String), (中文(简体) ),
Nullable 内部 Variant, (中文(简体) ), Nullable(Tuple(...)), (中文(简体) ), Dynamic(max_types = 255), (中文(简体) ),
页:1 BINARY 没有大小的别名,还有遗产 Object('json') (删除于
最近的服务器). 这些是刻意的解析器测试输入, 这是类型字符串
解析器,而不是类型验证器——因此它们被允许列入清单,以及 validate:live
仅在一个 出乎预料 失败.