sequelize 是 Node 中使用比较多的一个 ORM 库,最近计划将项目中的 sequelize 升级至 V5 版本。
根据 升级文档,其中一项是即将禁用 String based operators,使用 Sequelize.Op 等 Symbol operators 来代替。
而 operator 主要用在查询条件中,用以生成查询条件,如
const where = { age: { $lte: 10 }}
// 替换为const replaceWhere = { age: { [Op.lte]: 10 }}const operatorsAliases = { $eq: Op.eq, $ne: Op.ne, $gte: Op.gte, $all: Op.all, $in: Op.in, ...moreAliase}简而言之,需要把本项目中的所有查询条件, 从 operatorsAliases 左边的替换为右边的。这也是本篇文章的主要内容
本文链接: https://blog.zhequtao.com/post/sequelize-op-replacement-and-sed/
准备工作
在开始工作之前,需要先把 git 的工作区和暂存区清理干净,避免替换过程中造成无法回退的尴尬局面。
把工作区和暂存区清理干净的意思就是,先把能 commit 的 commit 掉,不能 commit 的 stash 掉,当然切个新分支就更好了。
VS Code 全局替换
在刚开始随手手动替换了几个之后,觉得这样也不是办法,决定开始使用 VS Code 的全局替换。
首先思考一个查询的 operator 会出现的位置,无外乎以下几种
where.age = { $lte: 10 }where.age.$lte = 10where.age['$lte'] = 10另外,顺序很重要,从最具体到抽象的顺序如下
['$lte', Op.lte],['.$lte', [Op.lte]],['$lte', [Op.lte]]然后,按照顺序挨个替换就好了,但替换了几个知乎,我发现…我的耐心实在有限
> Object.keys(operatorsAliases).length34我需要替换 34 * 3 = 102 次,这也不能怪我烦啊,搁谁谁都没有耐心
使用 sed 命令替换文件
多掌握一个命令是多么重要
先来一个 hello, world 版的 sed 命令,以下命令把 hello 替换成 word
恩,sed 替换的语法和 vim 简直一模一样,这告诉我们掌握 vim 多么重要…
$ echo hello | sed "s/hello/world/g"world根据上一部分所讲的规则,写一个 sed 文件 (replace.sed),对示例(test.js)做一个测试
s/'$lte'/Op.lte/gs/.$lte/[Op.lte]/gs/$lte/[Op.lte]/gwhere.age = { $lte: 10 }where.age.$lte = 10where.age['$lte'] = 10做了简单的测试,输入以下命令,看起来工作地还不错
$ sed -f replace.sed test.jswhere.age = {[Op.lte]: 10 }where.age[Op.lte] = 10where.age[Op.lte] = 10但是有 34 个 alias 需要替换,利用浏览器的控制台生成 sed 文件
> Object.keys(operatorsAliases).map(op => op.slice(1)).flatMap(op => [`s/'\$${op}\b'/Op.${op}/g`, `s/\.\$${op}\b/[Op.${op}]/g`, `s/\$${op}\b/[Op.${op}]/g`]).join('\n')s/'$eq'/Op.eq/gs/.$eq/[Op.eq]/gs/$eq/[Op.eq]/gs/'$ne'/Op.ne/gs/.$ne/[Op.ne]/gs/$ne/[Op.ne]/g......虽然生成的命令有些简单粗暴…,不过简单粗暴的东西就是好用
替换项目下所有文件
只剩下一个问题,如何列出当前路径下的所有文件
多掌握一个命令是多么重要
我把所有我能想到的命令给列下来
find .应该可以排除掉 .gitignores 所列文件,但好像有点麻烦,我从来没用过。ls -R格式不够友好tree可读性不错,但机器可读性太差了
如何排除文件夹可以参考 How to exclude a directory in find . command
以上三个命令都不太好用。柳暗花明又一村,这里有一个更简单而又恰到好处的命令
git ls-files关于 git 的更多命令,可以参考 Git Cheat Sheets
此时,shell 命令如下,-i 代表直接替换文件,-i "" 代表替换时文件名不添加后缀,为啥一定要写个空字符串,因为 MAC 下的 sed 命令就是如此丧心病狂。
$ sed -i "" -f replace.sed $(git ls-files)不过,这时候有新的问题产生了,在 git diff 时发现有一些模板中带有 $index ,也会被替换成 [Op.in]dex,这是不期望的结果
git checkout .使用正则匹配
使用 \b 匹配单词,完美解决问题。
s/'\$eq\b'/Op.eq/gs/\.\$eq\b/[Op.eq]/gs/\$eq\b/[Op.eq]/g不过,在 MAC 下并不支持 \b,可以拿以下命令做个试验。这时候在 MAC 下需要安装 gnu-sed,终于把 MAC 下的 sed 命令替换掉了
$ echo "hello" | sed "s/\bhello\b/world/g"hello$ brew install gnu-sed$ echo "hello" | gsed "s/\bhello\b/world/g"world
# 一定一定要用双引号括起来$ echo "hello" | gsed s/\bhello\b/world/ghello这里有一个很重要的点,即sed命令一定要用双引号给括起来
使用 js 生成新的 sed 命令
Object.keys(operatorsAliases).map(op => op.slice(1)).flatMap(op => [`s/'\\$${op}\\b'/Op.${op}/g`, `s/\\.\\$${op}\\b/[Op.${op}]/g`, `s/\\$${op}\\b/[Op.${op}]/g`]).join('\n')最后执行命令,成功替换全部字符
# -i 代表直接替换文件,-r 代表支持扩展的正则表达式$ gsed -i -r -f r.sed $(git ls-files| grep -v src/data)
$ git diff --shortstat63 files changed, 293 insertions(+), 293 deletions(-)编译
项目使用的 typescript,最后编译出错。还有类似以下一种情况,手动改掉
const $or = {}const where = { $or}附录
sed 文件如下
s/'\$eq\b'/Op.eq/gs/\.\$eq\b/[Op.eq]/gs/\$eq\b/[Op.eq]/gs/'\$ne\b'/Op.ne/gs/\.\$ne\b/[Op.ne]/gs/\$ne\b/[Op.ne]/gs/'\$gte\b'/Op.gte/gs/\.\$gte\b/[Op.gte]/gs/\$gte\b/[Op.gte]/gs/'\$gt\b'/Op.gt/gs/\.\$gt\b/[Op.gt]/gs/\$gt\b/[Op.gt]/gs/'\$lte\b'/Op.lte/gs/\.\$lte\b/[Op.lte]/gs/\$lte\b/[Op.lte]/gs/'\$lt\b'/Op.lt/gs/\.\$lt\b/[Op.lt]/gs/\$lt\b/[Op.lt]/gs/'\$not\b'/Op.not/gs/\.\$not\b/[Op.not]/gs/\$not\b/[Op.not]/gs/'\$in\b'/Op.in/gs/\.\$in\b/[Op.in]/gs/\$in\b/[Op.in]/gs/'\$notIn\b'/Op.notIn/gs/\.\$notIn\b/[Op.notIn]/gs/\$notIn\b/[Op.notIn]/gs/'\$is\b'/Op.is/gs/\.\$is\b/[Op.is]/gs/\$is\b/[Op.is]/gs/'\$like\b'/Op.like/gs/\.\$like\b/[Op.like]/gs/\$like\b/[Op.like]/gs/'\$notLike\b'/Op.notLike/gs/\.\$notLike\b/[Op.notLike]/gs/\$notLike\b/[Op.notLike]/gs/'\$iLike\b'/Op.iLike/gs/\.\$iLike\b/[Op.iLike]/gs/\$iLike\b/[Op.iLike]/gs/'\$notILike\b'/Op.notILike/gs/\.\$notILike\b/[Op.notILike]/gs/\$notILike\b/[Op.notILike]/gs/'\$regexp\b'/Op.regexp/gs/\.\$regexp\b/[Op.regexp]/gs/\$regexp\b/[Op.regexp]/gs/'\$notRegexp\b'/Op.notRegexp/gs/\.\$notRegexp\b/[Op.notRegexp]/gs/\$notRegexp\b/[Op.notRegexp]/gs/'\$iRegexp\b'/Op.iRegexp/gs/\.\$iRegexp\b/[Op.iRegexp]/gs/\$iRegexp\b/[Op.iRegexp]/gs/'\$notIRegexp\b'/Op.notIRegexp/gs/\.\$notIRegexp\b/[Op.notIRegexp]/gs/\$notIRegexp\b/[Op.notIRegexp]/gs/'\$between\b'/Op.between/gs/\.\$between\b/[Op.between]/gs/\$between\b/[Op.between]/gs/'\$notBetween\b'/Op.notBetween/gs/\.\$notBetween\b/[Op.notBetween]/gs/\$notBetween\b/[Op.notBetween]/gs/'\$overlap\b'/Op.overlap/gs/\.\$overlap\b/[Op.overlap]/gs/\$overlap\b/[Op.overlap]/gs/'\$contains\b'/Op.contains/gs/\.\$contains\b/[Op.contains]/gs/\$contains\b/[Op.contains]/gs/'\$contained\b'/Op.contained/gs/\.\$contained\b/[Op.contained]/gs/\$contained\b/[Op.contained]/gs/'\$adjacent\b'/Op.adjacent/gs/\.\$adjacent\b/[Op.adjacent]/gs/\$adjacent\b/[Op.adjacent]/gs/'\$strictLeft\b'/Op.strictLeft/gs/\.\$strictLeft\b/[Op.strictLeft]/gs/\$strictLeft\b/[Op.strictLeft]/gs/'\$strictRight\b'/Op.strictRight/gs/\.\$strictRight\b/[Op.strictRight]/gs/\$strictRight\b/[Op.strictRight]/gs/'\$noExtendRight\b'/Op.noExtendRight/gs/\.\$noExtendRight\b/[Op.noExtendRight]/gs/\$noExtendRight\b/[Op.noExtendRight]/gs/'\$noExtendLeft\b'/Op.noExtendLeft/gs/\.\$noExtendLeft\b/[Op.noExtendLeft]/gs/\$noExtendLeft\b/[Op.noExtendLeft]/gs/'\$and\b'/Op.and/gs/\.\$and\b/[Op.and]/gs/\$and\b/[Op.and]/gs/'\$or\b'/Op.or/gs/\.\$or\b/[Op.or]/gs/\$or\b/[Op.or]/gs/'\$any\b'/Op.any/gs/\.\$any\b/[Op.any]/gs/\$any\b/[Op.any]/gs/'\$all\b'/Op.all/gs/\.\$all\b/[Op.all]/gs/\$all\b/[Op.all]/gs/'\$values\b'/Op.values/gs/\.\$values\b/[Op.values]/gs/\$values\b/[Op.values]/gs/'\$col\b'/Op.col/gs/\.\$col\b/[Op.col]/gs/\$col\b/[Op.col]/g欢迎关注我的公众号中关村程序员,我会定期分享一些前后端以及运维的文章,并且会有技术与生活上的每日回顾,欢迎关注交流
