Skip to content

Commit

Permalink
Added hoist field transform package + docs (#2862)
Browse files Browse the repository at this point in the history
* feat(transforms): added initial version of hoist-field transform

* chore: added changeset

* feat(hoist-field): refactor to enable bare implementation

* chore: cleanup

* chore: cleanup

* chore: cleanup

* chore: regen snapshots to match new format

* fix(hoist-field): use new import fn in unit test

* ..

* Use wrap mode by default

Co-authored-by: Arda TANRIKULU <[email protected]>
  • Loading branch information
ntziolis and ardatan authored Mar 21, 2022
1 parent 67fb117 commit b1a6df9
Show file tree
Hide file tree
Showing 9 changed files with 662 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .changeset/perfect-zebras-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@graphql-mesh/transform-hoist-field': minor
'@graphql-mesh/types': patch
'@graphql-mesh/website': patch
---

Added @graphql-mesh/transform-hoist-field package
37 changes: 37 additions & 0 deletions packages/transforms/hoist-field/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@graphql-mesh/transform-hoist-field",
"version": "0.0.0",
"sideEffects": false,
"main": "dist/index.js",
"module": "dist/index.mjs",
"typings": "dist/index.d.ts",
"typescript": {
"definition": "dist/index.d.ts"
},
"exports": {
".": {
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./*": {
"require": "./dist/*.js",
"import": "./dist/*.mjs"
}
},
"license": "MIT",
"peerDependencies": {
"graphql": "*"
},
"dependencies": {
"@graphql-mesh/types": "0.68.1",
"@graphql-mesh/utils": "0.31.0",
"@graphql-tools/delegate": "8.5.4",
"@graphql-tools/wrap": "8.4.6",
"@graphql-tools/utils": "8.6.3",
"@graphql-mesh/cache-inmemory-lru": "0.6.3"
},
"publishConfig": {
"access": "public",
"directory": "dist"
}
}
83 changes: 83 additions & 0 deletions packages/transforms/hoist-field/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { MeshTransform, MeshTransformOptions, YamlConfig } from '@graphql-mesh/types';
import { applyRequestTransforms, applyResultTransforms, applySchemaTransforms } from '@graphql-mesh/utils';
import { DelegationContext, SubschemaConfig, Transform } from '@graphql-tools/delegate';
import { ExecutionRequest, ExecutionResult } from '@graphql-tools/utils';
import { HoistField } from '@graphql-tools/wrap';
import { GraphQLSchema } from 'graphql';

type HoistFieldCtorPathConfigItem = ConstructorParameters<typeof HoistField>[1][0];
type HoistFieldTransformFieldPathConfig = YamlConfig.HoistFieldTransformConfig['pathConfig'][0];

export default class MeshHoistField implements MeshTransform {
noWrap = false;
private transforms: Transform[];

constructor({ config }: MeshTransformOptions<YamlConfig.HoistFieldTransformConfig[]>) {
this.transforms = config.map(({ typeName, pathConfig, newFieldName, alias, filterArgsInPath = false }) => {
const processedPathConfig = pathConfig.map(config => this.getPathConfigItem(config, filterArgsInPath));
return new HoistField(typeName, processedPathConfig, newFieldName, alias);
});
}

private getPathConfigItem(
pathConfigItemFromConfig: HoistFieldTransformFieldPathConfig,
filterArgsInPath: boolean
): HoistFieldCtorPathConfigItem {
if (typeof pathConfigItemFromConfig === 'string') {
const pathConfigItem: HoistFieldCtorPathConfigItem = {
fieldName: pathConfigItemFromConfig,
argFilter: () => filterArgsValue(filterArgsInPath),
};

return pathConfigItem;
}

if (!pathConfigItemFromConfig.fieldName) {
throw new Error(`Field name is required in pathConfig item`);
}

if (!pathConfigItemFromConfig.filterArgs) {
throw new Error(`FilterArgs is required in pathConfig item`);
}

const filterArgsDict = (pathConfigItemFromConfig.filterArgs || []).reduce((prev, argName) => {
prev[argName] = true;
return prev;
}, {});

const pathConfigItem: HoistFieldCtorPathConfigItem = {
fieldName: pathConfigItemFromConfig.fieldName,
argFilter: arg => {
return filterArgsValue(filterArgsDict[arg.name]);
},
};

return pathConfigItem;
}

transformSchema(
originalWrappingSchema: GraphQLSchema,
subschemaConfig: SubschemaConfig,
transformedSchema?: GraphQLSchema
) {
return applySchemaTransforms(originalWrappingSchema, subschemaConfig, transformedSchema, this.transforms);
}

transformRequest(
originalRequest: ExecutionRequest,
delegationContext: DelegationContext,
transformationContext: Record<string, any>
) {
return applyRequestTransforms(originalRequest, delegationContext, transformationContext, this.transforms);
}

transformResult(originalResult: ExecutionResult, delegationContext: DelegationContext, transformationContext: any) {
return applyResultTransforms(originalResult, delegationContext, transformationContext, this.transforms);
}
}

// The argFilters in HoistField seem to work more like argIncludes, hence the value needs to be negated
// https://github.com/ardatan/graphql-tools/blob/af266974bf02967e0675187e9bea0391fd7fe0cf/packages/wrap/src/transforms/HoistField.ts#L44
function filterArgsValue(filter: boolean) {
return !filter;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`hoist should hoist field and filter args with global flag 1`] = `
"type Query {
users: [User!]!
}
type UserSearchResult {
page: Int!
}
type User {
id: ID!
name: String!
}"
`;

exports[`hoist should hoist field and filter individual args via pathConfig 1`] = `
"type Query {
users(page: Int): [User!]!
}
type UserSearchResult {
page: Int!
}
type User {
id: ID!
name: String!
}"
`;

exports[`hoist should hoist field and filter individual args via pathConfig independent of global flag 1`] = `
"type Query {
users(page: Int): [User!]!
}
type UserSearchResult {
page: Int!
}
type User {
id: ID!
name: String!
}"
`;

exports[`hoist should hoist field with mixed pathConfig array 1`] = `
"type Query {
users(limit: Int!, page: Int): [User!]!
}
type UserSearchResult {
page: Int!
}
type User {
id: ID!
name: String!
}"
`;

exports[`hoist should hoist field with string pathConfig array 1`] = `
"type Query {
users(limit: Int!, page: Int): [User!]!
}
type UserSearchResult {
page: Int!
}
type User {
id: ID!
name: String!
}"
`;
Loading

1 comment on commit b1a6df9

@vercel
Copy link

@vercel vercel bot commented on b1a6df9 Mar 21, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.