Skip to content

Commit 1d0fc20

Browse files
authored
Feature DQL first non-null value of a list (#2543)
To be used in conjunction with defining inline fields in sublists/-tasks, and/or just to extract the first non-null value of any given list.
1 parent 0164e3a commit 1d0fc20

File tree

3 files changed

+27
-0
lines changed

3 files changed

+27
-0
lines changed

Diff for: docs/docs/reference/functions.md

+9
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,15 @@ nonnull([null, false]) = [false]
432432
nonnull([1, 2, 3]) = [1, 2, 3]
433433
```
434434
435+
### `firstvalue(array)`
436+
437+
Return the first non-null value from the array, as a single element. This can be used to pick the first defined field in the children of a task/list item, like in `firstvalue(children.myField)`.
438+
439+
```js
440+
firstvalue([null, 1, 2]) => 1
441+
firstvalue(children.myField) => If children.myField equals [null, null, "myValue", null], it would return "myValue"
442+
```
443+
435444
### `all(array)`
436445

437446
Returns `true` only if ALL values in the array are truthy. You can also pass multiple arguments to this function, in

Diff for: src/expression/functions.ts

+11
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,16 @@ export namespace DefaultFunctions {
878878
})
879879
.add1("null", () => null)
880880
.build();
881+
882+
// Returns the first non-null value from the array as a single element
883+
export const firstvalue = new FunctionBuilder("firstvalue")
884+
.add1("array", a => {
885+
let nonnull = a.filter(v => Values.typeOf(v) != "null");
886+
let res = nonnull.length != 0 ? nonnull[0] : null;
887+
return res;
888+
})
889+
.add1("null", () => null)
890+
.build();
881891
}
882892

883893
/** Default function implementations for the expression evaluator. */
@@ -919,6 +929,7 @@ export const DEFAULT_FUNCTIONS: Record<string, FunctionImpl> = {
919929
reverse: DefaultFunctions.reverse,
920930
length: DefaultFunctions.length,
921931
nonnull: DefaultFunctions.nonnull,
932+
firstvalue: DefaultFunctions.firstvalue,
922933
all: DefaultFunctions.all,
923934
any: DefaultFunctions.any,
924935
none: DefaultFunctions.none,

Diff for: src/test/function/aggregation.test.ts

+7
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,10 @@ describe("nonnull()", () => {
8383
test("empty", () => expectEvals("nonnull([])", []));
8484
test("[null, false]", () => expectEvals("nonnull([null, false])", [false]));
8585
});
86+
87+
describe("firstvalue()", () => {
88+
test("empty", () => expectEvals("firstvalue([])", null));
89+
test("null", () => expectEvals("firstvalue(null)", null));
90+
test("[1, 2, 3]", () => expectEvals("firstvalue([1, 2, 3])", 1));
91+
test("[null, 1, 2]", () => expectEvals("firstvalue([null, 1, 2])", 1));
92+
});

0 commit comments

Comments
 (0)