Skip to content

Commit

Permalink
feat(rewriter): expose parent object and element path to rewriter (#20)
Browse files Browse the repository at this point in the history
* feat(rewriter): expose parent object and element path to rewriter

This changes the implementation of `rewriteResultsAtPath` so that now the parent and path of the element is exposed to `Rewriter`.`rewriteResponse` instead of the element itself. This should support implement field name response rewrites.

BREAKING CHANGE: This changes the definition of `Rewriter`.`rewriteResponse`. The `path` references the location of the element while the `response` points to the parent of the element. Combining these will result in the original behavior.

* refactor: rename property to fix shallowing

* refactor: rename variable for clarity
  • Loading branch information
gregbty authored Sep 8, 2020
1 parent 42c05c8 commit 62e8211
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 40 deletions.
4 changes: 2 additions & 2 deletions src/RewriteHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ export default class RewriteHandler {
let rewrittenResponse = response;
this.matches.reverse().forEach(({ rewriter, paths }) => {
paths.forEach(path => {
rewrittenResponse = rewriteResultsAtPath(rewrittenResponse, path, responseAtPath =>
rewriter.rewriteResponse(responseAtPath)
rewrittenResponse = rewriteResultsAtPath(rewrittenResponse, path, (parentResponse, key) =>
rewriter.rewriteResponse(parentResponse, key)
);
});
});
Expand Down
32 changes: 23 additions & 9 deletions src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,24 +261,38 @@ interface ResultObj {
export const rewriteResultsAtPath = (
results: ResultObj,
path: ReadonlyArray<string>,
callback: (resultsAtPath: any) => any
callback: (parentResult: any, key: string | number) => any
): ResultObj => {
if (path.length === 0) return callback(results);
if (path.length === 0) return results;

const curPathElm = path[0];
const remainingPath = path.slice(1);
const newResults = { ...results };
const curResults = results[curPathElm];

if (path.length === 1) {
if (Array.isArray(curResults)) {
newResults[curPathElm] = curResults.map((_, index) => {
const newValue = callback(curResults, index);
return newValue;
});
} else {
newResults[curPathElm] = callback(results, curPathElm);
}

return newResults;
}

const remainingPath = path.slice(1);
// if the path stops here, just return results without any rewriting
if (curResults === undefined || curResults === null) return results;

if (Array.isArray(curResults)) {
newResults[curPathElm] = curResults.reduce((acc, resultElm) => {
const elmResults = rewriteResultsAtPath(resultElm, remainingPath, callback);
return acc.concat(elmResults);
}, []);
return newResults;
newResults[curPathElm] = curResults.map(result =>
rewriteResultsAtPath(result, remainingPath, callback)
);
} else {
newResults[curPathElm] = rewriteResultsAtPath(curResults, remainingPath, callback);
}

newResults[curPathElm] = rewriteResultsAtPath(curResults, remainingPath, callback);
return newResults;
};
15 changes: 10 additions & 5 deletions src/rewriters/NestFieldOutputsRewriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,21 @@ class NestFieldOutputsRewriter extends Rewriter {
} as NodeAndVarDefs;
}

public rewriteResponse(response: any) {
if (typeof response === 'object') {
public rewriteResponse(response: any, key: string | number) {
const pathResponse = super.rewriteResponse(response, key);

if (typeof pathResponse === 'object') {
// undo the nesting in the response so it matches the original query
if (response[this.newOutputName] && typeof response[this.newOutputName] === 'object') {
const rewrittenResponse = { ...response, ...response[this.newOutputName] };
if (
pathResponse[this.newOutputName] &&
typeof pathResponse[this.newOutputName] === 'object'
) {
const rewrittenResponse = { ...pathResponse, ...pathResponse[this.newOutputName] };
delete rewrittenResponse[this.newOutputName];
return rewrittenResponse;
}
}
return response;
return pathResponse;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/rewriters/Rewriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ abstract class Rewriter {
return variables;
}

public rewriteResponse(response: any): any {
return response;
public rewriteResponse(response: any, key: string | number): any {
return response[key];
}
}

Expand Down
9 changes: 6 additions & 3 deletions src/rewriters/ScalarFieldToObjectFieldRewriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ class ScalarFieldToObjectFieldRewriter extends Rewriter {
} as NodeAndVarDefs;
}

public rewriteResponse(response: any) {
public rewriteResponse(response: any, key: string | number) {
const pathResponse = super.rewriteResponse(response, key);

if (typeof response === 'object') {
// undo the nesting in the response so it matches the original query
return response[this.objectFieldName];
return pathResponse[this.objectFieldName];
}
return response;

return pathResponse;
}
}

Expand Down
41 changes: 22 additions & 19 deletions test/ast.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ describe('ast utils', () => {
moreThings: [{ type: 'dog' }, { type: 'cat' }, { type: 'lion' }]
}
};
expect(rewriteResultsAtPath(obj, ['thing1', 'moreThings', 'type'], elm => elm + '!')).toEqual(
{
thing1: {
moreThings: [{ type: 'dog!' }, { type: 'cat!' }, { type: 'lion!' }]
}
expect(
rewriteResultsAtPath(obj, ['thing1', 'moreThings', 'type'], (elm, path) => elm[path] + '!')
).toEqual({
thing1: {
moreThings: [{ type: 'dog!' }, { type: 'cat!' }, { type: 'lion!' }]
}
);
});
});

it("doesn't include null or undefined results", () => {
Expand All @@ -49,20 +49,23 @@ describe('ast utils', () => {
}
]
};
expect(rewriteResultsAtPath(obj, ['things', 'moreThings', 'type'], elm => elm + '!')).toEqual(
{
things: [
{
moreThings: [{ type: 'dog!' }, { type: 'cat!' }]
},
{
moreThings: [{ type: 'bear!' }, { type: 'cat!' }]
}
]
}
);
expect(
rewriteResultsAtPath(obj, ['things', 'moreThings'], elm => ({ ...elm, meh: '7' }))
rewriteResultsAtPath(obj, ['things', 'moreThings', 'type'], (elm, path) => elm[path] + '!')
).toEqual({
things: [
{
moreThings: [{ type: 'dog!' }, { type: 'cat!' }]
},
{
moreThings: [{ type: 'bear!' }, { type: 'cat!' }]
}
]
});
expect(
rewriteResultsAtPath(obj, ['things', 'moreThings'], (elm, path) => ({
...elm[path],
meh: '7'
}))
).toEqual({
things: [
{
Expand Down

0 comments on commit 62e8211

Please sign in to comment.