Skip to content

Commit

Permalink
feat: executor from graphql-js (#4778)
Browse files Browse the repository at this point in the history
* feat: executor from graphql-js

* Some cleanup

* Make it even more agnostic

* Do not fail fast

* Go

* No more jsutils

* Go

* More

* Revert "Go"

This reverts commit c6a6204.

* make it use tools more

* fix build

* remove fn in fork

* changeset

* bad rebase

* Drop v15

* Drop v14

* Use more from executor

* chore(dependencies): updated changesets for modified dependencies

* Go

* Yes

* chore(dependencies): updated changesets for modified dependencies

* Go

* Relax

* Go

* chore(dependencies): updated changesets for modified dependencies

Co-authored-by: Arda TANRIKULU <ardatanrikulu@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Oct 27, 2022
1 parent e60266b commit df5848b
Show file tree
Hide file tree
Showing 85 changed files with 8,602 additions and 251 deletions.
5 changes: 5 additions & 0 deletions .changeset/@graphql-tools_delegate-4778-dependencies.md
@@ -0,0 +1,5 @@
---
'@graphql-tools/delegate': patch
---
dependencies updates:
- Added dependency [`@graphql-tools/executor@0.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/executor/v/0.0.0) (to `dependencies`)
5 changes: 5 additions & 0 deletions .changeset/brown-glasses-rule.md
@@ -0,0 +1,5 @@
---
'@graphql-tools/utils': minor
---

add isIterableObject, isObjectLike, isPromise, promiseReduce, hasOwnProperty
5 changes: 5 additions & 0 deletions .changeset/gorgeous-pants-tickle.md
@@ -0,0 +1,5 @@
---
'@graphql-tools/utils': minor
---

add `Path` util from `graphql/jsutils`
5 changes: 5 additions & 0 deletions .changeset/little-scissors-breathe.md
@@ -0,0 +1,5 @@
---
'@graphql-tools/executor': patch
---

initial release
5 changes: 5 additions & 0 deletions .changeset/poor-taxis-look.md
@@ -0,0 +1,5 @@
---
'@graphql-tools/utils': patch
---

improve inpsect util
26 changes: 26 additions & 0 deletions .eslintrc.cjs
Expand Up @@ -32,6 +32,18 @@ module.exports = {
'@typescript-eslint/explicit-module-boundary-types': 'off',
'default-param-last': 'off',
'import/no-extraneous-dependencies': ['error', { devDependencies: ['**/*.test.ts', '**/*.spec.ts'] }],
'no-restricted-imports': [
'error',
{
paths: [
{
name: 'graphql',
importNames: ['ExecutionResult', 'ExecutionArgs', 'execute', 'subscribe'],
message: 'Please use `execute` and `subscribe` from `@graphql-tools/executro` instead.',
},
],
},
],
},
env: {
es6: true,
Expand Down Expand Up @@ -68,6 +80,20 @@ module.exports = {
eqeqeq: 'off',
},
},
{
files: ['packages/executor/**'],
env: {
jest: true,
},
rules: {
// TODO: Enable us incrementally
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-inferrable-types': 'off',
'prefer-rest-params': 'off',
'no-throw-literal': 'off',
'promise/param-names': 'off',
},
},
],
ignorePatterns: [
'dist',
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/benchmark.yml
Expand Up @@ -13,6 +13,7 @@ jobs:
name: Federation Benchmark with ${{matrix.products_size}} Products
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
products_size: [3, 10, 50, 100, 1000]
steps:
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/tests.yml
Expand Up @@ -34,9 +34,9 @@ jobs:
name: Type Check on GraphQL v${{matrix.graphql_version}}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
graphql_version:
- 14
- 15
- 16
- '17.0.0-alpha.1'
Expand Down Expand Up @@ -64,7 +64,6 @@ jobs:
os: [ubuntu-latest] # remove windows to speed up the tests
node-version: [14, 16, 18]
graphql_version:
- 14
- 15
- 16
- '17.0.0-alpha.1'
Expand Down
3 changes: 2 additions & 1 deletion packages/batch-delegate/tests/basic.example.test.ts
@@ -1,4 +1,5 @@
import { execute, OperationTypeNode, parse } from 'graphql';
import { execute } from '@graphql-tools/executor';
import { OperationTypeNode, parse } from 'graphql';

import { makeExecutableSchema } from '@graphql-tools/schema';
import { batchDelegateToSchema } from '@graphql-tools/batch-delegate';
Expand Down
3 changes: 2 additions & 1 deletion packages/batch-delegate/tests/withTransforms.test.ts
@@ -1,4 +1,5 @@
import { execute, GraphQLList, GraphQLObjectType, Kind, OperationTypeNode, parse } from 'graphql';
import { execute } from '@graphql-tools/executor';
import { GraphQLList, GraphQLObjectType, Kind, OperationTypeNode, parse } from 'graphql';

import { makeExecutableSchema } from '@graphql-tools/schema';
import { batchDelegateToSchema } from '@graphql-tools/batch-delegate';
Expand Down
6 changes: 3 additions & 3 deletions packages/batch-execute/src/splitResult.ts
@@ -1,8 +1,8 @@
// adapted from https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js

import { ExecutionResult, GraphQLError } from 'graphql';
import { GraphQLError } from 'graphql';

import { relocatedError } from '@graphql-tools/utils';
import { createGraphQLError, ExecutionResult, relocatedError } from '@graphql-tools/utils';

import { parseKey } from './prefix.js';

Expand Down Expand Up @@ -41,7 +41,7 @@ export function splitResult({ data, errors }: ExecutionResult, numResults: numbe
} else {
splitResults.forEach(result => {
const resultErrors = (result.errors = (result.errors || []) as GraphQLError[]);
resultErrors.push(new GraphQLError(error.message));
resultErrors.push(createGraphQLError(error.message));
});
}
}
Expand Down
17 changes: 11 additions & 6 deletions packages/batch-execute/tests/batchExecute.test.ts
@@ -1,7 +1,8 @@
import { graphql, parse, print, OperationDefinitionNode, ExecutionResult } from 'graphql';
import { parse, print, OperationDefinitionNode, validate } from 'graphql';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { createBatchingExecutor } from '@graphql-tools/batch-execute';
import { Executor } from '@graphql-tools/utils';
import { ExecutionResult, Executor } from '@graphql-tools/utils';
import { execute } from '@graphql-tools/executor';

describe('batch execution', () => {
let executorCalls = 0;
Expand Down Expand Up @@ -32,16 +33,20 @@ describe('batch execution', () => {
},
});

const exec = (({ document, variables }) => {
const exec: Executor = async ({ document, variables }) => {
executorCalls += 1;
executorDocument = print(document);
executorVariables = variables;
return graphql({
const errors = validate(schema, document);
if (errors.length > 0) {
return { errors };
}
return execute({
schema,
source: executorDocument,
document,
variableValues: executorVariables,
});
}) as Executor;
};

const batchExec = createBatchingExecutor(exec);

Expand Down
1 change: 1 addition & 0 deletions packages/delegate/package.json
Expand Up @@ -54,6 +54,7 @@
},
"dependencies": {
"@graphql-tools/batch-execute": "8.5.6",
"@graphql-tools/executor": "0.0.0",
"@graphql-tools/schema": "9.0.4",
"@graphql-tools/utils": "8.12.0",
"dataloader": "2.1.0",
Expand Down
6 changes: 2 additions & 4 deletions packages/delegate/src/delegateToSchema.ts
Expand Up @@ -5,9 +5,6 @@ import {
OperationTypeNode,
DocumentNode,
GraphQLOutputType,
ExecutionArgs,
subscribe,
execute,
} from 'graphql';

import { ValueOrPromise } from 'value-or-promise';
Expand Down Expand Up @@ -39,6 +36,7 @@ import { Subschema } from './Subschema.js';
import { createRequest, getDelegatingOperation } from './createRequest.js';
import { Transformer } from './Transformer.js';
import { applySchemaTransforms } from './applySchemaTransforms.js';
import { ExecutionArgs, execute, subscribe } from '@graphql-tools/executor';

export function delegateToSchema<
TContext extends Record<string, any> = Record<string, any>,
Expand Down Expand Up @@ -234,5 +232,5 @@ export const createDefaultExecutor = memoize1(function createDefaultExecutor(sch
return subscribe(executionArgs);
}
return execute(executionArgs);
} as Executor;
};
});
5 changes: 3 additions & 2 deletions packages/delegate/tests/createRequest.test.ts
@@ -1,8 +1,9 @@
import { graphql, Kind, GraphQLError, OperationTypeNode } from 'graphql';
import { graphql, Kind, OperationTypeNode } from 'graphql';

import { createRequest } from '../src/createRequest.js';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { delegateRequest } from '../src/delegateToSchema.js';
import { createGraphQLError } from '@graphql-tools/utils';

describe('bare requests', () => {
test('should work', async () => {
Expand Down Expand Up @@ -254,7 +255,7 @@ describe('bare requests', () => {
data: {
delegate: null,
},
errors: [new GraphQLError('test')],
errors: [createGraphQLError('test')],
});
});
});
6 changes: 3 additions & 3 deletions packages/delegate/tests/errors.test.ts
@@ -1,4 +1,4 @@
import { GraphQLError, GraphQLResolveInfo, locatedError, graphql, OperationTypeNode } from 'graphql';
import { GraphQLResolveInfo, locatedError, graphql, OperationTypeNode } from 'graphql';

import { makeExecutableSchema } from '@graphql-tools/schema';
import { createGraphQLError, ExecutionResult } from '@graphql-tools/utils';
Expand Down Expand Up @@ -40,7 +40,7 @@ describe('Errors', () => {

test('persists single error', () => {
const result = {
errors: [new GraphQLError('Test error')],
errors: [createGraphQLError('Test error')],
};
try {
checkResultAndHandleErrors(result, {
Expand Down Expand Up @@ -77,7 +77,7 @@ describe('Errors', () => {

test('combines errors and persists the original errors', () => {
const result = {
errors: [new GraphQLError('Error1'), new GraphQLError('Error2')],
errors: [createGraphQLError('Error1'), createGraphQLError('Error2')],
};
try {
checkResultAndHandleErrors(result, {
Expand Down
3 changes: 3 additions & 0 deletions packages/executor/README.md
@@ -0,0 +1,3 @@
## `@graphql-tools/executor`

Fork of GraphQL.js' execute function
73 changes: 73 additions & 0 deletions packages/executor/package.json
@@ -0,0 +1,73 @@
{
"name": "@graphql-tools/executor",
"version": "0.0.0",
"author": "Saihajpreet Singh <saihajpreet.singh@gmail.com>",
"license": "MIT",
"sideEffects": false,
"repository": {
"type": "git",
"url": "https://github.com/ardatan/graphql-tools.git",
"directory": "packages/executor"
},
"keywords": [
"gql",
"graphql",
"typescript"
],
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"exports": {
".": {
"require": {
"types": "./dist/typings/index.d.cts",
"default": "./dist/cjs/index.js"
},
"import": {
"types": "./dist/typings/index.d.ts",
"default": "./dist/esm/index.js"
},
"default": {
"types": "./dist/typings/index.d.ts",
"default": "./dist/esm/index.js"
}
},
"./*": {
"require": {
"types": "./dist/typings/*.d.cts",
"default": "./dist/cjs/*.js"
},
"import": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/esm/*.js"
},
"default": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/esm/*.js"
}
},
"./package.json": "./package.json"
},
"typings": "dist/typings/index.d.ts",
"typescript": {
"definition": "dist/typings/index.d.ts"
},
"dependencies": {
"@graphql-tools/utils": "8.12.0",
"@graphql-typed-document-node/core": "3.1.1"
},
"devDependencies": {
"graphql": "^16.6.0",
"typescript": "4.8.4"
},
"peerDependencies": {
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
},
"buildOptions": {
"input": "./src/index.ts"
},
"publishConfig": {
"directory": "dist",
"access": "public"
},
"type": "module"
}
63 changes: 63 additions & 0 deletions packages/executor/src/__testUtils__/expectJSON.ts
@@ -0,0 +1,63 @@
import { isObjectLike } from '@graphql-tools/utils';

/**
* Creates an object map with the same keys as `map` and values generated by
* running each value of `map` thru `fn`.
*/
function mapValue<T, V>(map: Record<string, T>, fn: (value: T, key: string) => V): Record<string, V> {
const result = Object.create(null);

for (const key of Object.keys(map)) {
result[key] = fn(map[key], key);
}
return result;
}

/**
* Deeply transforms an arbitrary value to a JSON-safe value by calling toJSON
* on any nested value which defines it.
*/
function toJSONDeep(value: unknown): unknown {
if (!isObjectLike(value)) {
return value;
}

// @ts-expect-error: toJSON is not defined on all objects
if (typeof value.toJSON === 'function') {
// @ts-expect-error: toJSON is not defined on all objects
return value.toJSON();
}

if (Array.isArray(value)) {
return value.map(toJSONDeep);
}

return mapValue(value, toJSONDeep);
}

export function expectJSON(actual: unknown) {
const actualJSON = toJSONDeep(actual);

return {
toDeepEqual(expected: unknown) {
const expectedJSON = toJSONDeep(expected);
expect(actualJSON).toMatchObject(expectedJSON as any);
},
toDeepNestedProperty(path: string, expected: unknown) {
const expectedJSON = toJSONDeep(expected);
expect(actualJSON).toHaveProperty(path, expectedJSON);
},
};
}

export function expectToThrowJSON(fn: () => unknown) {
function mapException(): unknown {
try {
return fn();
} catch (error) {
return error;
}
}

return expect(mapException());
}
3 changes: 3 additions & 0 deletions packages/executor/src/__testUtils__/resolveOnNextTick.ts
@@ -0,0 +1,3 @@
export function resolveOnNextTick(): Promise<void> {
return Promise.resolve(undefined);
}

0 comments on commit df5848b

Please sign in to comment.