Skip to content

Commit

Permalink
Merge pull request #19 from specialblend/feat/path-head
Browse files Browse the repository at this point in the history
feat: path head option
  • Loading branch information
specialblend authored Nov 22, 2021
2 parents bdf5246 + b4a1fd1 commit 68138f5
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 10 deletions.
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,61 @@ query GetAddresses2 {

[see example unit tests.](example/GetAddresses.example.test.ts)

#### using JSONPath on array fields

By default, mapql will return head (first element) of result from JSONPath query. This can be disabled with argument `head: false`, useful when expecting list of values. Default value is `head: true`.

example:

```javascript
const data = {
exampleObj: {
exampleStr: "hello world",
},
destinations: [
{
array_string: "foo",
},
{
array_string: "bar",
},
{
array_string: "baz",
},
],
}
```

```graphql
query PathHead {
exampleStr
exampleStrHead(head: true)
exampleStrNoHead(head: false)
destinationsHead(from: "destinations[*].array_string", head: true)
destinationsNoHead(from: "destinations[*].array_string", head: false)
destinations(from: "destinations[*].array_string")
}
```

```json
{
"destinations": "foo",
"destinationsHead": "foo",
"destinationsNoHead": [
"foo",
"bar",
"baz"
],
"exampleStr": "hello world",
"exampleStrHead": "hello world",
"exampleStrNoHead": [
"hello world"
]
}
```

[see example unit tests.](example/PathHead.example.test.ts)

### filtering fields

⭕ query:
Expand Down
43 changes: 43 additions & 0 deletions example/PathHead.example.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import gql from "graphql-tag";
import map from "../src";

test("PathHead", () => {
const data = {
exampleObj: {
exampleStr: "hello world",
},
destinations: [
{
array_string: "foo",
},
{
array_string: "bar",
},
{
array_string: "baz",
},
],
};
const query = gql`
query PathHead {
exampleStr(from: "exampleObj.exampleStr")
exampleStrHead(from: "exampleObj.exampleStr", head: true)
exampleStrNoHead(from: "exampleObj.exampleStr", head: false)
destinationsHead(from: "destinations[*].array_string", head: true)
destinationsNoHead(from: "destinations[*].array_string", head: false)
destinations(from: "destinations[*].array_string")
}
`;
const result = map(query, data);
expect(result).toEqual(
//
{
destinations: "foo",
destinationsHead: "foo",
destinationsNoHead: ["foo", "bar", "baz"],
exampleStr: "hello world",
exampleStrHead: "hello world",
exampleStrNoHead: ["hello world"],
}
);
});
1 change: 1 addition & 0 deletions src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type ExecSource = JsonRecord;
export interface ExecArgs {
from?: PathSelector;
filter?: Filter;
head?: boolean;
}

export type Exec = {
Expand Down
4 changes: 2 additions & 2 deletions src/exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ function execPath(ex: Exec) {
const {
fieldName,
root,
args: { from },
args: { from, head = true },
} = ex;
if (shouldExPath(ex)) {
const pathName = isset(from) ? from : fieldName;
return path(pathName, data, root);
return path(pathName, data, root, head);
}
return root;
};
Expand Down
22 changes: 14 additions & 8 deletions src/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,31 @@ import type {
} from "./contract";

import jp from "jsonpath";
import { isset } from "./util";

function jsonpath(selector: string, data: JsonParent): Maybe<JsonChild> {
const [child] = jp.query(data, selector);
if (isset(child)) {
return child;
function jsonpath(
selector: string,
data: JsonParent,
head = true
): Maybe<JsonChild> {
const result = jp.query(data, selector);
const [first] = result;
if (head) {
return first;
}
return result;
}

export function path(
selector: PathSelector,
source: JsonRecord,
parent: JsonParent = source
parent: JsonParent = source,
head = true
): Maybe<JsonChild> {
if (selector === "@") {
return jsonpath("$", parent);
}
if (selector[0] === "$") {
return jsonpath(selector, source);
return jsonpath(selector, source, head);
}
return jsonpath(selector, parent);
return jsonpath(selector, parent, head);
}

0 comments on commit 68138f5

Please sign in to comment.