Gel CLI 实战:gel describe schema命令详解与原理剖析
【免费下载链接】edgedbGel supercharges Postgres with a modern data model, graph queries, Auth & AI solutions, and much more.项目地址: https://gitcode.com/gh_mirrors/ed/edgedb
gel describe schema是 Gel 官方 CLI 中用于对当前连接数据库执行 Schema 内省(introspection)的核心命令,它能在终端中直接输出整库的 SDL 结构描述,是开发者快速审查数据模型、准备迁移、编写测试与核对版本间差异的利器。读完本文,你将掌握该命令的完整语法、连接目标指定方式、SDL/DDL 输出格式的差异,以及其在 Gel 编译器(EdgeQL Compiler)中的底层实现原理。
本文内容以仓库文档 docs/reference/using/cli/gel_describe/gel_describe_schema.rst 为骨架,并结合 describe 语句参考、连接选项文档 及 编译器实现 进行深度扩充。
命令概览
gel describe schema的作用是:给出由连接选项所指定数据库的 Schema 的 SDL(Schema Definition Language)描述。
其命令行语法(synopsis)为:
gel describe schema [<options>]从命令归属上看,它位于gel describe命令组之下。该命令组是一系列 Schema 内省工具的集合,gel describe组包含两个子命令(见 gel_describe/index.rst):
| 子命令 | 说明 |
|---|---|
gel describe object | 描述一个具名的 Schema 对象(type、link、property、function 等) |
gel describe schema | 描述当前数据库(分支)的完整 Schema |
与 EdgeQLdescribe内省语句的关系
文档明确指出:gel describe schema是终端命令,其等价于 EdgeQL 内省语句describe schema as sdl(参见 describe 语句参考)。
也就是说,下面两种写法在语义上是等价的:
# CLI 方式 gel describe schema # EdgeQL 方式(在交互式 shell 或查询中) db> describe schema as sdl;describe语句本身支持三种输出格式,理解它们的差异有助于你准确使用 CLI 命令:
as ddl:输出完整的 DDL(Data Definition Language)定义,即create type ...、create constraint ...形式的迁移式语句。生成的 DDL 是某个 Schema 对象(或整个库)的完整有效定义,前提是其所引用的其他 Schema 对象已存在。as sdl:输出 SDL 定义,即type ... { ... }形式的声明式数据模型。SDL 是 Gel 推荐的声明式 Schema 表达方式,也是gel describe schemaCLI 命令的默认输出。生成的 SDL 同样是完整有效的定义。as text [verbose]:输出面向人的定义,与 SDL 类似,但会包含所有继承而来的细节。verbose模式会额外展示注解(annotations)与约束(constraints)等默认被省略的信息。
一个值得注意的细节是:describe语句的输出类型是str,但它不能作为表达式嵌入到查询中使用——它是一条专用的内省语句,而非普通函数。
CLI 默认输出 SDL 的含义
由于gel describe schema等价于describe schema as sdl,因此你在终端中运行它,得到的就是一段可以直接用于重建数据模型的 SDL 文本。同时,从编译器实现看,完整的 Schema 描述还支持 DDL 输出(详见下文"底层实现原理"一节),只是 CLI 命令将 SDL 作为默认与约定的输出格式。
连接目标:Connection Options
gel describe schema命令运行在它所连接的数据库上,因此指定连接目标的方式与所有 Gel CLI 命令一致——通过一组标准的连接选项(connection flags)。相关完整说明见 连接选项文档,其解析优先级为:
- 显式 flag 优先:CLI 始终尊重通过 flag 显式传入的连接参数;
- 环境变量:若未提供 flag,则使用环境变量(如
GEL_HOST、GEL_PORT、GEL_BRANCH等)来确定实例; - 项目目录:若没有环境变量,CLI 会检查当前工作目录是否位于某个已关联实例的项目目录内,并使用项目配置;
- 失败:以上条件都不满足时,命令报错退出。
常用连接参数如下(完整清单请查阅 gel_connopts.rst):
| 选项 | 说明 |
|---|---|
-I <name>, --instance=<name> | 指定要连接的命名实例;Gel Cloud 实例名格式为<org-name>/<instance-name>;覆盖 host/port |
--dsn=<dsn> | 指定连接 DSN;覆盖除密码外的所有其他选项 |
--credentials-file /path/to/file | 指向包含凭据的 JSON 文件 |
-H <hostname>, --host=<hostname> | 服务器主机名,默认取GEL_HOST环境变量 |
-P <port>, --port=<port> | TCP 端口,默认取GEL_PORT环境变量,否则为5656 |
--unix-path /path/to/socket | Unix socket 路径;若为目录,则按 port 与 admin 参数计算实际路径 |
--admin | 通过免密 Unix socket 连接,默认以超级用户权限连接 |
-u <username>, --user=<username> | 以指定用户连接,默认取GEL_USER,否则为 admin |
-b <branch_name>, --branch=<branch_name> | 指定分支名,默认取GEL_BRANCH;本地实例默认最近切换的分支或 main 分支 |
--password / --no-password | 强制/禁止密码提示 |
--password-from-stdin | 将标准输入的第一行作为密码 |
--tls-ca-file /path/to/cert | 校验服务器的证书(自签名服务器证书或 CA 证书) |
--tls-security <mode> | TLS 安全模式:default、strict、no_host_verification、insecure |
--secret-key <key> | 连接 Gel Cloud 实例的 secret key |
--wait-until-available=<wait_time> | 连接失败时持续重试,直至达到指定时长(如30s) |
--connect-timeout=<timeout> | 连接超时时间,默认10s |
注:在 EdgeDB 5 之前"分支"被称为"数据库",旧的
-d <dbname>, --database=<dbname>与GEL_DATABASE环境变量仍被保留以作向后兼容。
典型用法示例
# 使用当前项目关联的实例(最常见,自动解析连接参数) gel describe schema # 显式指定实例 gel describe schema -I my_instance # 指定主机、端口、分支 gel describe schema -H localhost -P 5656 -b main # 通过 DSN 连接远程实例 gel describe schema --dsn=gel://user:password@host:5656/main # 输出到文件,便于版本对比或迁移准备 gel describe schema > current_schema.sdl输出格式示例:从 CLI 到 EdgeQL
以下示例取自 describe 语句参考 并适配 CLI 视角。假设数据库中存在如下 SDL 数据模型:
abstract type Named { required name: str { delegated constraint exclusive; } } type User extending Named { required email: str { annotation title := 'Contact email'; } }在 EdgeQL shell 中执行describe schema;(其默认输出为 DDL 格式),可以得到整个数据库 Schema 的完整 DDL 描述:
db> describe schema; { "create module default if not exists; create abstract type default::Named { create required single property name -> std::str { create delegated constraint std::exclusive; }; }; create type default::User extending default::Named { create required single property email -> std::str { create annotation std::title := 'Contact email'; }; };" }而在 CLI 中执行gel describe schema(等价于describe schema as sdl),你将得到对应的声明式 SDL:
type default::User extending default::Named { required single property email -> std::str { annotation std::title := 'Contact email'; }; };两者的区别可以这样理解:
- SDL(CLI 默认):声明式模型,描述"Schema 长什么样",适合阅读、评审与作为数据模型的"真源(source of truth)";
- DDL:命令式变更,描述"如何创建出这样的 Schema",适合迁移脚本与从零建库。
屏蔽(Masking)警告
describe命令还具备一个实用特性:当用户自定义对象屏蔽(mask)了标准库中的同名对象时,它会给出警告提示。例如在default模块中自定义了len函数(计算向量长度),则会输出被屏蔽的内置std::len函数定义(以注释形式附在结果中),便于你意识到名称遮蔽问题。这也提醒我们:gel describe schema输出的不只是"我写了什么",还包含标准库被遮蔽对象的信息,是审计命名冲突的有效手段。
底层实现原理:编译器视角
从源码层面看,gel describe schema最终会转化为一条DescribeStmt(描述语句)并交由 EdgeQL 编译器处理。其关键实现在 edb/edgeql/compiler/stmt.py 的compile_DescribeStmt中(约 L860-L891):
if ql.object is qlast.DescribeGlobal.Schema: if ql.language is qltypes.DescribeLanguage.DDL: # DESCRIBE SCHEMA AS DDL text = s_ddl.ddl_text_from_schema( ctx.env.schema, ) elif ql.language is qltypes.DescribeLanguage.SDL: # DESCRIBE SCHEMA AS SDL text = s_ddl.sdl_text_from_schema( ctx.env.schema, ) else: raise errors.QueryError( f'cannot describe full schema as {ql.language}') # 结果以 std::str 字符串常量的形式返回给客户端 stmt.result = setgen.ensure_set( irast.StringConstant(value=text, typeref=ct), ctx=ictx, )从这段代码可以得出几个关键结论:
- 全库 Schema 描述支持两种语言:
DDL(通过s_ddl.ddl_text_from_schema)与SDL(通过s_ddl.sdl_text_from_schema),分别对应describe schema as ddl与describe schema as sdl。CLI 的gel describe schema约定使用 SDL。 - 描述文本生成于编译期:文本是基于编译上下文(
ctx.env.schema)中已解析的 Schema 对象实时生成的,而非查询数据库返回的原始元数据。 - 返回类型是字符串常量:最终以
std::str类型的StringConstant作为查询结果,这与文档中"输出类型为 str,但不能作为查询表达式"的描述一致。 - 非法组合会被拒绝:例如对全库 Schema 使用
as text(DescribeLanguage.Text)时会抛出QueryError("cannot describe full schema as ...")。
此外,同类命令describe config(数据库配置、实例配置)与describe roles(角色)也在这同一函数中处理(stmt.py L894-L920),分别通过config_desc.compile_describe_config与内置函数sys._describe_roles_as_ddl实现——这印证了describe是 Gel 内省体系中的统一入口。
在测试与工具链中的实际应用
describe schema as sdl在 Gel 自身测试基础设施中被广泛使用。例如 edb/testbase/server.py(约 L1926)中,测试框架通过:
orig_schema = await self.con.query_single('describe schema as sdl')在测试执行前后抓取 Schema 快照,用于校验 Schema 的等价性/一致性。这为你提供了该命令的另一种典型用途:在测试或 CI 中对 Schema 做前后对比,确保迁移或运行时变更符合预期。
实战场景小结
综合文档与源码,gel describe schema的高价值使用场景包括:
- 数据模型审查:快速查看整个库的 SDL 全貌,评审模型设计是否合理、命名是否一致;
- 迁移准备:在编写
gel migration create之前,用gel describe schema核对当前基线,明确即将发生的 Schema 变更; - 版本对比:将不同分支/实例的
gel describe schema输出分别保存为.sdl文件,用 diff 工具定位模型差异; - 测试断言:如 Gel 自身测试那样,在测试前后抓取 SDL 快照,验证操作后 Schema 的一致性(参见 edb/testbase/server.py);
- 命名冲突审计:关注输出中被标注为"被屏蔽"(masked)的标准库对象,及时处理命名遮蔽。
延伸阅读
- gel describe 命令组索引:
describe家族全部子命令概览; - gel describe object:描述单个具名 Schema 对象,支持
--verbose显示注解与约束等额外细节; - describe 语句参考:
as ddl/as sdl/as text [verbose]三种格式的完整说明与示例; - 连接选项文档:所有连接 flag 的完整清单与解析优先级;
- 注解(annotations) 与 约束(constraints):
verbose模式下额外展示的 Schema 细节的数据模型定义。
【免费下载链接】edgedbGel supercharges Postgres with a modern data model, graph queries, Auth & AI solutions, and much more.项目地址: https://gitcode.com/gh_mirrors/ed/edgedb
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考