Skip to content
This repository has been archived by the owner on Dec 8, 2020. It is now read-only.

add tool: pluck multiple #36

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
24 changes: 24 additions & 0 deletions packages/tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,30 @@ import { atob } from "@timberio/tools";
console.log(atob("hello world")); // <-- returns "aGVsbG8gd29ybGQ="
```

### `pluckMultiple(source: { [key: string]: any }, paths: string[])`

Returns a new object with just those paths which is requested from source object.

** Usage example **

```typescript
import { pluckMultiple } from '@timberio/tools';
const paths = ["length", "response.status"];
const source = {
request: {
secure: true,
headers: { "content-type": "text/plain" },
href: "http://google.com/?q=whatever",
},
response: { status: 200 },
length: 40,
message: null,
};

const result = pluckMultiple(source, paths);
console.log(result); // { "length": 40, "response": { status: 200 }}
```

### LICENSE

[ISC](LICENSE.md)
4 changes: 3 additions & 1 deletion packages/tools/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Queue from "./queue";
import { base64Encode } from "./encode";
import makeBatch from "./batch";
import makeThrottle from "./throttle";
import pluckMultiple from "./pluck-multiple";

export {
// Types
Expand All @@ -12,5 +13,6 @@ export {
// Functions
base64Encode,
makeBatch,
makeThrottle
makeThrottle,
pluckMultiple,
};
119 changes: 119 additions & 0 deletions packages/tools/src/pluck-multiple.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import pluckMultiple from "./pluck-multiple";

describe("pluck multiple tests", () => {
it("should return an obj with given paths", () => {
const paths = ["length"];
const source = {
length: 40,
message: null,
};

const expected = { length: 40 };
expect(pluckMultiple(source, paths)).toEqual(expected);
});

it("should return an obj with given paths when nested ctx is given", () => {
const paths = ["length", "request.headers", "response.status"];
const source = {
request: {
secure: true,
headers: { "content-type": "text/plain" },
href: "http://google.com/?q=whatever",
},
response: { status: 200 },
length: 40,
message: null,
};

const expected = {
request: {
headers: { "content-type": "text/plain" },
},
length: 40,
response: { status: 200 },
};
expect(pluckMultiple(source, paths)).toEqual(expected);
});

it("should set undefined in destination if source does not have the path requested", () => {
const paths = ["length", "request.headers", "response.status", "foo.bar"];
const source = {
request: {
secure: true,
headers: { "content-type": "text/plain" },
href: "http://google.com/?q=whatever",
},
response: { status: 200 },
length: 40,
message: null,
};

const expected = {
request: {
headers: { "content-type": "text/plain" },
},
length: 40,
response: { status: 200 },
foo: {
bar: undefined,
},
};
expect(pluckMultiple(source, paths)).toEqual(expected);
});

it("shoudl work with path with same root like request.headers request.href", () => {
const paths = [
"length",
"request.headers",
"request.href",
"request.body.text",
"request.body.json.username",
"request.body.json.address.pin",
"response.status",
"foo.bar",
];

const source = {
request: {
secure: true,
headers: { "content-type": "text/plain" },
href: "http://google.com/?q=whatever",
body: {
json: {
username: "user123",
address: {
street: "str str",
pin: 300011,
},
},
text: "",
},
},
response: { status: 200 },
length: 40,
message: null,
};

const expected = {
request: {
headers: { "content-type": "text/plain" },
href: "http://google.com/?q=whatever",
body: {
json: {
username: "user123",
address: {
pin: 300011,
},
},
text: "",
},
},
length: 40,
response: { status: 200 },
foo: {
bar: undefined,
},
};
expect(pluckMultiple(source, paths)).toEqual(expected);
});
});
70 changes: 70 additions & 0 deletions packages/tools/src/pluck-multiple.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* gets the value from source for given path
*
* @param source - object
* @param path - string
*/
function get(source: object | any, path: string) {
let segs: string[] = path.split(".");

while (segs.length) {
let seg: string | undefined = segs.shift();
if (seg) {
if (source[seg] === undefined) return undefined;
source = source[seg];
}
}
return source;
}

/**
* sets the value for given path in the destination object
*
* @param destination - object
* @param path - string
* @param value - any
*/
function set(destination: { [key: string]: any }, path: string, value: any) {
const segs: string[] = path.split(".");

let seg: string | undefined = segs.shift();
let next: { [key: string]: any } = {};

if (seg) {
if (destination[seg]) {
next = destination[seg];
} else {
next = destination[seg] = !segs.length ? value : {};
}
}

while (segs.length) {
seg = segs.shift();
if (seg) {
if (!segs.length) {
next[seg] = value;
} else if (!next[seg]) {
next[seg] = {};
}
next = next[seg];
}
}
}

/**
* lets us request a 'path' of deeply nested object keys,
* and returns just those keys in a new object
*
* @param source - object
* @param paths - string[]
*/
export default function pluckMultiple(
source: { [key: string]: any },
paths: string[]
) {
const destination = {};
for (const path of paths) {
set(destination, path, get(source, path));
}
return destination;
}