Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions lib/attrsets.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let
inherit (builtins) head length;
inherit (lib.trivial) mergeAttrs warn;
inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName;
inherit (lib.lists) foldr foldl' concatMap elemAt all partition groupBy take foldl;
inherit (lib.lists) foldr foldl' concatMap elemAt all partition groupBy take foldl intersectLists;
in

rec {
Expand Down Expand Up @@ -548,7 +548,7 @@ rec {

`names`

: A list of attribute names to get out of `set`
: A list of attribute names to get out of `attrs`

`attrs`

Expand All @@ -575,6 +575,44 @@ rec {
names:
attrs: genAttrs names (name: attrs.${name});

/**
Given a list of possible attribute names, return the set of
attribuets whose name is in the list from the given set.

It works like `getAttrs` when the first attribute is a list,
but skip attributes not in the input set
instead of throwing the "attribute is missing" error.

# Inputs

`names`

: A list of possible attribute names to get out of `attrs`.

`attrs`

: The set to get the existing named attribute from.

# Type

```
getOptionalAttrs :: [String] -> AttrSet -> AttrSet
```

# Example
:::{.example}

## `lib.attrsets.getOptionalAttrs` usage example
```nix
getOptionalAttrs [ "a" "b" "d" ] { a = 1; b = 2; c = 3; }
=> { a = 1; b = 2; }
```
:::
*/
getOptionalAttrs =
names:
attrs: getAttrs (intersectLists (attrNames attrs) names) attrs;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe an implementation using intersectAttrs would be more efficient.


/**
Collect each attribute named `attr` from a list of attribute
sets. Sets that don't contain the named attribute are ignored.
Expand Down
2 changes: 1 addition & 1 deletion lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ let
inherit (self.fixedPoints) fix fix' converge extends composeExtensions
composeManyExtensions makeExtensible makeExtensibleWithCustomName;
inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath
getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs
getAttrFromPath attrVals attrValues getAttrs getOptionalAttrs catAttrs filterAttrs
filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs
mapAttrs' mapAttrsToList attrsToList concatMapAttrs mapAttrsRecursive
mapAttrsRecursiveCond genAttrs isDerivation toDerivation optionalAttrs
Expand Down
41 changes: 41 additions & 0 deletions lib/tests/misc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ let
functionArgs
generators
genList
getAttrs
getOptionalAttrs
getExe
getExe'
groupBy
Expand Down Expand Up @@ -1854,6 +1856,45 @@ runTests {
};
};

testGetAttrsExample = {
expr = [
(getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; })
];
expected = [
{ a = 1; b = 2; }
];
};

testGetAttrsEmptyList = {
expr = getAttrs [ ] { a = 1; b = 2; c = 3; };
expected = { };
};

testGetAttrsEmpty = {
expr = getAttrs [ ] { };
expected = { };
};

testGetOptionalAttrsExample = {
expr = getOptionalAttrs [ "a" "b" "d" ] { a = 1; b = 2; c = 3; };
expected = { a = 1; b = 2; };
};

testGetOptionalAttrsEmptyNames = {
expr = getOptionalAttrs [ ] { a = 1; b = 2; c = 3; };
expected = { };
};

testGetOptionalAttrsEmptyValues = {
expr = getOptionalAttrs [ "a" "b" "d" ] { };
expected = { };
};

testGetOptionalAttrsEmpty = {
expr = getOptionalAttrs [ ] { };
expected = { };
};

## Levenshtein distance functions and co.
testCommonPrefixLengthEmpty = {
expr = strings.commonPrefixLength "" "hello";
Expand Down