资讯动态

Gel 内置迁移系统实战:用 watch、migration create 与数据迁移安全演进你的 Schema

发布时间:2026/9/23 12:01:56 来源:尧图企业网站定制
Gel 内置迁移系统实战用 watch、migration create 与数据迁移安全演进你的 Schema【免费下载链接】edgedbGel supercharges Postgres with a modern data model, graph queries, Auth AI solutions, and much more.项目地址: https://gitcode.com/gh_mirrors/ed/edgedbGelEdgeDB 的开源继任者即本仓库项目内置了一套烘焙在数据库里的迁移系统让你在开发过程中可以边改 Schema 边即时生效、随时把变更固化为可提交版本控制的迁移文件并在已有数据与新模式冲突时通过 fill 表达式安全完成数据迁移。读完本文你将掌握gel watch --migrate的实时开发循环、gel migration creategel migrate的固化提交流程以及如何用fill_expr、assert_exists、assert_single和类型转换处理带数据的状态变更。本文基于 docs/intro/migrations.rst 整理并辅以仓库源码印证其底层机制。一、迁移系统概览Schema 文件是唯一事实来源Gel 迁移系统的设计哲学与大多数 ORM 完全不同你直接编辑用 Schema 定义语言SDL编写的.gel文件数据库负责把这些文件翻译成实际的迁移动作。你不需要手写CREATE TABLE/ALTER TABLE也不需要维护与 Schema 脱节的迁移脚本——Schema 文件本身才是唯一事实来源迁移文件只是 Schema 演进历史的固化快照。从源码看迁移在 Gel 中是一等公民对象。在 edb/schema/migrations.py 中Migration类继承自so.Object其script字段存放完整的迁移脚本、sdl字段存放对应 Schema 定义还带有generated_by与message等元数据字段而MigrationCommand同一文件 L80 起负责执行迁移命令注释里明确区分了显式CREATE MIGRATION与由START MIGRATION产生的隐式CREATE MIGRATION两种路径——这正是交互式migration create与--dev-mode同步两条流程的底层体现。想跟随本文动手实践先通过gel project init新建项目它会自动创建实例与空 Schema 文件docs/intro/installation.rst、docs/intro/projects.rst 有完整说明。二、开发模式gel watch --migrate实现 Schema 热加载开发阶段最省心的做法是运行一个长驻命令让 Gel 替你监视 Schema 文件并自动把变更应用到数据库$ gel watch --migrate Hint: --migrate will apply any changes from your schema files to the database. When ready to commit your changes, use: 1) gel migration create to write those changes to a migration file, 2) gel migrate --dev-mode to replace all synced changes with the migration. Monitoring /home/instancename for changes in: --migrate: gel migration apply --dev-mode看到上面类似输出即表示一切就绪。watch是一个长驻进程你每保存一次.gel文件它就立即把差异应用到数据库底层执行的正是gel migration apply --dev-mode——把当前 Schema 与数据库实际状态之间的差异当作开发期同步直接应用不产生迁移文件。注意watch会把变更应用到本地开发实例不会自动写入迁移文件因此它非常适合快速迭代、试错的数据模型。注意如果 Schema 无法应用watch会在控制台输出错误。若你正通过客户端绑定执行查询下一次查询时该错误也会在该客户端处暴露——所以在改完 Schema 后若发现查询行为异常先回头看watch控制台的报错信息。目录约定与初始 Schema按约定Gel Schema 放在代码库根目录下的dbschema目录中项目根还有一个gel.toml配置文件. ├── dbschema │ └── default.gel # schema file (written by you) └── gel.toml编辑dbschema/default.gel在module default块内写下第一个 Schematype User { required name: str; } type Post { required title: str; required author: User; }通常把整个 Schema 放在单个文件中项目初始化生成的default文件即可但同样支持把 Schema 拆分到多个.gel文件中。保存后只要 Schema 合法watch就会把它应用进数据库。三、持续演进直接编辑 Schema 文件随着应用发展直接修改 Schema 文件即可。比如为Post增加一个关联的评论类型type User { required name: str; } type Post { required title: str; required author: User; } type Comment { required content: str; }保存的瞬间watch就开始把新 Schema 应用到数据库。这正是Schema 文件驱动开发的体验数据模型演进等于编辑文件数据库状态始终跟随。四、固化迁移gel migration create与交互式审批当你对 Schema 满意、准备锁定并提交版本控制时运行$ gel migration create其工作流程如下CLI 读取你的 Schema 文件并发送给当前活动的 Gel 实例实例把文件内容与当前 Schema 状态比对由数据库本身生成迁移计划这是本系统区别于传统工具的关键迁移计划不产自本地工具逻辑而是数据库内建的 diff 引擎迁移计划以交互方式逐条呈现给你审批每个检测到的 Schema 变更都会单独询问。审批时你有一系列命令可选y批准、n拒绝、q取消整个迁移?查看更多高级选项。$ gel migration create did you create object type default::Comment? [y,n,l,c,b,s,q,?] y did you create object type default::User? [y,n,l,c,b,s,q,?] y did you create object type default::Post? [y,n,l,c,b,s,q,?] y Created dbschema/migrations/00001.edgeql, id: hash审批完成后迁移被写入dbschema/migrations/00001.edgeql文件名按序号递增并带有全局唯一的迁移 id。这个迁移文件就是可以提交到版本控制、在团队中共享的Schema 演进记录。五、不迭代时的直达路径编辑 → 创建 → 应用watch适合持续迭代但如果你已经明确知道要改什么、想一次性锁定迁移可以跳过watch走三步流程编辑你的 Schema 文件用gel migration create创建迁移用gel migrate应用迁移。由于没有watch在背后自动同步Schema 文件的改动不会在保存时自动生效因此最后必须显式执行gel migrate$ gel migrate Applied m1virjowa... (00002.edgeql)应用成功后数据库即反映新的 Schema。这条路径也正是 CI/CD 与多环境部署的标准姿势迁移文件是幂等的、可审阅的、可回放的历史记录。六、数据迁移当 Schema 变更与存量数据冲突某些 Schema 变更会因现有数据而无法直接应用。设想给Post增加一个required body属性type User { required name: str; } type Post { required title: str; required body: str; required author: User; } type Comment { required content: str; }如果此前从没往数据库插入过Post对象一切顺利但更常见的情况是测试期间已经插入了若干Post。它们没有body而现在数据库被告知所有Post都必须有body——这个变更无法应用因为存量数据会破坏新约束。你有两种选择方案 A删除违规数据。直接删掉所有Post对象然后保存 Schemawatch就能应用变更db delete Post; { default::Post {id: a4a0a40c-d9f5-11ed-8912-1397f7af9fdf}, default::Post {id: cc051bea-d9f5-11ed-a26d-2b64b6b273a4} }方案 B使用 fill 表达式补齐数据推荐不丢数据。放弃watch改用手动创建并应用迁移的流程。运行gel migration create交互式计划生成器会要求你提供一个 EdgeQL 表达式用于把数据库现有内容映射到新 Schema$ gel migration create did you create property body of object type default::Post? [y,n,l,c,b,s,q,?] y Please specify an expression to populate existing objects in order to make property body of object type default::Post required: fill_expr因为body属性尚不存在数据库里所有Post都没有它。你提供的表达式会被用来给缺少该属性的每个Post对象赋予一个body。最简单的做法是给一个默认值fill_expr No content Created dbschema/migrations/00002.edgeql, id: m1pjiibv4sa4cao7txpgsbuw2erctmacyrj4qmn45ggapsaztmvxfa生成的迁移文件长什么样来看看新创建的00002.edgeqlCREATE MIGRATION m1pjiibv4sa4cao7txpgsbuw2erctmacyrj4qmn45ggapsaztmvxfa ONTO m1nlvzbm7buwktkp4vu4shylq6zp2shruokbbssyeidqmmmfqz77yq { ALTER TYPE default::Post { CREATE REQUIRED PROPERTY body: std::str { SET REQUIRED USING (No content); }; }; };结构清晰可见一个CREATE MIGRATION块ONTO子句指明该迁移基于的上一代迁移 id内部是ALTER TYPE语句创建Post.body作为 required 属性而你的 fill 表达式No content被原样写进了SET REQUIRED USING (...)。迁移文件的 id如m1pjiibv4sa4cao7txpgsbuw2erctmacyrj4qmn45ggapsaztmvxfa与上一代的 id 一起构成了可追溯的迁移链。从实现层面看fill 表达式正是通过 edb/pgsql/delta.py 的_alter_pointer_optionality落地到 PostgreSQL 的它会对指针的存储列执行ALTER TABLE ... ALTER COLUMN ... SET/DROP NOT NULL见 L4268-L4279并在fill_expr非空时生成 UPDATE 语句回填存量行。值得注意的细节是对于 multi 指针若没有提供 fill 表达式且指针变为 required代码会合成一个假的空集合类型转换表达式L4293-L4305其作用是在存在空值对象时主动触发错误防止静默产生违反约束的数据——这是 Gel 保证数据完整性的一个精巧设计。七、fill 表达式的高级玩法任意 EdgeQL 表达式fill 表达式不限于字符串字面量——你可以在其中使用任意 EdgeQL 表达式。以下三个特性在数据迁移中尤其常用表达式用途示例assert_exists运行时基数断言下界告诉 Gel 输入集合至少有一个元素否则抛错。适合用于我确信所有数据都已就绪若没有就失败的场景。fill_expr assert_exists(.body)assert_single运行时基数断言上界断言输入集合至多一个元素多于一个即抛CardinalityViolationError。适合把multi属性改成single的场景。fill_expr assert_single(.sheep)类型转换type cast把属性从一种类型转换为另一种类型时非常有用。cast_expr bigint.xp使用assert_exists时要注意如果你提供了类似assert_exists(.body)的 fill 表达式在迁移执行前必须自行确保所有Post都有body否则迁移会失败——它只是断言不会替你造数据。这些断言函数在仓库标准库中有明确定义edb/lib/std/20-genericfuncs.edgeql 中std::assert_single的注解明确写着检查输入集合至多包含一个元素否则抛出 CardinalityViolationErrorstd::assert_exists则检查至少包含一个元素两者都被标记为Immutable易变性并声明了preserves_optionality/preserves_upper_cardinality因此可以被迁移引擎安全地内联进回填 SQL 而不会破坏基数推断。相关的运行期错误处理可以在 edb/server/compiler/errormech.py 中找到线索。八、两种工作流的取舍与最佳实践把前面内容归纳一下Gel 提供两条互补的 Schema 演进路径场景推荐工作流是否生成迁移文件数据冲突处理快速迭代、原型验证gel watch --migrate编辑即生效否由watch控制台即时报错明确变更、锁定提交编辑 →gel migration create→gel migrate是交互式fill_expr回填团队协作 / CI / 生产部署基于迁移文件回放是版本控制在迁移文件中固化 fill 表达式实践建议开发期优先用watch --migrate让反馈循环最短提交前务必gel migration create生成可审阅的迁移文件并纳入版本控制涉及 required 新增 / 类型变更 / 基数变化时不要直接删数据用 fill 表达式在迁移中补齐或断言迁移文件是 Schema 演进的事实记录保持其可读、可回放是团队协作与生产发布的基础。延伸阅读Schema 迁移完整指南ref_migration_guide迁移技巧与注意事项ref_migration_tipsCLI 参考gel migration 相关命令ref_cli_gel_migration迁移系统的底层实现Schema 侧见 edb/schema/migrations.pyDDL 语法见 edb/edgeql/parser/grammar/ddl.py迁移测试覆盖见 tests/test_edgeql_ddl.py其中包含大量CREATE MIGRATION与迁移交互流程的用例【免费下载链接】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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价