专栏名称: 程序人生
十年漫漫程序人生,打过各种杂,也做过让我骄傲的软件;管理过数十人的团队,还带领一班兄弟姐妹创过业,目前在硅谷一家创业公司担任 VP。关注程序人生,了解程序猿,学做程序猿,做好程序猿,让我们的程序人生精彩满满。
目录
相关文章推荐
51好读  ›  专栏  ›  程序人生

renovate: 处理 Postgres 模式迁移

程序人生  · 公众号  · 程序员  · 2023-01-09 22:00

正文

请到「今天看啥」查看全文


table auth.users alter column created_at set default now ();
# then apply the changes $ renovate apply Your repo is dirty. Please commit the changes before applying.
$ git commit -a -m "add updated_at column and set default value for created_at"
# now you can directly apply # apply can use -p to run a previously saved plan or manually edited plan # the remove schema and the plan being executed will be saved in _meta/plans/202109301022/. $ renovate apply
The following SQLs will be applied:
alter table auth.users add column updated_at timestamptz not null ; alter table auth.users alter column created_at set default now ();
Continue (y/n)? y Successfully applied migration to postgres://user@localhost:5432/hello. Your repo is updated with the latest schema. See `git diff HEAD~1` for details.

我的大概想法是:用户可以创建一个 db schema repo,用 git 管理 schema 的修改。用户不必考虑 schema migration,只需在现有的 schema 上修改即可,当 renovate schema plan 时,Renovate 会通过 pg_dump 来获取远端的 schema,然后本地和和远端的 SQL 都会被解析成  AST,二者在 AST 级别对比找不同即可。

有了这个思路,接下来就是一些大的数据结构的定义,比如 postgres 下的一个 schema 可以这样描述:

pub struct Schema {    pub types: BTreeMap<String, DataType>,    pub tables: BTreeMap<String, Table>,    pub views: BTreeMap<String, View>,    pub functions: BTreeMap<String, Function>,    pub triggers: BTreeMap<String, Trigger>,}

一个 table 可以这么描述:

pub struct Table {    pub columns: BTreeMap,    pub constraints: BTreeMap,    pub privileges: BTreeMap,}

每个级别的数据都需要实现 Planner trait:

pub trait Planner {    fn diff(&self, remote: &Self) -> Vec;    fn plan(&self, diff: &[Diff]) -> Vec;}

这样,我们就可以从顶层的 schema 一层层追溯到一个 table 的 column 下的 constraint,进行 diff 并给出 migration plan。整体的架构如下(图是今天画的,大致思路没变):

思路有了,我就开始有一搭没一搭地为每个数据结构写一些基础的 parser,然后实现其 migration planner trait。最初,处理的都是一些比较容易的情况,比如用户修改 index 后,我们可以删除旧的 index,再创建新的 index,如下所示:







请到「今天看啥」查看全文