Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added hoist field transform package + docs #2862

Merged
merged 10 commits into from
Mar 21, 2022
Merged
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
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