OPA 进阶-简洁的推导式

2020-04-06 18:21:05 +08:00
 newmiao

本文来讲讲OPA推导式( comprehensions ),主要涉及三类数据的推导式:object,array,set

我们将以实现判断配置文件数据的不同聚合方式为例展开。

用到的输入(配置文件列表)为:

// input.json
// posix 为常见路径格式
// traditional-mac 为 mac 的一种文件路径格式
{
  "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

首先看一个按文件路径类型聚合文件的例子:

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数组

对应结果为

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> }

定义的keyterm需要在body内赋值,最后会复合出一个对象,包含有所有满足的<key>: <term>

这里要注意的事body内条件要都满足才会返回

array comprehensions

上边例子中paths是一个数组推导式

其语法为: [ <term> | <body> ]

注意这里的[], 只有数组推导式用方括号

而且其内容是可重复的

对应再举一个将所有文件路径转为posix的例子:

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[_]
]

这里按文件路径类型推导出path1path2两个数组

其内部对于file.type的判断达到了过滤匹配的作用

set comprehensions

上边功能也可以用集合推导式实现如下:

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中查看)

实现基于文件后缀聚合文件路径, 即输出为:

{
  "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

extSets := {e |
  e = regex.find_all_string_submatch_n(".*\\.(.*)$", files[_].path, -1)[0][1]
}

本文代码详见:NewbMiao/opa-koans

下一篇,我们讲讲如何用OPA的测试和压测保证规则的正确性与效率。

文章首发公众号:newbmiao

推荐阅读:OPA 系列

1189 次点击
所在节点    Go 编程语言
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/659885

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX