diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 29fde58b..9ba92c3e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,4 @@ ### Checklist - [ ] Pull request details were added to CHANGELOG.md +- [ ] Valid examples WDL's were added or updated to the SPEC.md (see the [guide](https://github.com/openwdl/wdl-tests/blob/main/docs/MarkdownTests.md) on writing markdown tests) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ebc07e2..2e5bd737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ version development consist of multiple files. [PR 241](https://github.com/openwdl/wdl/pull/241) by @cjllanwarne. + version 1.2.0 --------------------------- @@ -57,6 +58,9 @@ version 1.2.0 + Added `disks` and `gpu` reserved hints for requesting specific resources. ++ Added `contains_key` function to standard library. [PR 603](https://github.com/openwdl/wdl/pull/603) + + version 1.1.1 --------------------------- diff --git a/RFC.md b/RFC.md index 68bfa24e..b49f9723 100644 --- a/RFC.md +++ b/RFC.md @@ -3,7 +3,7 @@ RFC Process Most technical decisions are decided through the "RFC" ([Request for Comments](https://en.wikipedia.org/wiki/Request_for_Comments)) process. Small changes, such as minor grammatical edits to the specification, do not need to need to follow the RFC process. However, if one intends to make a substantive change to the WDL specification , the following process should be adhered to: - 1. Ideally have an informal discussion of the topic on the [mailing list](https://groups.google.com/forum/#!forum/openwdl) and/or the [gitter channel](https://gitter.im/openwdl/wdl) in order to gauge basic viability. As a rule of thumb, receiving encouraging feedback from long-standing community members is a good indication that the RFC is worth pursuing. + 1. Ideally have an informal discussion of the topic on [Slack](https://join.slack.com/t/openwdl/shared_invite/zt-ctmj4mhf-cFBNxIiZYs6SY9HgM9UAVw) and/or [GitHub discussions](https://github.com/openwdl/wdl/discussions) in order to gauge basic viability. As a rule of thumb, receiving encouraging feedback from long-standing community members is a good indication that the RFC is worth pursuing. 2. Write up a formal proposal, including requested changes to the current specification, as a pull request on GitHub 3. A core team member will be assigned as the *shepherd* of this RFC. The shepherd shall be responsible for keeping the discussion moving and ensuring all concerns are responded to. 4. Work to build broad support from the community. Encouraging people to comment, show support, show dissent, etc. Ultimately the level of community support for a change will decide its fate. diff --git a/SPEC.md b/SPEC.md index 6b2f1b54..ca900758 100644 --- a/SPEC.md +++ b/SPEC.md @@ -179,6 +179,7 @@ Revisions to this specification are made periodically in order to correct errors - [`as_pairs`](#as_pairs) - [`as_map`](#as_map) - [`keys`](#keys) + - [✨ `contains_key`](#-contains_key) - [`collect_by_key`](#collect_by_key) - [Other Functions](#other-functions) - [`defined`](#defined) @@ -9819,6 +9820,98 @@ Example output:
+### ✨ `contains_key` + +``` +* Boolean contains_key(Map[P, Y], P) +* Boolean contains_key(Object, String) +* Boolean contains_key(Map[String, Y]|Struct|Object, Array[String]) +``` + +Given a key-value type collection (`Map`, `Struct`, or `Object`) and a key, tests whether the collection contains an entry with the given key. + +This function has thre variants: + +1. `Boolean contains_key(Map[P, Y], P)`: Tests whether the `Map` has an entry with the given key. If `P` is an optional type (e.g., `String?`), then the second argument may be `None`. +2. `Boolean contains_key(Object, String)`: Tests whether the `Object` has an entry with the given name. +3. `Boolean contains_key(Map[String, Y]|Struct|Object, Array[String])`: Tests recursively for the presence of a compound key within a nested collection. + +For the third variant, the first argument is a collection that may be nested to any level, i.e., contain values that are collections, which themselves may contain collections, and so on. The second argument is an array of keys that are resolved recursively. If the value associated with any except the last key in the array is `None` or not a collection type, this function returns `false`. + +For example, if the first argument is a `Map[String, Map[String, Int]]` and the second argument is `["foo", "bar"]`, then the outer `Map` is tested for the presence of key "foo", and if it is present, then its value is tested for the presence of key "bar". This only tests for the presence of the named element, *not* whether or not it is `defined`. + +**Parameters** + +1. `Map[P, Y]`|`Struct`|`Object`: Collection to search for the key. +2. `P|Array[String]`: The key to search. If the first argument is a `Map`, then the key must be of the same type as the `Map`'s key type. If the `Map`'s key type is optional then the key may also be optional. If the first argument is a `Map[String, Y]`, `Struct`, or `Object`, then the key may be either a `String` or `Array[String]`. + +**Returns**: `true` if the collection contains the key, otherwise false. + +**Example** + ++ Example input: + + ```json + { + "get_values.m": {"a": 1, "b": 2}, + "get_values.key1": "a", + "get_values.key2": "c", + "get_values.p1": { + "name": "John", + "details": { + "phone": "123-456-7890" + } + }, + "get_values.p2": { + "name": "Agent X" + } + } + ``` + + Example output: + + ```json + { + "get_ints_and_exts.i1": 1, + "get_ints_and_exts.i2": null, + "get_ints_and_exts.phone1": "123-456-7890", + "get_ints_and_exts.phone2": null, + } + ``` +
+