本文来讲讲OPA
推导式(comprehensions),主要涉及三类数据的推导式:object,array,set
我们将以实现判断配置文件数据的不同聚合方式为例展开。
用到的输入(配置文件列表)为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
{ "files": [ { "type": "posix", "path": "/Users/newbmiao/Documents/1.yaml" }, { "type": "posix", "path": "/Users/newbmiao/Documents/2.yaml" }, { "type": "traditional-mac", "path": "Macintosh HD:Users:newbmiao:Documents:3.yml" }, { "type": "traditional-mac", "path": "Macintosh HD:Users:newbmiao:Documents:3.json" } ] }
|
comprehensions
推导式(comprehensions
)提供了一种从子查询构建复合值(Composite Values
)的简洁方法。
定义很晦涩,我们从例子来看会清晰许多
object comprehensions
首先看一个按文件路径类型聚合文件的例子:
1 2 3 4 5 6 7 8 9 10 11
| import input.files
group_files_by_type := {type: paths | file := files[_] type := file.type paths := [path | tmp := files[_] tmp.type == type path := tmp.path ] }
|
即两层遍历,外层遍历获取type
内层遍历按type
匹配推导出paths
数组
对应结果为
1 2 3 4 5 6 7 8 9 10 11 12 13
| opa eval -f values -d . -i input.json "data.example_comprehensions.group_files_by_type" [ { "posix": [ "/Users/newbmiao/Documents/1.yaml", "/Users/newbmiao/Documents/2.yaml" ], "traditional-mac": [ "Macintosh HD:Users:newbmiao:Documents:3.yml", "Macintosh HD:Users:newbmiao:Documents:3.json" ] } ]
|
忽略实现细节,对象的推导式语法为:
{ <key>: <term> | <body> }
定义的key
和term
需要在body
内赋值,最后会复合出一个对象,包含有所有满足的<key>: <term>
这里要注意的事body
内条件要都满足才会返回
array comprehensions
上边例子中paths
是一个数组推导式
其语法为: [ <term> | <body> ]
注意这里的[]
, 只有数组推导式用方括号
而且其内容是可重复的
对应再举一个将所有文件路径转为posix
的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| convert_all_to_posix_path_array := [path | path1 := [p | file := files[_] file.type == "posix" p := file.path ]
path2 := [p | file := files[_] file.type == "traditional-mac" p := replace(replace(file.path, "Macintosh HD", ""), ":", "/") ]
paths := array.concat(path1, path2) path = paths[_] ]
|
这里按文件路径类型推导出path1
和path2
两个数组
其内部对于file.type
的判断达到了过滤匹配的作用
set comprehensions
上边功能也可以用集合推导式实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| convert_all_to_posix_path_sets := {path | path1 := {p | file := files[_] file.type == "posix" p := file.path }
path2 := {p | file := files[_] file.type == "traditional-mac" p := replace(replace(file.path, "Macintosh HD", ""), ":", "/") }
paths := path1 | path2 path = paths[_] }
|
集合推导式语法为:
{ <term> | <body> }
其特点是不会重复
可以看出同样功能,集合做组合操作比较表意
类似的,交集可以用&
,差集可以用-
以上就是OPA
三类推导式的使用方式。推导式最大的特点就是简洁。
一旦你熟悉了,就可以写出很多优雅的聚合方式。
最后出一个题目,大家可以自己练习下(答案可以去opa-koans
中查看)
实现基于文件后缀聚合文件路径, 即输出为:
1 2 3 4 5 6 7 8 9 10 11 12
| { "json": [ "Macintosh HD:Users:newbmiao:Documents:3.json" ], "yaml": [ "/Users/newbmiao/Documents/1.yaml", "/Users/newbmiao/Documents/2.yaml" ], "yml": [ "Macintosh HD:Users:newbmiao:Documents:3.yml" ] }
|
提示, 对于文件后缀可以用如下两种方式获取
方式一: hardcode
extSets := ["yaml", "yml", "json"]
方式二:regex
1 2 3
| extSets := {e | e = regex.find_all_string_submatch_n(".*\\.(.*)$", files[_].path, -1)[0][1] }
|
本文代码详见:NewbMiao/opa-koans
下一篇,我们讲讲如何用OPA
的测试和压测保证规则的正确性与效率。
如有疑问,请文末留言交流或邮件:newbvirgil@gmail.com
本文链接 : https://newbmiao.github.io/2020/03/20/opa-comprehensions.html