├── .circleci └── config.yml ├── .commitlintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── Bug_report.yml │ ├── Feature_request.yml │ ├── Regression.yml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md └── lock.yml ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── .npmignore ├── .prettierignore ├── .prettierrc ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── eslint.config.mjs ├── lerna.json ├── package.json ├── packages ├── apollo │ ├── LICENSE │ ├── README.md │ ├── lib │ │ ├── constants │ │ │ ├── apollo.constants.ts │ │ │ └── index.ts │ │ ├── decorators │ │ │ ├── index.ts │ │ │ └── plugin.decorator.ts │ │ ├── drivers │ │ │ ├── apollo-base.driver.ts │ │ │ ├── apollo-federation.driver.ts │ │ │ ├── apollo-gateway.driver.ts │ │ │ ├── apollo.driver.ts │ │ │ └── index.ts │ │ ├── errors │ │ │ ├── authentication.error.ts │ │ │ ├── forbidden.error.ts │ │ │ ├── index.ts │ │ │ ├── user-input.error.ts │ │ │ └── validation.error.ts │ │ ├── graphiql │ │ │ ├── graphiql-html.factory.ts │ │ │ ├── graphiql-playground.plugin.ts │ │ │ └── interfaces │ │ │ │ └── graphiql-options.interface.ts │ │ ├── index.ts │ │ ├── interfaces │ │ │ ├── apollo-driver-config.interface.ts │ │ │ ├── apollo-federation-driver-config.interface.ts │ │ │ ├── apollo-gateway-driver-config.interface.ts │ │ │ └── index.ts │ │ ├── services │ │ │ ├── index.ts │ │ │ └── plugins-explorer.service.ts │ │ └── utils │ │ │ ├── async-iterator.util.ts │ │ │ ├── get-apollo-server.ts │ │ │ └── index.ts │ ├── package.json │ ├── tests │ │ ├── code-first-duplicate-resolvers │ │ │ ├── app.module.ts │ │ │ ├── module-a │ │ │ │ ├── module-a.module.ts │ │ │ │ └── user.resolver.ts │ │ │ ├── module-b │ │ │ │ ├── module-b.module.ts │ │ │ │ └── user.resolver.ts │ │ │ └── query.resolver.ts │ │ ├── code-first-federation │ │ │ ├── app.module.ts │ │ │ ├── caching.module.ts │ │ │ ├── human │ │ │ │ ├── character.entity.ts │ │ │ │ ├── human.entity.ts │ │ │ │ ├── human.module.ts │ │ │ │ └── human.resolver.ts │ │ │ ├── main.ts │ │ │ ├── post │ │ │ │ ├── post.entity.ts │ │ │ │ ├── post.module.ts │ │ │ │ ├── post.resolver.ts │ │ │ │ └── post.service.ts │ │ │ ├── recipe │ │ │ │ ├── irecipe.resolver.ts │ │ │ │ ├── recipe.module.ts │ │ │ │ └── recipe.ts │ │ │ ├── unions │ │ │ │ └── search-result.union.ts │ │ │ └── user │ │ │ │ ├── user.entity.ts │ │ │ │ ├── user.module.ts │ │ │ │ └── user.resolver.ts │ │ ├── code-first │ │ │ ├── app.module.ts │ │ │ ├── cats │ │ │ │ ├── cats.module.ts │ │ │ │ └── cats.resolver.ts │ │ │ ├── common │ │ │ │ ├── filters │ │ │ │ │ └── unauthorized.filter.ts │ │ │ │ ├── guards │ │ │ │ │ └── auth.guard.ts │ │ │ │ └── scalars │ │ │ │ │ └── date.scalar.ts │ │ │ ├── directions │ │ │ │ ├── directions.module.ts │ │ │ │ └── directions.resolver.ts │ │ │ ├── enums │ │ │ │ ├── direction.enum.ts │ │ │ │ └── sample-orphaned.enum.ts │ │ │ ├── main.ts │ │ │ ├── other │ │ │ │ ├── abstract.resolver.ts │ │ │ │ ├── sample-orphaned.type.ts │ │ │ │ └── sample-scalar.ts │ │ │ └── recipes │ │ │ │ ├── dto │ │ │ │ ├── filter-recipes-count.args.ts │ │ │ │ ├── new-recipe.input.ts │ │ │ │ └── recipes.args.ts │ │ │ │ ├── ingredients.resolver.ts │ │ │ │ ├── irecipes.resolver.ts │ │ │ │ ├── models │ │ │ │ ├── category.ts │ │ │ │ ├── ingredient.ts │ │ │ │ └── recipe.ts │ │ │ │ ├── recipes.module.ts │ │ │ │ ├── recipes.resolver.ts │ │ │ │ ├── recipes.service.ts │ │ │ │ └── unions │ │ │ │ └── search-result.union.ts │ │ ├── duplicate-resolvers │ │ │ ├── app.module.ts │ │ │ ├── duplicate-resolver.graphql │ │ │ ├── module-a │ │ │ │ ├── module-a.module.ts │ │ │ │ └── user.resolver.ts │ │ │ └── module-b │ │ │ │ ├── module-b.module.ts │ │ │ │ └── user.resolver.ts │ │ ├── e2e │ │ │ ├── __snapshots__ │ │ │ │ ├── code-first-federation.spec.ts.snap │ │ │ │ └── serialized-graph.spec.ts.snap │ │ │ ├── code-first-federation-caching.spec.ts │ │ │ ├── code-first-federation.spec.ts │ │ │ ├── code-first-inheritance.spec.ts │ │ │ ├── code-first-schema.spec.ts │ │ │ ├── code-first.spec.ts │ │ │ ├── custom-context.spec.ts │ │ │ ├── duplicate-resolvers.spec.ts │ │ │ ├── generated-definitions.spec.ts │ │ │ ├── global-prefix-fastify.spec.ts │ │ │ ├── global-prefix.spec.ts │ │ │ ├── graphiql-playground.spec.ts │ │ │ ├── graphql-async-class.spec.ts │ │ │ ├── graphql-async-existing.spec.ts │ │ │ ├── graphql-async.spec.ts │ │ │ ├── graphql-fastify.spec.ts │ │ │ ├── graphql-federation-async-class.spec.ts │ │ │ ├── graphql-federation-async-existing.spec.ts │ │ │ ├── graphql-federation-async.spec.ts │ │ │ ├── graphql-federation-fastify.spec.ts │ │ │ ├── graphql-federation-schema-host.spec.ts │ │ │ ├── graphql-federation.spec.ts │ │ │ ├── graphql-gateway-async-class.spec.ts │ │ │ ├── graphql-gateway-async-existing.spec.ts │ │ │ ├── graphql-gateway-async.spec.ts │ │ │ ├── graphql-gateway-fastify.spec.ts │ │ │ ├── graphql-gateway.spec.ts │ │ │ ├── graphql-request-scoped.spec.ts │ │ │ ├── graphql-sort-auto-schema.spec.ts │ │ │ ├── graphql-sort-schema.spec.ts │ │ │ ├── graphql-transform-auto-schema-file.spec.ts │ │ │ ├── graphql.spec.ts │ │ │ ├── guards-filters.spec.ts │ │ │ ├── pipes.spec.ts │ │ │ ├── request-scoped.spec.ts │ │ │ ├── resolver-registration-methods.spec.ts │ │ │ └── serialized-graph.spec.ts │ │ ├── generated-definitions │ │ │ ├── array-property.fixture.ts │ │ │ ├── array-property.graphql │ │ │ ├── custom-header.fixture.ts │ │ │ ├── custom-header.graphql │ │ │ ├── custom-scalar-default-type.fixture.ts │ │ │ ├── custom-scalar-type-mapping.fixture.ts │ │ │ ├── custom-scalar-type-mapping.graphql │ │ │ ├── custom-scalar.fixture.ts │ │ │ ├── custom-scalar.graphql │ │ │ ├── enum-as-type.fixture.ts │ │ │ ├── enum-as-type.graphql │ │ │ ├── enum.fixture.ts │ │ │ ├── enum.graphql │ │ │ ├── federation-partial-query.fixture.ts │ │ │ ├── federation-partial-query.graphql │ │ │ ├── federation-typedef.fixture.ts │ │ │ ├── federation-typedef.graphql │ │ │ ├── federation.fixture.ts │ │ │ ├── federation.graphql │ │ │ ├── interface-property.fixture.ts │ │ │ ├── interface-property.graphql │ │ │ ├── mutation.fixture.ts │ │ │ ├── mutation.graphql │ │ │ ├── query-skip-args.fixture.ts │ │ │ ├── query.fixture.ts │ │ │ ├── query.graphql │ │ │ ├── simple-type.fixture.ts │ │ │ ├── simple-type.graphql │ │ │ ├── typename.fixture.ts │ │ │ └── typename.graphql │ │ ├── graphql-federation │ │ │ ├── gateway │ │ │ │ ├── config │ │ │ │ │ ├── config.module.ts │ │ │ │ │ └── config.service.ts │ │ │ │ ├── gateway-async-class.module.ts │ │ │ │ ├── gateway-async-existing.module.ts │ │ │ │ ├── gateway-async.module.ts │ │ │ │ ├── gateway.module.ts │ │ │ │ └── supergraph-sdl.ts │ │ │ ├── posts-service │ │ │ │ ├── federation-posts.module.ts │ │ │ │ └── posts │ │ │ │ │ ├── date.scalar.ts │ │ │ │ │ ├── post-type.enum.ts │ │ │ │ │ ├── posts.interfaces.ts │ │ │ │ │ ├── posts.module.ts │ │ │ │ │ ├── posts.resolvers.ts │ │ │ │ │ ├── posts.service.ts │ │ │ │ │ ├── posts.types.graphql │ │ │ │ │ ├── upper.directive.ts │ │ │ │ │ └── users.resolvers.ts │ │ │ └── users-service │ │ │ │ ├── config │ │ │ │ ├── config.module.ts │ │ │ │ └── config.service.ts │ │ │ │ ├── federation-users.async-class.module.ts │ │ │ │ ├── federation-users.async-existing.module.ts │ │ │ │ ├── federation-users.async.module.ts │ │ │ │ ├── federation-users.module.ts │ │ │ │ └── users │ │ │ │ ├── users.interfaces.ts │ │ │ │ ├── users.module.ts │ │ │ │ ├── users.resolvers.ts │ │ │ │ ├── users.service.ts │ │ │ │ └── users.types.graphql │ │ ├── graphql │ │ │ ├── app.module.ts │ │ │ ├── async-options-class.module.ts │ │ │ ├── async-options-existing.module.ts │ │ │ ├── async-options.module.ts │ │ │ ├── cats │ │ │ │ ├── cats-request-scoped.service.ts │ │ │ │ ├── cats.guard.ts │ │ │ │ ├── cats.module.ts │ │ │ │ ├── cats.resolvers.ts │ │ │ │ ├── cats.service.ts │ │ │ │ ├── cats.types.graphql │ │ │ │ └── interfaces │ │ │ │ │ └── cat.interface.ts │ │ │ ├── common │ │ │ │ └── scalars │ │ │ │ │ └── date.scalar.ts │ │ │ ├── config.module.ts │ │ │ ├── config.service.ts │ │ │ ├── custom-context │ │ │ │ ├── custom-context.module.ts │ │ │ │ └── custom-context.resolver.ts │ │ │ ├── global-prefix-async-options-class.module.ts │ │ │ ├── global-prefix-async-options.module.ts │ │ │ ├── global-prefix.module.ts │ │ │ ├── graphiql-playground.module.ts │ │ │ ├── hello │ │ │ │ ├── cats.types.graphql │ │ │ │ ├── dto │ │ │ │ │ └── test.dto.ts │ │ │ │ ├── guards │ │ │ │ │ └── request-scoped.guard.ts │ │ │ │ ├── hello.module.ts │ │ │ │ ├── hello.resolver.ts │ │ │ │ ├── hello.service.ts │ │ │ │ ├── interceptors │ │ │ │ │ └── logging.interceptor.ts │ │ │ │ └── users │ │ │ │ │ ├── user-by-id.pipe.ts │ │ │ │ │ └── users.service.ts │ │ │ ├── main.ts │ │ │ ├── sort-auto-schema.module.ts │ │ │ ├── sort-schema.module.ts │ │ │ └── transform-auto-schema-file.module.ts │ │ ├── jest-e2e.ts │ │ ├── subscriptions │ │ │ ├── app │ │ │ │ ├── app.module.ts │ │ │ │ ├── auth.guard.ts │ │ │ │ ├── notification.module.ts │ │ │ │ ├── notification.resolver.ts │ │ │ │ └── notification.ts │ │ │ ├── async-iterator.spec.ts │ │ │ ├── compat.spec.ts │ │ │ ├── graphql-ws.spec.ts │ │ │ ├── subscription-transport-ws.spec.ts │ │ │ └── utils │ │ │ │ ├── graphql-ws.link.ts │ │ │ │ └── malformed-token.exception.ts │ │ └── utils │ │ │ ├── assertion-utils.ts │ │ │ ├── introspection-schema.utils.ts │ │ │ ├── printed-schema-with-cache-control.snapshot.ts │ │ │ └── printed-schema.snapshot.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── graphql │ ├── LICENSE │ ├── README.md │ ├── lib │ │ ├── decorators │ │ │ ├── args-type.decorator.ts │ │ │ ├── args.decorator.ts │ │ │ ├── context.decorator.ts │ │ │ ├── directive.decorator.ts │ │ │ ├── extensions.decorator.ts │ │ │ ├── field.decorator.ts │ │ │ ├── hide-field.decorator.ts │ │ │ ├── index.ts │ │ │ ├── info.decorator.ts │ │ │ ├── input-type.decorator.ts │ │ │ ├── interface-type.decorator.ts │ │ │ ├── mutation.decorator.ts │ │ │ ├── object-type.decorator.ts │ │ │ ├── param.utils.ts │ │ │ ├── parent.decorator.ts │ │ │ ├── query.decorator.ts │ │ │ ├── resolve-field.decorator.ts │ │ │ ├── resolve-property.decorator.ts │ │ │ ├── resolve-reference.decorator.ts │ │ │ ├── resolver.decorator.ts │ │ │ ├── resolvers.utils.ts │ │ │ ├── root.decorator.ts │ │ │ ├── scalar.decorator.ts │ │ │ └── subscription.decorator.ts │ │ ├── drivers │ │ │ ├── abstract-graphql.driver.ts │ │ │ └── index.ts │ │ ├── enums │ │ │ ├── class-type.enum.ts │ │ │ ├── gql-paramtype.enum.ts │ │ │ └── resolver.enum.ts │ │ ├── extra │ │ │ └── graphql-model-shim.ts │ │ ├── factories │ │ │ └── params.factory.ts │ │ ├── federation │ │ │ ├── graphql-federation-definitions.factory.ts │ │ │ ├── graphql-federation.factory.ts │ │ │ ├── index.ts │ │ │ ├── type-defs-decorator.factory.ts │ │ │ └── type-defs-federation2.decorator.ts │ │ ├── graphql-ast.explorer.ts │ │ ├── graphql-definitions.factory.ts │ │ ├── graphql-schema.builder.ts │ │ ├── graphql-schema.host.ts │ │ ├── graphql-types.loader.ts │ │ ├── graphql.constants.ts │ │ ├── graphql.factory.ts │ │ ├── graphql.module.ts │ │ ├── index.ts │ │ ├── interfaces │ │ │ ├── base-type-options.interface.ts │ │ │ ├── build-federated-schema-options.interface.ts │ │ │ ├── build-schema-options.interface.ts │ │ │ ├── class-decorator-factory.interface.ts │ │ │ ├── complexity.interface.ts │ │ │ ├── custom-scalar.interface.ts │ │ │ ├── field-middleware.interface.ts │ │ │ ├── gql-entrypoint-metadata.interface.ts │ │ │ ├── gql-exception-filter.interface.ts │ │ │ ├── gql-module-options.interface.ts │ │ │ ├── graphql-driver.interface.ts │ │ │ ├── graphql-exception.interface.ts │ │ │ ├── index.ts │ │ │ ├── resolve-type-fn.interface.ts │ │ │ ├── resolver-metadata.interface.ts │ │ │ ├── return-type-func.interface.ts │ │ │ ├── schema-file-config.interface.ts │ │ │ └── type-options.interface.ts │ │ ├── plugin │ │ │ ├── compiler-plugin.ts │ │ │ ├── index.ts │ │ │ ├── merge-options.ts │ │ │ ├── metadata-loader.ts │ │ │ ├── plugin-constants.ts │ │ │ ├── plugin-debug-logger.ts │ │ │ ├── utils │ │ │ │ ├── ast-utils.ts │ │ │ │ ├── is-filename-matched.util.ts │ │ │ │ ├── plugin-utils.ts │ │ │ │ └── type-reference-to-identifier.util.ts │ │ │ └── visitors │ │ │ │ ├── model-class.visitor.ts │ │ │ │ └── readonly.visitor.ts │ │ ├── scalars │ │ │ ├── index.ts │ │ │ ├── iso-date.scalar.ts │ │ │ └── timestamp.scalar.ts │ │ ├── schema-builder │ │ │ ├── collections │ │ │ │ ├── array-with-global-cache.collection.ts │ │ │ │ ├── field-directive.collection.ts │ │ │ │ ├── index.ts │ │ │ │ ├── metada-collection-model.interface.ts │ │ │ │ ├── metadata-by-name.collection.ts │ │ │ │ ├── metadata-by-target.collection.ts │ │ │ │ ├── metadata-list-by-name.collection.ts │ │ │ │ └── target-metadata.collection.ts │ │ │ ├── errors │ │ │ │ ├── cannot-determine-arg-type.error.ts │ │ │ │ ├── cannot-determine-host-type.error.ts │ │ │ │ ├── cannot-determine-input-type.error.ts │ │ │ │ ├── cannot-determine-output-type.error.ts │ │ │ │ ├── default-nullable-conflict.error.ts │ │ │ │ ├── default-values-conflict.error.ts │ │ │ │ ├── directive-parsing.error.ts │ │ │ │ ├── invalid-nullable-option.error.ts │ │ │ │ ├── multiple-fields-with-same-name.error.ts │ │ │ │ ├── return-type-cannot-be-resolved.error.ts │ │ │ │ ├── schema-generation.error.ts │ │ │ │ ├── unable-to-find-fields.error.ts │ │ │ │ ├── undefined-resolver-type.error.ts │ │ │ │ ├── undefined-return-type.error.ts │ │ │ │ └── undefined-type.error.ts │ │ │ ├── factories │ │ │ │ ├── args.factory.ts │ │ │ │ ├── ast-definition-node.factory.ts │ │ │ │ ├── enum-definition.factory.ts │ │ │ │ ├── factories.ts │ │ │ │ ├── input-type-definition.factory.ts │ │ │ │ ├── input-type.factory.ts │ │ │ │ ├── interface-definition.factory.ts │ │ │ │ ├── mutation-type.factory.ts │ │ │ │ ├── object-type-definition.factory.ts │ │ │ │ ├── orphaned-types.factory.ts │ │ │ │ ├── output-type.factory.ts │ │ │ │ ├── query-type.factory.ts │ │ │ │ ├── resolve-type.factory.ts │ │ │ │ ├── root-type.factory.ts │ │ │ │ ├── subscription-type.factory.ts │ │ │ │ └── union-definition.factory.ts │ │ │ ├── graphql-schema.factory.ts │ │ │ ├── helpers │ │ │ │ ├── file-system.helper.ts │ │ │ │ └── get-default-value.helper.ts │ │ │ ├── index.ts │ │ │ ├── metadata │ │ │ │ ├── class.metadata.ts │ │ │ │ ├── directive.metadata.ts │ │ │ │ ├── enum.metadata.ts │ │ │ │ ├── extensions.metadata.ts │ │ │ │ ├── index.ts │ │ │ │ ├── interface.metadata.ts │ │ │ │ ├── object-type.metadata.ts │ │ │ │ ├── param.metadata.ts │ │ │ │ ├── property.metadata.ts │ │ │ │ ├── resolver.metadata.ts │ │ │ │ └── union.metadata.ts │ │ │ ├── schema-builder.module.ts │ │ │ ├── services │ │ │ │ ├── orphaned-reference.registry.ts │ │ │ │ ├── type-fields.accessor.ts │ │ │ │ └── type-mapper.service.ts │ │ │ ├── storages │ │ │ │ ├── index.ts │ │ │ │ ├── lazy-metadata.storage.ts │ │ │ │ ├── type-definitions.storage.ts │ │ │ │ └── type-metadata.storage.ts │ │ │ ├── type-definitions.generator.ts │ │ │ └── utils │ │ │ │ ├── get-fields-and-decorator.util.ts │ │ │ │ ├── get-interfaces-array.util.ts │ │ │ │ ├── is-target-equal-util.ts │ │ │ │ └── is-throwing.util.ts │ │ ├── services │ │ │ ├── base-explorer.service.ts │ │ │ ├── gql-arguments-host.ts │ │ │ ├── gql-execution-context.ts │ │ │ ├── gql-subscription.service.ts │ │ │ ├── index.ts │ │ │ ├── resolvers-explorer.service.ts │ │ │ └── scalars-explorer.service.ts │ │ ├── tokens.ts │ │ ├── type-factories │ │ │ ├── create-union-type.factory.ts │ │ │ ├── index.ts │ │ │ └── register-enum-type.factory.ts │ │ ├── type-helpers │ │ │ ├── field-type.helper.ts │ │ │ ├── index.ts │ │ │ ├── intersection-type.helper.ts │ │ │ ├── omit-type.helper.ts │ │ │ ├── partial-type.helper.ts │ │ │ ├── pick-type.helper.ts │ │ │ └── type-helpers.utils.ts │ │ └── utils │ │ │ ├── add-class-type-metadata.util.ts │ │ │ ├── auto-schema-file.util.ts │ │ │ ├── decorate-field-resolver.util.ts │ │ │ ├── extend.util.ts │ │ │ ├── extract-metadata.util.ts │ │ │ ├── generate-token.util.ts │ │ │ ├── get-number-of-arguments.util.ts │ │ │ ├── index.ts │ │ │ ├── is-pipe.util.ts │ │ │ ├── normalize-resolver-args.ts │ │ │ ├── normalize-route-path.util.ts │ │ │ ├── reflection.utilts.ts │ │ │ ├── remove-temp.util.ts │ │ │ ├── scalar-types.utils.ts │ │ │ ├── stringify-without-quotes.util.ts │ │ │ └── transform-schema.util.ts │ ├── package.json │ ├── plugin.js │ ├── tests │ │ ├── graphql-ast.explorer.spec.ts │ │ ├── graphql.factory.spec.ts │ │ ├── jest-e2e.json │ │ ├── plugin │ │ │ ├── cases │ │ │ │ ├── .gitignore │ │ │ │ ├── es5-eager-imports │ │ │ │ │ ├── author.model.ts │ │ │ │ │ ├── expected │ │ │ │ │ │ ├── author.model.js │ │ │ │ │ │ └── post.model.js │ │ │ │ │ └── post.model.ts │ │ │ │ └── tsconfig.json │ │ │ ├── decorators │ │ │ │ └── field.decorator.spec.ts │ │ │ ├── fixtures │ │ │ │ ├── create-cat-alt.dto.ts │ │ │ │ ├── create-cat.dto.ts │ │ │ │ ├── deprecation.dto.ts │ │ │ │ ├── es5-class.dto.ts │ │ │ │ ├── nullable.dto.ts │ │ │ │ ├── project │ │ │ │ │ ├── app.module.ts │ │ │ │ │ ├── common │ │ │ │ │ │ └── scalars │ │ │ │ │ │ │ └── date.scalar.ts │ │ │ │ │ ├── recipes │ │ │ │ │ │ ├── dto │ │ │ │ │ │ │ ├── new-recipe.input.ts │ │ │ │ │ │ │ ├── non-exported.input.ts │ │ │ │ │ │ │ └── recipes.args.ts │ │ │ │ │ │ ├── models │ │ │ │ │ │ │ ├── ingredient.model.ts │ │ │ │ │ │ │ └── recipe.model.ts │ │ │ │ │ │ ├── recipes.module.ts │ │ │ │ │ │ ├── recipes.resolver.ts │ │ │ │ │ │ └── recipes.service.ts │ │ │ │ │ └── tsconfig.json │ │ │ │ └── serialized-meta.fixture.ts │ │ │ ├── helpers │ │ │ │ └── metadata-printer.ts │ │ │ ├── model-class-visitor.spec.ts │ │ │ ├── plugin-utils.spec.ts │ │ │ ├── readonly-visitor.spec.ts │ │ │ └── type-helpers │ │ │ │ ├── fixtures │ │ │ │ ├── base-type.fixture.ts │ │ │ │ ├── create-user-dto.fixture.ts │ │ │ │ └── serialized-metadata.fixture.ts │ │ │ │ ├── intersection-type.helper.spec.ts │ │ │ │ ├── omit-type.helper.spec.ts │ │ │ │ ├── partial-type.helper.spec.ts │ │ │ │ ├── pick-type.helper.spec.ts │ │ │ │ └── type-helpers.test-utils.ts │ │ ├── schema-builder │ │ │ ├── factories │ │ │ │ └── root-type.factory.spec.ts │ │ │ └── storages │ │ │ │ ├── field-directive.collection.spec.ts │ │ │ │ ├── metadata-by-name.collection.spec.ts │ │ │ │ └── metadata-list-by-name.collection.spec.ts │ │ └── utils │ │ │ └── get-number-of-arguments.util.spec.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── mercurius │ ├── LICENSE │ ├── README.md │ ├── lib │ │ ├── drivers │ │ │ ├── index.ts │ │ │ ├── mercurius-federation.driver.ts │ │ │ ├── mercurius-gateway.driver.ts │ │ │ └── mercurius.driver.ts │ │ ├── index.ts │ │ ├── interfaces │ │ │ ├── index.ts │ │ │ ├── mercurius-driver-config.interface.ts │ │ │ ├── mercurius-federation-driver-config.interface.ts │ │ │ ├── mercurius-gateway-driver-config.interface.ts │ │ │ ├── mercurius-hook.interface.ts │ │ │ └── mercurius-plugin.interface.ts │ │ └── utils │ │ │ ├── build-mercurius-federated-schema.util.ts │ │ │ ├── register-mercurius-hooks.util.ts │ │ │ ├── register-mercurius-plugin.util.ts │ │ │ ├── transform-schema.util.ts │ │ │ └── validation.util.ts │ ├── package.json │ ├── tests │ │ ├── code-first-duplicate-resolvers │ │ │ ├── app.module.ts │ │ │ ├── module-a │ │ │ │ ├── module-a.module.ts │ │ │ │ └── user.resolver.ts │ │ │ ├── module-b │ │ │ │ ├── module-b.module.ts │ │ │ │ └── user.resolver.ts │ │ │ └── query.resolver.ts │ │ ├── code-first-federation │ │ │ ├── gateway │ │ │ │ ├── gateway.module.ts │ │ │ │ └── main.ts │ │ │ ├── posts-service │ │ │ │ ├── federation-posts.module.ts │ │ │ │ ├── main.ts │ │ │ │ ├── posts │ │ │ │ │ ├── post.entity.ts │ │ │ │ │ ├── post.module.ts │ │ │ │ │ ├── post.resolver.ts │ │ │ │ │ └── post.service.ts │ │ │ │ ├── unions │ │ │ │ │ └── search-result.union.ts │ │ │ │ └── users │ │ │ │ │ ├── user.entity.ts │ │ │ │ │ ├── user.module.ts │ │ │ │ │ └── user.resolver.ts │ │ │ ├── recipes-service │ │ │ │ ├── federation-recipes.module.ts │ │ │ │ ├── main.ts │ │ │ │ └── recipes │ │ │ │ │ ├── irecipe.resolver.ts │ │ │ │ │ ├── recipe.module.ts │ │ │ │ │ └── recipe.ts │ │ │ └── users-service │ │ │ │ ├── federation-users.module.ts │ │ │ │ ├── main.ts │ │ │ │ └── users │ │ │ │ ├── user.entity.ts │ │ │ │ ├── user.module.ts │ │ │ │ ├── user.resolver.ts │ │ │ │ └── user.service.ts │ │ ├── code-first │ │ │ ├── app.module.ts │ │ │ ├── cats │ │ │ │ ├── cats.module.ts │ │ │ │ └── cats.resolver.ts │ │ │ ├── common │ │ │ │ ├── filters │ │ │ │ │ └── unauthorized.filter.ts │ │ │ │ ├── guards │ │ │ │ │ └── auth.guard.ts │ │ │ │ └── scalars │ │ │ │ │ └── date.scalar.ts │ │ │ ├── directions │ │ │ │ ├── directions.module.ts │ │ │ │ └── directions.resolver.ts │ │ │ ├── enums │ │ │ │ └── direction.enum.ts │ │ │ ├── main.ts │ │ │ ├── other │ │ │ │ ├── abstract.resolver.ts │ │ │ │ └── sample-orphaned.type.ts │ │ │ └── recipes │ │ │ │ ├── dto │ │ │ │ ├── filter-recipes-count.args.ts │ │ │ │ ├── new-recipe.input.ts │ │ │ │ └── recipes.args.ts │ │ │ │ ├── irecipes.resolver.ts │ │ │ │ ├── models │ │ │ │ ├── category.ts │ │ │ │ ├── ingredient.ts │ │ │ │ └── recipe.ts │ │ │ │ ├── recipes.module.ts │ │ │ │ ├── recipes.resolver.ts │ │ │ │ ├── recipes.service.ts │ │ │ │ └── unions │ │ │ │ └── search-result.union.ts │ │ ├── duplicate-resolvers │ │ │ ├── app.module.ts │ │ │ ├── duplicate-resolver.graphql │ │ │ ├── module-a │ │ │ │ ├── module-a.module.ts │ │ │ │ └── user.resolver.ts │ │ │ └── module-b │ │ │ │ ├── module-b.module.ts │ │ │ │ └── user.resolver.ts │ │ ├── e2e │ │ │ ├── base-hooks-array.spec.ts │ │ │ ├── base-hooks.spec.ts │ │ │ ├── code-first-federation.spec.ts │ │ │ ├── code-first-plugin.spec.ts │ │ │ ├── code-first.spec.ts │ │ │ ├── duplicate-resolvers.spec.ts │ │ │ ├── global-prefix-fastify.spec.ts │ │ │ ├── graphql-async-class.spec.ts │ │ │ ├── graphql-async-existing.spec.ts │ │ │ ├── graphql-async.spec.ts │ │ │ ├── graphql-federation-async-class.spec.ts │ │ │ ├── graphql-federation-async-existing.spec.ts │ │ │ ├── graphql-federation-async.spec.ts │ │ │ ├── graphql-federation-plugin.spec.ts │ │ │ ├── graphql-federation-schema-host.spec.ts │ │ │ ├── graphql-federation.spec.ts │ │ │ ├── graphql-gateway-plugin.spec.ts │ │ │ ├── graphql-gateway.spec.ts │ │ │ ├── graphql.spec.ts │ │ │ ├── pipes.spec.ts │ │ │ └── resolver-registration-methods.spec.ts │ │ ├── graphql-federation │ │ │ ├── gateway │ │ │ │ ├── config │ │ │ │ │ ├── config.module.ts │ │ │ │ │ └── config.service.ts │ │ │ │ ├── gateway-async-class.module.ts │ │ │ │ ├── gateway-async-existing.module.ts │ │ │ │ ├── gateway-async.module.ts │ │ │ │ └── gateway.module.ts │ │ │ ├── posts-service │ │ │ │ ├── federation-posts.module.ts │ │ │ │ └── posts │ │ │ │ │ ├── date.scalar.ts │ │ │ │ │ ├── post-type.enum.ts │ │ │ │ │ ├── posts.interfaces.ts │ │ │ │ │ ├── posts.module.ts │ │ │ │ │ ├── posts.resolvers.ts │ │ │ │ │ ├── posts.service.ts │ │ │ │ │ ├── posts.types.graphql │ │ │ │ │ ├── upper.directive.ts │ │ │ │ │ └── users.resolvers.ts │ │ │ └── users-service │ │ │ │ ├── config │ │ │ │ ├── config.module.ts │ │ │ │ └── config.service.ts │ │ │ │ ├── federation-users.async-class.module.ts │ │ │ │ ├── federation-users.async-existing.module.ts │ │ │ │ ├── federation-users.async.module.ts │ │ │ │ ├── federation-users.module.ts │ │ │ │ └── users │ │ │ │ ├── users.interfaces.ts │ │ │ │ ├── users.module.ts │ │ │ │ ├── users.resolvers.ts │ │ │ │ ├── users.service.ts │ │ │ │ └── users.types.graphql │ │ ├── graphql │ │ │ ├── app.module.ts │ │ │ ├── async-options-class.module.ts │ │ │ ├── async-options-existing.module.ts │ │ │ ├── async-options.module.ts │ │ │ ├── cats │ │ │ │ ├── cats-request-scoped.service.ts │ │ │ │ ├── cats.guard.ts │ │ │ │ ├── cats.module.ts │ │ │ │ ├── cats.resolvers.ts │ │ │ │ ├── cats.service.ts │ │ │ │ ├── cats.types.graphql │ │ │ │ └── interfaces │ │ │ │ │ └── cat.interface.ts │ │ │ ├── common │ │ │ │ └── scalars │ │ │ │ │ └── date.scalar.ts │ │ │ ├── config.module.ts │ │ │ ├── config.service.ts │ │ │ ├── global-prefix-async-options-class.module.ts │ │ │ ├── global-prefix-async-options.module.ts │ │ │ ├── global-prefix.module.ts │ │ │ ├── hello │ │ │ │ ├── cats.types.graphql │ │ │ │ ├── dto │ │ │ │ │ └── test.dto.ts │ │ │ │ ├── guards │ │ │ │ │ └── request-scoped.guard.ts │ │ │ │ ├── hello.module.ts │ │ │ │ ├── hello.resolver.ts │ │ │ │ ├── hello.service.ts │ │ │ │ ├── interceptors │ │ │ │ │ └── logging.interceptor.ts │ │ │ │ └── users │ │ │ │ │ ├── user-by-id.pipe.ts │ │ │ │ │ └── users.service.ts │ │ │ ├── main.ts │ │ │ ├── sort-auto-schema.module.ts │ │ │ ├── sort-schema.module.ts │ │ │ └── transform-auto-schema-file.module.ts │ │ ├── hooks │ │ │ ├── base-array │ │ │ │ ├── graphql.config.ts │ │ │ │ └── hooks.module.ts │ │ │ ├── base │ │ │ │ ├── graphql.config.ts │ │ │ │ └── hooks.module.ts │ │ │ ├── cats │ │ │ │ ├── cats.module.ts │ │ │ │ └── cats.resolver.ts │ │ │ └── mocks │ │ │ │ └── logger.mock.ts │ │ ├── jest-e2e.ts │ │ ├── plugins │ │ │ ├── code-first-plugin │ │ │ │ ├── app.module.ts │ │ │ │ ├── dogs │ │ │ │ │ ├── dogs.module.ts │ │ │ │ │ └── dogs.resolver.ts │ │ │ │ └── main.ts │ │ │ ├── graphql-federation-plugin │ │ │ │ ├── gateway │ │ │ │ │ └── gateway.module.ts │ │ │ │ ├── posts-service │ │ │ │ │ └── federation-posts.module.ts │ │ │ │ └── users-service │ │ │ │ │ └── federation-users.module.ts │ │ │ └── mocks │ │ │ │ ├── interfaces │ │ │ │ ├── plugin-options.interface.ts │ │ │ │ └── plugin-response.interface.ts │ │ │ │ ├── mock.plugin.ts │ │ │ │ └── utils │ │ │ │ ├── constants.ts │ │ │ │ └── plugin-response.ts │ │ ├── subscriptions-federation │ │ │ ├── app │ │ │ │ ├── app.module.ts │ │ │ │ ├── auth.guard.ts │ │ │ │ ├── notification.module.ts │ │ │ │ ├── notification.resolver.ts │ │ │ │ └── notification.ts │ │ │ └── subscriptions.spec.ts │ │ └── subscriptions │ │ │ ├── app │ │ │ ├── app.module.ts │ │ │ ├── auth.guard.ts │ │ │ ├── notification.module.ts │ │ │ ├── notification.resolver.ts │ │ │ └── notification.ts │ │ │ └── subscriptions.spec.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── tsconfig.build.json └── tsconfig.json ├── renovate.json └── yarn.lock /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-angular"], 3 | "rules": { 4 | "subject-case": [ 5 | 2, 6 | "always", 7 | ["sentence-case", "start-case", "pascal-case", "upper-case", "lower-case"] 8 | ], 9 | "type-enum": [ 10 | 2, 11 | "always", 12 | [ 13 | "build", 14 | "chore", 15 | "ci", 16 | "docs", 17 | "feat", 18 | "fix", 19 | "perf", 20 | "refactor", 21 | "revert", 22 | "style", 23 | "test", 24 | "sample" 25 | ] 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | ## To encourage contributors to use issue templates, we don't allow blank issues 2 | blank_issues_enabled: false 3 | 4 | contact_links: 5 | - name: "\u2753 Discord Community of NestJS" 6 | url: "https://discord.gg/NestJS" 7 | about: "Please ask support questions or discuss suggestions/enhancements here." 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | 4 | # IDE 5 | /.idea 6 | /.awcache 7 | /.vscode 8 | 9 | # misc 10 | npm-debug.log 11 | .DS_Store 12 | 13 | # tests 14 | /test 15 | /coverage 16 | /.nyc_output 17 | test-schema.graphql 18 | *.test-definitions.ts 19 | 20 | # dist 21 | packages/**/dist 22 | **/*.tsbuildinfo 23 | 24 | .yarn/ -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx commitlint -c --config .commitlintrc.json -E --edit $1 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # source 2 | lib 3 | tests 4 | index.ts 5 | package-lock.json 6 | tsconfig.json 7 | .prettierrc 8 | 9 | # misc 10 | .commitlintrc.json 11 | .release-it.json 12 | .eslintignore 13 | .eslintrc.js 14 | renovate.json 15 | .prettierignore 16 | .prettierrc -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | packages/**/tests/generated-definitions/*.ts 2 | packages/**/tests/**/*.fixture.ts 3 | 4 | packages/**/tests/cases/**/*.ts 5 | packages/**/tests/cases/**/*.ts 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "version": "13.1.0", 4 | "npmClient": "yarn", 5 | "changelog": { 6 | "labels": { 7 | "feature": "Features", 8 | "bug": "Bug fixes", 9 | "enhancement": "Enhancements", 10 | "dependencies": "Dependencies" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/apollo/lib/constants/apollo.constants.ts: -------------------------------------------------------------------------------- 1 | export const PLUGIN_METADATA = 'graphql:plugin'; 2 | -------------------------------------------------------------------------------- /packages/apollo/lib/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './apollo.constants'; 2 | -------------------------------------------------------------------------------- /packages/apollo/lib/decorators/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugin.decorator'; 2 | -------------------------------------------------------------------------------- /packages/apollo/lib/decorators/plugin.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | import { PLUGIN_METADATA } from '../constants'; 3 | 4 | /** 5 | * Decorator that marks a class as an Apollo plugin. 6 | * 7 | * @publicApi 8 | */ 9 | export function Plugin(): ClassDecorator { 10 | return (target: Function) => { 11 | SetMetadata(PLUGIN_METADATA, true)(target); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /packages/apollo/lib/drivers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './apollo-federation.driver'; 2 | export * from './apollo-gateway.driver'; 3 | export * from './apollo.driver'; 4 | -------------------------------------------------------------------------------- /packages/apollo/lib/errors/authentication.error.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError, GraphQLErrorOptions } from 'graphql'; 2 | 3 | /** 4 | * This error is thrown when the user is not authenticated. 5 | * 6 | * "AuthenticationError" class was removed in the latest version of Apollo Server (4.0.0) 7 | * It was moved to the @nestjs/apollo package to avoid regressions & make migration easier. 8 | * 9 | * @publicApi 10 | * 11 | */ 12 | export class AuthenticationError extends GraphQLError { 13 | constructor(message: string, options?: GraphQLErrorOptions) { 14 | super(message, { 15 | ...options, 16 | extensions: { 17 | code: 'UNAUTHENTICATED', 18 | ...options?.extensions, 19 | }, 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/apollo/lib/errors/forbidden.error.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError, GraphQLErrorOptions } from 'graphql'; 2 | 3 | /** 4 | * This error is thrown when the user is not authorized to access a resource. 5 | * 6 | * "ForbiddenError" class was removed in the latest version of Apollo Server (4.0.0) 7 | * It was moved to the @nestjs/apollo package to avoid regressions & make migration easier. 8 | * 9 | * @publicApi 10 | * 11 | */ 12 | export class ForbiddenError extends GraphQLError { 13 | constructor(message: string, options?: GraphQLErrorOptions) { 14 | super(message, { 15 | ...options, 16 | extensions: { 17 | code: 'FORBIDDEN', 18 | ...options?.extensions, 19 | }, 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/apollo/lib/errors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './authentication.error'; 2 | export * from './forbidden.error'; 3 | export * from './user-input.error'; 4 | export * from './validation.error'; 5 | -------------------------------------------------------------------------------- /packages/apollo/lib/errors/user-input.error.ts: -------------------------------------------------------------------------------- 1 | import { ApolloServerErrorCode } from '@apollo/server/errors'; 2 | import { GraphQLError, GraphQLErrorOptions } from 'graphql'; 3 | 4 | /** 5 | * This error is thrown when the user input is invalid. 6 | * 7 | * "UserInputError" class was removed in the latest version of Apollo Server (4.0.0) 8 | * It was moved to the @nestjs/apollo package to avoid regressions & make migration easier. 9 | * 10 | * @publicApi 11 | * 12 | */ 13 | export class UserInputError extends GraphQLError { 14 | constructor(message: string, options?: GraphQLErrorOptions) { 15 | super(message, { 16 | ...options, 17 | extensions: { 18 | code: ApolloServerErrorCode.BAD_USER_INPUT, 19 | ...options?.extensions, 20 | }, 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/apollo/lib/graphiql/graphiql-playground.plugin.ts: -------------------------------------------------------------------------------- 1 | import { ApolloServerPlugin } from '@apollo/server'; 2 | import { GraphiQLHTMLFactory } from './graphiql-html.factory'; 3 | import { GraphiQLOptions } from './interfaces/graphiql-options.interface'; 4 | 5 | export class GraphiQLPlaygroundPlugin implements ApolloServerPlugin { 6 | private readonly graphiqlHTMLFactory = new GraphiQLHTMLFactory(); 7 | 8 | constructor(private readonly options: GraphiQLOptions) {} 9 | 10 | async serverWillStart() { 11 | const html = this.graphiqlHTMLFactory.create(this.options); 12 | return { 13 | async renderLandingPage() { 14 | return { html }; 15 | }, 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/apollo/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './decorators'; 2 | export * from './drivers'; 3 | export * from './errors'; 4 | export * from './interfaces'; 5 | export * from './utils'; 6 | export * from './services'; 7 | -------------------------------------------------------------------------------- /packages/apollo/lib/interfaces/apollo-federation-driver-config.interface.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApolloDriverAsyncConfig, 3 | ApolloDriverConfig, 4 | ApolloDriverConfigFactory, 5 | } from './apollo-driver-config.interface'; 6 | 7 | export type ApolloFederationDriverConfig = ApolloDriverConfig; 8 | export type ApolloFederationDriverConfigFactory = ApolloDriverConfigFactory; 9 | export type ApolloFederationDriverAsyncConfig = ApolloDriverAsyncConfig; 10 | -------------------------------------------------------------------------------- /packages/apollo/lib/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './apollo-driver-config.interface'; 2 | export * from './apollo-federation-driver-config.interface'; 3 | export * from './apollo-gateway-driver-config.interface'; 4 | -------------------------------------------------------------------------------- /packages/apollo/lib/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugins-explorer.service'; 2 | -------------------------------------------------------------------------------- /packages/apollo/lib/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-apollo-server'; 2 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-duplicate-resolvers/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloDriver } from '../../lib'; 4 | import { ModuleAModule } from './module-a/module-a.module'; 5 | import { ModuleBModule } from './module-b/module-b.module'; 6 | import { QueryResolver } from './query.resolver'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRoot({ 11 | driver: ApolloDriver, 12 | autoSchemaFile: true, 13 | }), 14 | ModuleAModule, 15 | ModuleBModule, 16 | QueryResolver, 17 | ], 18 | controllers: [], 19 | providers: [], 20 | }) 21 | export class AppModule {} 22 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-duplicate-resolvers/module-a/module-a.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | 4 | @Module({ 5 | imports: [], 6 | controllers: [], 7 | providers: [UserResolver], 8 | }) 9 | export class ModuleAModule {} 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-duplicate-resolvers/module-a/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class UserResolver { 5 | @Mutation(() => String, { name: 'moduleALogin' }) 6 | login(@Args('code') code: string) { 7 | return code; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-duplicate-resolvers/module-b/module-b.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | 4 | @Module({ 5 | imports: [], 6 | controllers: [], 7 | providers: [UserResolver], 8 | }) 9 | export class ModuleBModule {} 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-duplicate-resolvers/module-b/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class UserResolver { 5 | @Mutation(() => String, { name: 'moduleBLogin' }) 6 | login(@Args('username') username: string) { 7 | return username; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-duplicate-resolvers/query.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class QueryResolver { 5 | @Query(() => Boolean, { name: '_' }) 6 | test() { 7 | return true; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/human/character.entity.ts: -------------------------------------------------------------------------------- 1 | import { Field, ID, InterfaceType } from '@nestjs/graphql'; 2 | 3 | @InterfaceType() 4 | export abstract class Character { 5 | @Field((type) => ID) 6 | id: string; 7 | 8 | @Field() 9 | name: string; 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/human/human.entity.ts: -------------------------------------------------------------------------------- 1 | import { ObjectType } from '@nestjs/graphql'; 2 | import { Character } from './character.entity'; 3 | 4 | @ObjectType({ 5 | implements: () => [Character], 6 | }) 7 | export class Human implements Character { 8 | id: string; 9 | name: string; 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/human/human.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { HumanResolver } from './human.resolver'; 3 | 4 | @Module({ 5 | providers: [HumanResolver], 6 | }) 7 | export class HumanModule {} 8 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/human/human.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Query, Resolver, ResolveField } from '@nestjs/graphql'; 2 | import { Human } from './human.entity'; 3 | import { Character } from './character.entity'; 4 | 5 | @Resolver(() => Character) 6 | export class HumanResolver { 7 | @Query(() => [Human]) 8 | humans(): Human[] { 9 | return [ 10 | { id: '1', name: 'Bob' }, 11 | { id: '2', name: 'Alice' }, 12 | ]; 13 | } 14 | 15 | @ResolveField(() => [Human]) 16 | friends(): Human[] { 17 | return [{ id: '3', name: 'Peter' }]; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/main.ts: -------------------------------------------------------------------------------- 1 | import { ValidationPipe } from '@nestjs/common'; 2 | import { NestFactory } from '@nestjs/core'; 3 | import { ApplicationModule } from './app.module'; 4 | 5 | async function bootstrap() { 6 | const app = await NestFactory.create(ApplicationModule); 7 | app.useGlobalPipes(new ValidationPipe()); 8 | await app.listen(3000); 9 | } 10 | bootstrap(); 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/post/post.entity.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Field, ID, Int, ObjectType } from '@nestjs/graphql'; 2 | 3 | @ObjectType() 4 | @Directive('@key(fields: "id")') 5 | export class Post { 6 | @Field((type) => ID) 7 | public id: number; 8 | 9 | @Field() 10 | public title: string; 11 | 12 | @Field((type) => Int) 13 | public authorId: number; 14 | 15 | constructor(post: Partial) { 16 | Object.assign(this, post); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/post/post.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PostService } from './post.service'; 3 | import { PostResolver } from './post.resolver'; 4 | 5 | @Module({ 6 | providers: [PostService, PostResolver], 7 | exports: [PostService], 8 | }) 9 | export class PostModule {} 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/post/post.service.ts: -------------------------------------------------------------------------------- 1 | import { Post } from './post.entity'; 2 | import { Injectable } from '@nestjs/common'; 3 | 4 | const data = [ 5 | { 6 | id: 1, 7 | title: 'HELLO WORLD', 8 | authorId: 2, 9 | }, 10 | { 11 | id: 2, 12 | title: 'lorem ipsum', 13 | authorId: 1, 14 | }, 15 | ]; 16 | 17 | @Injectable() 18 | export class PostService { 19 | public findOne(id: number) { 20 | const post = data.find((p) => p.id === id); 21 | if (post) { 22 | return new Post(post); 23 | } 24 | return null; 25 | } 26 | 27 | public all() { 28 | return data.map((p) => new Post(p)); 29 | } 30 | 31 | public forAuthor(authorId: number) { 32 | return data.filter((p) => p.authorId === authorId).map((p) => new Post(p)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/recipe/irecipe.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Query, Resolver } from '@nestjs/graphql'; 2 | import { IRecipe } from './recipe'; 3 | 4 | @Resolver((of) => IRecipe) 5 | export class IRecipeResolver { 6 | @Query((returns) => IRecipe) 7 | public recipe() { 8 | return { id: '1', title: 'Recipe', description: 'Interface description' }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/recipe/recipe.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { IRecipeResolver } from './irecipe.resolver'; 3 | 4 | @Module({ 5 | providers: [IRecipeResolver], 6 | }) 7 | export class RecipeModule {} 8 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/recipe/recipe.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Directive, 3 | Field, 4 | ID, 5 | InterfaceType, 6 | ObjectType, 7 | } from '@nestjs/graphql'; 8 | 9 | @InterfaceType() 10 | export abstract class Base { 11 | @Field((type) => ID) 12 | id: string; 13 | } 14 | 15 | @InterfaceType({ 16 | resolveType: (value) => { 17 | return Recipe; 18 | }, 19 | }) 20 | export abstract class IRecipe extends Base { 21 | @Field() 22 | title: string; 23 | 24 | @Field() 25 | @Directive('@external') 26 | externalField: string; 27 | } 28 | 29 | @ObjectType({ implements: IRecipe }) 30 | export class Recipe extends IRecipe { 31 | @Field() 32 | description: string; 33 | } 34 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/unions/search-result.union.ts: -------------------------------------------------------------------------------- 1 | import { createUnionType } from '@nestjs/graphql/type-factories'; 2 | import { Post } from '../post/post.entity'; 3 | import { User } from '../user/user.entity'; 4 | 5 | export const FederationSearchResultUnion = createUnionType({ 6 | name: 'FederationSearchResultUnion', 7 | description: 'Search result description', 8 | types: () => [Post, User], 9 | resolveType: (value) => { 10 | if ('posts' in value) { 11 | return User; 12 | } 13 | if ('title' in value) { 14 | return Post; 15 | } 16 | return undefined; 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/user/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Field, ID, ObjectType } from '@nestjs/graphql'; 2 | import { Post } from '../post/post.entity'; 3 | 4 | @ObjectType() 5 | @Directive('@extends') 6 | @Directive('@key(fields: "id")') 7 | export class User { 8 | @Field((type) => ID) 9 | @Directive('@external') 10 | public id: number; 11 | 12 | @Field((type) => [Post]) 13 | public posts: Post[]; 14 | 15 | constructor(post: Partial) { 16 | Object.assign(this, post); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | import { PostModule } from '../post/post.module'; 4 | 5 | @Module({ 6 | providers: [UserResolver], 7 | imports: [PostModule], 8 | }) 9 | export class UserModule {} 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first-federation/user/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Parent, ResolveField, Resolver } from '@nestjs/graphql'; 2 | import { PostService } from '../post/post.service'; 3 | import { User } from './user.entity'; 4 | 5 | @Resolver((of) => User) 6 | export class UserResolver { 7 | constructor(private readonly postService: PostService) {} 8 | 9 | @ResolveField() 10 | public posts(@Parent() user: User) { 11 | return this.postService.forAuthor(user.id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloDriverConfig } from '../../lib'; 4 | import { ApolloDriver } from '../../lib/drivers'; 5 | import { DirectionsModule } from './directions/directions.module'; 6 | import { RecipesModule } from './recipes/recipes.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | RecipesModule, 11 | DirectionsModule, 12 | GraphQLModule.forRoot({ 13 | driver: ApolloDriver, 14 | includeStacktraceInErrorResponses: false, 15 | installSubscriptionHandlers: true, 16 | autoSchemaFile: true, 17 | }), 18 | ], 19 | }) 20 | export class ApplicationModule {} 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/cats/cats.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Query, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class CatsResolver { 5 | @Query((returns) => String) 6 | getAnimalName(): string { 7 | return 'cat'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/common/filters/unauthorized.filter.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentsHost, Catch, UnauthorizedException } from '@nestjs/common'; 2 | import { GqlExceptionFilter } from '@nestjs/graphql'; 3 | 4 | @Catch(UnauthorizedException) 5 | export class UnauthorizedFilter implements GqlExceptionFilter { 6 | catch(exception: any, host: ArgumentsHost) { 7 | exception.message = 'Unauthorized error'; 8 | return exception; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/common/guards/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CanActivate, 3 | ExecutionContext, 4 | Injectable, 5 | UnauthorizedException, 6 | } from '@nestjs/common'; 7 | import { GqlExecutionContext } from '@nestjs/graphql'; 8 | 9 | @Injectable() 10 | export class AuthGuard implements CanActivate { 11 | async canActivate(context: ExecutionContext): Promise { 12 | const gqlContext = GqlExecutionContext.create(context); 13 | if (gqlContext) { 14 | throw new UnauthorizedException(); 15 | } 16 | return true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/common/scalars/date.scalar.ts: -------------------------------------------------------------------------------- 1 | import { Scalar } from '@nestjs/graphql'; 2 | import { Kind, ValueNode } from 'graphql'; 3 | 4 | @Scalar('Date', (type) => Date) 5 | export class DateScalar { 6 | description = 'Date custom scalar type'; 7 | 8 | parseValue(value: any) { 9 | return new Date(value); // value from the client 10 | } 11 | 12 | serialize(value: any) { 13 | return value.getTime(); // value sent to the client 14 | } 15 | 16 | parseLiteral(ast: ValueNode) { 17 | if (ast.kind === Kind.INT) { 18 | return parseInt(ast.value, 10); // ast value is always in string format 19 | } 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/directions/directions.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { DirectionsResolver } from './directions.resolver'; 3 | 4 | @Module({ 5 | providers: [DirectionsResolver], 6 | }) 7 | export class DirectionsModule {} 8 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/directions/directions.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Query, Resolver } from '@nestjs/graphql'; 2 | import { Direction } from '../enums/direction.enum'; 3 | 4 | @Resolver() 5 | export class DirectionsResolver { 6 | @Query((returns) => Direction) 7 | move( 8 | @Args({ name: 'direction', type: () => Direction }) 9 | direction: Direction, 10 | ): Direction { 11 | return direction; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/enums/direction.enum.ts: -------------------------------------------------------------------------------- 1 | import { registerEnumType } from '@nestjs/graphql'; 2 | 3 | export enum Direction { 4 | Up = 'UP', 5 | Down = 'DOWN', 6 | Left = 'LEFT', 7 | Right = 'RIGHT', 8 | Sideways = 'SIDEWAYS', 9 | } 10 | 11 | registerEnumType(Direction, { 12 | name: 'Direction', // this one is mandatory 13 | description: 'The basic directions', // this one is optional 14 | valuesMap: { 15 | Sideways: { 16 | deprecationReason: 'Replaced with Left or Right', 17 | }, 18 | Up: { 19 | description: 'The primary direction', 20 | }, 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/enums/sample-orphaned.enum.ts: -------------------------------------------------------------------------------- 1 | import { registerEnumType } from '@nestjs/graphql'; 2 | 3 | export enum SampleOrphanedEnum { 4 | Red = 'RED', 5 | Blue = 'BLUE', 6 | Black = 'BLACK', 7 | White = 'WHITE', 8 | } 9 | 10 | registerEnumType(SampleOrphanedEnum, { 11 | name: 'SampleOrphanedEnum', 12 | description: 'orphaned enum', 13 | }); 14 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/main.ts: -------------------------------------------------------------------------------- 1 | import { ValidationPipe } from '@nestjs/common'; 2 | import { NestFactory } from '@nestjs/core'; 3 | import { ApplicationModule } from './app.module'; 4 | 5 | async function bootstrap() { 6 | const app = await NestFactory.create(ApplicationModule); 7 | app.useGlobalPipes(new ValidationPipe()); 8 | await app.listen(3000); 9 | } 10 | bootstrap(); 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/other/abstract.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Query, Resolver } from '@nestjs/graphql'; 2 | import { RecipesArgs } from '../recipes/dto/recipes.args'; 3 | import { Recipe } from '../recipes/models/recipe'; 4 | 5 | @Resolver(() => Recipe, { isAbstract: true }) 6 | export class AbstractResolver { 7 | @Query((returns) => [Recipe]) 8 | abstractRecipes(@Args() recipesArgs: RecipesArgs): Recipe[] { 9 | return []; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/other/sample-orphaned.type.ts: -------------------------------------------------------------------------------- 1 | import { Field, ID, ObjectType } from '@nestjs/graphql'; 2 | 3 | @ObjectType({ description: 'orphaned type' }) 4 | export class SampleOrphanedType { 5 | @Field((type) => ID) 6 | id: string; 7 | 8 | @Field() 9 | title: string; 10 | 11 | @Field({ nullable: true }) 12 | description?: string; 13 | 14 | @Field() 15 | creationDate: Date; 16 | 17 | @Field() 18 | get averageRating(): number { 19 | return 0.5; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/recipes/dto/filter-recipes-count.args.ts: -------------------------------------------------------------------------------- 1 | import { ArgsType, Field } from '@nestjs/graphql'; 2 | @ArgsType() 3 | export class FilterRecipesCountArgs { 4 | @Field({ nullable: true }) 5 | type?: string; 6 | 7 | @Field({ nullable: true }) 8 | status?: string; 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/recipes/dto/new-recipe.input.ts: -------------------------------------------------------------------------------- 1 | import { Field, InputType } from '@nestjs/graphql'; 2 | import { Type } from 'class-transformer'; 3 | import { Length, MaxLength } from 'class-validator'; 4 | 5 | @InputType({ description: 'new recipe input' }) 6 | export class NewRecipeInput { 7 | @Field({ description: 'recipe title' }) 8 | @MaxLength(30) 9 | title: string; 10 | 11 | @Field({ nullable: true }) 12 | @Length(30, 255) 13 | description?: string; 14 | 15 | @Field({ nullable: false, defaultValue: 'published' }) 16 | status: string; 17 | 18 | @Type(() => String) 19 | @Field((type) => [String]) 20 | ingredients: string[]; 21 | } 22 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/recipes/dto/recipes.args.ts: -------------------------------------------------------------------------------- 1 | import { ArgsType, Field, Int } from '@nestjs/graphql'; 2 | import { Max, Min } from 'class-validator'; 3 | @ArgsType() 4 | export class RecipesArgs { 5 | @Field((type) => Int, { 6 | description: 'number of items to skip', 7 | nullable: true, 8 | }) 9 | @Min(0) 10 | skip: number = 0; 11 | 12 | @Field((type) => Int, { nullable: true }) 13 | @Min(1) 14 | @Max(50) 15 | take: number = 25; 16 | } 17 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/recipes/ingredients.resolver.ts: -------------------------------------------------------------------------------- 1 | import { ID, ResolveField, Resolver, Parent } from '@nestjs/graphql'; 2 | import { Ingredient } from './models/ingredient'; 3 | 4 | @Resolver((of) => Ingredient) 5 | export class IngredientsResolver { 6 | @ResolveField(() => ID) 7 | id(@Parent() { id }: Ingredient): string { 8 | return id; 9 | } 10 | 11 | @ResolveField() 12 | name(@Parent() { name }: Ingredient): string { 13 | return name; 14 | } 15 | 16 | @ResolveField() 17 | baseName(@Parent() { name }: Ingredient): string { 18 | return name; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/recipes/irecipes.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, ResolveField, Resolver } from '@nestjs/graphql'; 2 | import { IRecipe } from './models/recipe'; 3 | 4 | @Resolver((of) => IRecipe) 5 | export class IRecipesResolver { 6 | @ResolveField('interfaceResolver', () => Boolean) 7 | interfaceResolver( 8 | @Args('arg', { type: () => Number, nullable: true }) arg: number, 9 | ) { 10 | return true; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/recipes/models/category.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '@nestjs/graphql'; 2 | @ObjectType() 3 | export class Category { 4 | @Field((type) => String) 5 | name: string; 6 | 7 | @Field((type) => String, { defaultValue: 'default value' }) 8 | description: string; 9 | 10 | @Field((type) => [String], { defaultValue: [] }) 11 | tags: string[]; 12 | 13 | constructor(category: Partial) { 14 | Object.assign(this, category); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/apollo/tests/code-first/recipes/unions/search-result.union.ts: -------------------------------------------------------------------------------- 1 | import { createUnionType } from '@nestjs/graphql'; 2 | import { Ingredient } from '../models/ingredient'; 3 | import { Recipe } from '../models/recipe'; 4 | 5 | export const SearchResultUnion = createUnionType({ 6 | name: 'SearchResultUnion', 7 | description: 'Search result description', 8 | types: () => [Ingredient, Recipe], 9 | resolveType: (value) => { 10 | if ('name' in value) { 11 | return Ingredient; 12 | } 13 | if ('title' in value) { 14 | return Recipe; 15 | } 16 | return undefined; 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /packages/apollo/tests/duplicate-resolvers/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { ApolloDriver } from '../../lib'; 5 | import { ModuleAModule } from './module-a/module-a.module'; 6 | import { ModuleBModule } from './module-b/module-b.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRoot({ 11 | driver: ApolloDriver, 12 | typePaths: [join(__dirname, '*.graphql')], 13 | }), 14 | ModuleAModule, 15 | ModuleBModule, 16 | ], 17 | controllers: [], 18 | providers: [], 19 | }) 20 | export class AppModule {} 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/duplicate-resolvers/duplicate-resolver.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | _: Boolean 3 | } 4 | 5 | type Mutation { 6 | moduleALogin(code: String): String 7 | moduleBLogin(username: String): String 8 | } 9 | -------------------------------------------------------------------------------- /packages/apollo/tests/duplicate-resolvers/module-a/module-a.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | 4 | @Module({ 5 | imports: [], 6 | controllers: [], 7 | providers: [UserResolver], 8 | }) 9 | export class ModuleAModule {} 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/duplicate-resolvers/module-a/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class UserResolver { 5 | @Mutation('moduleALogin') 6 | login(@Args('code') code: string) { 7 | return code; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/duplicate-resolvers/module-b/module-b.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | 4 | @Module({ 5 | imports: [], 6 | controllers: [], 7 | providers: [UserResolver], 8 | }) 9 | export class ModuleBModule {} 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/duplicate-resolvers/module-b/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class UserResolver { 5 | @Mutation('moduleBLogin') 6 | login(@Args('username') username: string) { 7 | return username; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/array-property.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export interface Foo { 12 | a: string[]; 13 | b?: Nullable; 14 | c: Nullable[]; 15 | d?: Nullable[]>; 16 | e: string[][]; 17 | f: string[][][]; 18 | g?: Nullable[]>[]>[]>; 19 | } 20 | 21 | type Nullable = T | null; 22 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/array-property.graphql: -------------------------------------------------------------------------------- 1 | type Foo { 2 | a: [String!]! 3 | b: [String!] 4 | c: [String]! 5 | d: [String] 6 | e: [[String!]!]! 7 | f: [[[String!]!]!]! 8 | g: [[[String]]] 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/custom-header.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | /* Put anything here you like */ 12 | export type CustomDate = any; 13 | type Nullable = T | null; 14 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/custom-header.graphql: -------------------------------------------------------------------------------- 1 | scalar CustomDate -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/custom-scalar-default-type.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | export type CustomDate = unknown; 11 | type Nullable = T | null; 12 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/custom-scalar-type-mapping.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | export type List = string[]; 11 | export type Point = [number, number]; 12 | export type DateTime = Date; 13 | type Nullable = T | null; 14 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/custom-scalar-type-mapping.graphql: -------------------------------------------------------------------------------- 1 | scalar List 2 | scalar Point 3 | scalar DateTime -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/custom-scalar.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | export type CustomDate = any; 11 | type Nullable = T | null; 12 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/custom-scalar.graphql: -------------------------------------------------------------------------------- 1 | scalar CustomDate 2 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/enum-as-type.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | export type Foobar = "Foo" | "Bar" | "Baz"; 11 | type Nullable = T | null; 12 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/enum-as-type.graphql: -------------------------------------------------------------------------------- 1 | enum Foobar { 2 | Foo 3 | Bar 4 | Baz 5 | } 6 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/enum.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export enum Foobar { 12 | Foo = "Foo", 13 | Bar = "Bar", 14 | Baz = "Baz" 15 | } 16 | 17 | type Nullable = T | null; 18 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/enum.graphql: -------------------------------------------------------------------------------- 1 | enum Foobar { 2 | Foo 3 | Bar 4 | Baz 5 | } 6 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/federation-partial-query.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export interface IQuery { 12 | foo(): Nullable | Promise>; 13 | } 14 | 15 | type Nullable = T | null; 16 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/federation-partial-query.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | foo: Boolean 3 | } 4 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/federation-typedef.graphql: -------------------------------------------------------------------------------- 1 | type Post { 2 | id: ID! 3 | title: String! 4 | author: User! 5 | category: Category! 6 | } 7 | 8 | extend type User @key(fields: "id") { 9 | id: ID! @external 10 | posts: [Post] 11 | } 12 | 13 | extend type Query { 14 | getPosts: [Post] 15 | } 16 | 17 | extend enum Category { 18 | POST 19 | } 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/federation.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export enum Category { 12 | POST = "POST" 13 | } 14 | 15 | export class Post { 16 | id: string; 17 | title: string; 18 | author: User; 19 | category: Category; 20 | } 21 | 22 | export abstract class IQuery { 23 | abstract getPosts(): Nullable[]> | Promise[]>>; 24 | } 25 | 26 | export class User { 27 | id: string; 28 | posts?: Nullable[]>; 29 | } 30 | 31 | type Nullable = T | null; 32 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/federation.graphql: -------------------------------------------------------------------------------- 1 | type Post { 2 | id: ID! 3 | title: String! 4 | author: User! 5 | category: Category! 6 | } 7 | 8 | extend type User @key(fields: "id") { 9 | id: ID! @external 10 | posts: [Post] 11 | } 12 | 13 | extend type Query { 14 | getPosts: [Post] 15 | } 16 | 17 | extend enum Category { 18 | POST 19 | } 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/interface-property.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export interface Bar { 12 | id: number; 13 | } 14 | 15 | export interface Foo { 16 | a: Bar; 17 | b?: Nullable; 18 | } 19 | 20 | type Nullable = T | null; 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/interface-property.graphql: -------------------------------------------------------------------------------- 1 | type Bar { 2 | id: Int! 3 | } 4 | 5 | type Foo { 6 | a: Bar! 7 | b: Bar 8 | } 9 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/mutation.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export interface Cat { 12 | id: number; 13 | } 14 | 15 | export interface IMutation { 16 | createCat(name?: Nullable): Nullable | Promise>; 17 | returnsQuery(): Nullable | Promise>; 18 | } 19 | 20 | export interface IQuery { 21 | query(): Nullable | Promise>; 22 | } 23 | 24 | type Nullable = T | null; 25 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/mutation.graphql: -------------------------------------------------------------------------------- 1 | type Cat { 2 | id: Int! 3 | } 4 | 5 | type Mutation { 6 | createCat(name: String): Cat 7 | returnsQuery: Query 8 | } 9 | 10 | type Query { 11 | query: Int 12 | } 13 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/query-skip-args.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export interface Cat { 12 | id: number; 13 | } 14 | 15 | export interface IQuery { 16 | cat?: Nullable; 17 | } 18 | 19 | type Nullable = T | null; 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/query.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export interface Cat { 12 | id: number; 13 | } 14 | 15 | export interface IQuery { 16 | cat(id: string): Nullable | Promise>; 17 | } 18 | 19 | type Nullable = T | null; 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/query.graphql: -------------------------------------------------------------------------------- 1 | type Cat { 2 | id: Int! 3 | } 4 | 5 | type Query { 6 | cat(id: ID!): Cat 7 | } 8 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/simple-type.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export interface Cat { 12 | id: number; 13 | name: string; 14 | age?: Nullable; 15 | color?: Nullable; 16 | weight?: Nullable; 17 | } 18 | 19 | type Nullable = T | null; 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/simple-type.graphql: -------------------------------------------------------------------------------- 1 | type Cat { 2 | id: Int! 3 | name: String! 4 | age: Int 5 | color: String 6 | weight: Int 7 | } 8 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/typename.fixture.ts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ------------------------------------------------------- 4 | * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 5 | * ------------------------------------------------------- 6 | */ 7 | 8 | /* tslint:disable */ 9 | /* eslint-disable */ 10 | 11 | export interface Cat { 12 | __typename?: 'Cat'; 13 | id: number; 14 | name: string; 15 | age?: Nullable; 16 | color?: Nullable; 17 | weight?: Nullable; 18 | } 19 | 20 | type Nullable = T | null; 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/generated-definitions/typename.graphql: -------------------------------------------------------------------------------- 1 | type Cat { 2 | id: Int! 3 | name: String! 4 | age: Int 5 | color: String 6 | weight: Int 7 | } 8 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/gateway/config/config.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigService } from './config.service'; 3 | 4 | @Module({ 5 | providers: [ConfigService], 6 | exports: [ConfigService], 7 | }) 8 | export class ConfigModule {} 9 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/gateway/config/config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { 3 | ApolloGatewayDriverConfig, 4 | ApolloGatewayDriverConfigFactory, 5 | } from '../../../../lib'; 6 | import { supergraphSdl } from '../supergraph-sdl'; 7 | 8 | @Injectable() 9 | export class ConfigService implements ApolloGatewayDriverConfigFactory { 10 | public createGqlOptions(): Partial { 11 | return { 12 | gateway: { 13 | supergraphSdl, 14 | }, 15 | }; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/gateway/gateway-async-class.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloGatewayDriverConfig } from '../../../lib'; 4 | import { ApolloGatewayDriver } from '../../../lib/drivers'; 5 | import { ConfigModule } from './config/config.module'; 6 | import { ConfigService } from './config/config.service'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: ApolloGatewayDriver, 12 | useClass: ConfigService, 13 | imports: [ConfigModule], 14 | inject: [ConfigService], 15 | }), 16 | ], 17 | }) 18 | export class AppModule {} 19 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/gateway/gateway-async-existing.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloGatewayDriverConfig } from '../../../lib'; 4 | import { ApolloGatewayDriver } from '../../../lib/drivers'; 5 | import { ConfigModule } from './config/config.module'; 6 | import { ConfigService } from './config/config.service'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: ApolloGatewayDriver, 12 | useExisting: ConfigService, 13 | imports: [ConfigModule], 14 | inject: [ConfigService], 15 | }), 16 | ], 17 | }) 18 | export class AppModule {} 19 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/gateway/gateway-async.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloGatewayDriver } from '../../../lib/drivers'; 4 | import { ApolloGatewayDriverConfig } from '../../../lib/interfaces'; 5 | import { ConfigModule } from './config/config.module'; 6 | import { ConfigService } from './config/config.service'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: ApolloGatewayDriver, 12 | useFactory: async (configService: ConfigService) => ({ 13 | ...configService.createGqlOptions(), 14 | }), 15 | imports: [ConfigModule], 16 | inject: [ConfigService], 17 | }), 18 | ], 19 | }) 20 | export class AppModule {} 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/gateway/gateway.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloGatewayDriver } from '../../../lib/drivers'; 4 | import { supergraphSdl } from './supergraph-sdl'; 5 | 6 | @Module({ 7 | imports: [ 8 | GraphQLModule.forRoot({ 9 | driver: ApolloGatewayDriver, 10 | gateway: { 11 | includeStacktraceInErrorResponses: false, 12 | supergraphSdl, 13 | }, 14 | }), 15 | ], 16 | }) 17 | export class AppModule {} 18 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/posts-service/posts/post-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum PostType { 2 | IMAGE = 'IMAGE', 3 | TEXT = 'TEXT', 4 | } 5 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/posts-service/posts/posts.interfaces.ts: -------------------------------------------------------------------------------- 1 | import { PostType } from './post-type.enum'; 2 | 3 | export interface Post { 4 | id: string; 5 | title: string; 6 | body: string; 7 | userId: string; 8 | publishDate: Date; 9 | type: PostType; 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/posts-service/posts/posts.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PostsResolvers } from './posts.resolvers'; 3 | import { UsersResolvers } from './users.resolvers'; 4 | import { PostsService } from './posts.service'; 5 | import { DateScalar } from './date.scalar'; 6 | 7 | @Module({ 8 | providers: [PostsResolvers, PostsService, UsersResolvers, DateScalar], 9 | }) 10 | export class PostsModule {} 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/posts-service/posts/posts.types.graphql: -------------------------------------------------------------------------------- 1 | directive @upper on FIELD_DEFINITION 2 | 3 | scalar Date 4 | 5 | enum PostType { 6 | TEXT 7 | IMAGE 8 | } 9 | 10 | type Post @key(fields: "id") { 11 | id: ID! 12 | title: String! 13 | body: String! 14 | user: User 15 | publishDate: Date 16 | type: PostType 17 | } 18 | 19 | extend type User @key(fields: "id") { 20 | id: ID! @external 21 | posts: [Post] 22 | } 23 | 24 | extend type Query { 25 | getPosts(type: PostType): [Post] 26 | } 27 | 28 | extend type Mutation { 29 | publishPost(id: ID!, publishDate: Date!): Post 30 | } 31 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/posts-service/posts/users.resolvers.ts: -------------------------------------------------------------------------------- 1 | import { ResolveField, Resolver } from '@nestjs/graphql'; 2 | import { PostsService } from './posts.service'; 3 | @Resolver('User') 4 | export class UsersResolvers { 5 | constructor(private readonly postsService: PostsService) {} 6 | 7 | @ResolveField('posts') 8 | getPosts(reference: any) { 9 | return this.postsService.findByUserId(reference.id); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/config/config.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigService } from './config.service'; 3 | 4 | @Module({ 5 | providers: [ConfigService], 6 | exports: [ConfigService], 7 | }) 8 | export class ConfigModule {} 9 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/config/config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { ApolloServerPluginInlineTraceDisabled } from '@apollo/server/plugin/disabled'; 3 | import { join } from 'path'; 4 | import { ApolloDriverConfig, ApolloDriverConfigFactory } from '../../../../lib'; 5 | 6 | @Injectable() 7 | export class ConfigService implements ApolloDriverConfigFactory { 8 | public createGqlOptions(): Partial { 9 | return { 10 | typePaths: [join(__dirname, '../**/*.graphql')], 11 | plugins: [ApolloServerPluginInlineTraceDisabled()], 12 | }; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/federation-users.async-class.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloFederationDriver } from '../../../lib/drivers'; 4 | import { ConfigModule } from './config/config.module'; 5 | import { ConfigService } from './config/config.service'; 6 | import { UsersModule } from './users/users.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: ApolloFederationDriver, 12 | useClass: ConfigService, 13 | imports: [ConfigModule], 14 | inject: [ConfigService], 15 | }), 16 | UsersModule, 17 | ], 18 | }) 19 | export class AppModule {} 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/federation-users.async-existing.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloFederationDriver } from '../../../lib/drivers'; 4 | import { ConfigModule } from './config/config.module'; 5 | import { ConfigService } from './config/config.service'; 6 | import { UsersModule } from './users/users.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: ApolloFederationDriver, 12 | useExisting: ConfigService, 13 | imports: [ConfigModule], 14 | inject: [ConfigService], 15 | }), 16 | UsersModule, 17 | ], 18 | }) 19 | export class AppModule {} 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/federation-users.async.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloFederationDriver } from '../../../lib/drivers'; 4 | import { ConfigModule } from './config/config.module'; 5 | import { ConfigService } from './config/config.service'; 6 | import { UsersModule } from './users/users.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: ApolloFederationDriver, 12 | useFactory: async (configService: ConfigService) => ({ 13 | ...configService.createGqlOptions(), 14 | }), 15 | imports: [ConfigModule], 16 | inject: [ConfigService], 17 | }), 18 | UsersModule, 19 | ], 20 | }) 21 | export class AppModule {} 22 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/federation-users.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloServerPluginInlineTraceDisabled } from '@apollo/server/plugin/disabled'; 4 | import { join } from 'path'; 5 | import { ApolloDriverConfig } from '../../../lib'; 6 | import { ApolloFederationDriver } from '../../../lib/drivers'; 7 | import { UsersModule } from './users/users.module'; 8 | 9 | @Module({ 10 | imports: [ 11 | GraphQLModule.forRoot({ 12 | driver: ApolloFederationDriver, 13 | typePaths: [join(__dirname, '**/*.graphql')], 14 | plugins: [ApolloServerPluginInlineTraceDisabled()], 15 | }), 16 | UsersModule, 17 | ], 18 | }) 19 | export class AppModule {} 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/users/users.interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | id: string; 3 | name: string; 4 | } 5 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/users/users.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UsersResolvers } from './users.resolvers'; 3 | import { UsersService } from './users.service'; 4 | 5 | @Module({ 6 | providers: [UsersResolvers, UsersService], 7 | }) 8 | export class UsersModule {} 9 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/users/users.resolvers.ts: -------------------------------------------------------------------------------- 1 | import { Args, Query, Resolver, ResolveReference } from '@nestjs/graphql'; 2 | import { UsersService } from './users.service'; 3 | @Resolver('User') 4 | export class UsersResolvers { 5 | constructor(private readonly usersService: UsersService) {} 6 | 7 | @Query() 8 | getUser(@Args('id') id: string) { 9 | return this.usersService.findById(id); 10 | } 11 | 12 | @ResolveReference() 13 | resolveReference(reference: { __typename: string; id: string }) { 14 | return this.usersService.findById(reference.id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/users/users.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { User } from './users.interfaces'; 3 | 4 | @Injectable() 5 | export class UsersService { 6 | private readonly users: User[] = [ 7 | { 8 | id: '5', 9 | name: 'GraphQL', 10 | }, 11 | ]; 12 | 13 | findById(id: string) { 14 | return Promise.resolve(this.users.find((p) => p.id === id)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql-federation/users-service/users/users.types.graphql: -------------------------------------------------------------------------------- 1 | type User @key(fields: "id") { 2 | id: ID! 3 | name: String! 4 | } 5 | 6 | extend type Query { 7 | getUser(id: ID!): User 8 | } -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { ApolloDriverConfig } from '../../lib'; 5 | import { ApolloDriver } from '../../lib/drivers'; 6 | import { CatsModule } from './cats/cats.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRoot({ 12 | driver: ApolloDriver, 13 | typePaths: [join(__dirname, '**', '*.graphql')], 14 | }), 15 | ], 16 | }) 17 | export class ApplicationModule {} 18 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/async-options-class.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GqlOptionsFactory, GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { ApolloDriverConfig } from '../../lib'; 5 | import { ApolloDriver } from '../../lib/drivers'; 6 | import { CatsModule } from './cats/cats.module'; 7 | 8 | class ConfigService implements GqlOptionsFactory { 9 | createGqlOptions(): ApolloDriverConfig { 10 | return { 11 | typePaths: [join(__dirname, '**', '*.graphql')], 12 | }; 13 | } 14 | } 15 | 16 | @Module({ 17 | imports: [ 18 | CatsModule, 19 | GraphQLModule.forRootAsync({ 20 | driver: ApolloDriver, 21 | useClass: ConfigService, 22 | }), 23 | ], 24 | }) 25 | export class AsyncClassApplicationModule {} 26 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/async-options-existing.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloDriverConfig } from '../../lib'; 4 | import { ApolloDriver } from '../../lib/drivers'; 5 | import { CatsModule } from './cats/cats.module'; 6 | import { ConfigModule } from './config.module'; 7 | import { ConfigService } from './config.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | CatsModule, 12 | GraphQLModule.forRootAsync({ 13 | driver: ApolloDriver, 14 | imports: [ConfigModule], 15 | useExisting: ConfigService, 16 | }), 17 | ], 18 | }) 19 | export class AsyncExistingApplicationModule {} 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/async-options.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { ApolloDriverConfig } from '../../lib'; 5 | import { ApolloDriver } from '../../lib/drivers'; 6 | import { CatsModule } from './cats/cats.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRootAsync({ 12 | driver: ApolloDriver, 13 | useFactory: async () => ({ 14 | typePaths: [join(__dirname, '**', '*.graphql')], 15 | }), 16 | }), 17 | ], 18 | }) 19 | export class AsyncApplicationModule {} 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/cats/cats-request-scoped.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Scope } from '@nestjs/common'; 2 | import { Cat } from './interfaces/cat.interface'; 3 | 4 | @Injectable({ scope: Scope.REQUEST }) 5 | export class CatsRequestScopedService { 6 | static COUNTER = 0; 7 | private readonly cats: Cat[] = [{ id: 1, name: 'Cat', age: 5 }]; 8 | 9 | constructor() { 10 | CatsRequestScopedService.COUNTER++; 11 | } 12 | 13 | create(cat: Cat): Cat { 14 | this.cats.push(cat); 15 | return cat; 16 | } 17 | 18 | findAll(): Cat[] { 19 | return this.cats; 20 | } 21 | 22 | findOneById(id: number): Cat { 23 | return this.cats.find((cat) => cat.id === id); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/cats/cats.guard.ts: -------------------------------------------------------------------------------- 1 | import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; 2 | import { GqlExecutionContext } from '@nestjs/graphql'; 3 | 4 | @Injectable() 5 | export class CatsGuard implements CanActivate { 6 | canActivate(context: ExecutionContext): boolean { 7 | const ctx = GqlExecutionContext.create(context); 8 | return true; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/cats/cats.module.ts: -------------------------------------------------------------------------------- 1 | import { DynamicModule, Module, Scope } from '@nestjs/common'; 2 | import { CatsRequestScopedService } from './cats-request-scoped.service'; 3 | import { CatsResolvers } from './cats.resolvers'; 4 | import { CatsService } from './cats.service'; 5 | 6 | @Module({ 7 | providers: [CatsService, CatsResolvers], 8 | }) 9 | export class CatsModule { 10 | static enableRequestScope(): DynamicModule { 11 | return { 12 | module: CatsModule, 13 | providers: [ 14 | { 15 | provide: CatsService, 16 | useClass: CatsRequestScopedService, 17 | scope: Scope.REQUEST, 18 | }, 19 | ], 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/cats/cats.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { Cat } from './interfaces/cat.interface'; 3 | 4 | @Injectable() 5 | export class CatsService { 6 | static COUNTER = 0; 7 | private readonly cats: Cat[] = [{ id: 1, name: 'Cat', age: 5 }]; 8 | 9 | constructor() { 10 | CatsService.COUNTER++; 11 | } 12 | 13 | create(cat: Cat): Cat { 14 | this.cats.push(cat); 15 | return cat; 16 | } 17 | 18 | findAll(): Cat[] { 19 | return this.cats; 20 | } 21 | 22 | findOneById(id: number): Cat { 23 | return this.cats.find((cat) => cat.id === id); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/cats/cats.types.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | getCats: [Cat] 3 | cat(id: ID!): Cat 4 | } 5 | 6 | type Mutation { 7 | createCat(name: String): Cat 8 | } 9 | 10 | type Subscription { 11 | catCreated: Cat 12 | } 13 | 14 | type Cat { 15 | id: Int 16 | name: String 17 | age: Int 18 | color: String 19 | weight: Int 20 | } 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/cats/interfaces/cat.interface.ts: -------------------------------------------------------------------------------- 1 | export interface Cat { 2 | readonly id: number; 3 | readonly name: string; 4 | readonly age: number; 5 | } 6 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/common/scalars/date.scalar.ts: -------------------------------------------------------------------------------- 1 | import { Kind } from 'graphql'; 2 | import { Scalar } from '../../../../lib'; 3 | 4 | @Scalar('Date') 5 | export class DateScalar { 6 | description = 'Date custom scalar type'; 7 | 8 | parseValue(value) { 9 | return new Date(value); // value from the client 10 | } 11 | 12 | serialize(value) { 13 | return value.getTime(); // value sent to the client 14 | } 15 | 16 | parseLiteral(ast) { 17 | if (ast.kind === Kind.INT) { 18 | return parseInt(ast.value, 10); // ast value is always in string format 19 | } 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/config.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigService } from './config.service'; 3 | 4 | @Module({ 5 | providers: [ConfigService], 6 | exports: [ConfigService], 7 | }) 8 | export class ConfigModule {} 9 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { join } from 'path'; 3 | import { 4 | ApolloDriverConfig, 5 | ApolloDriverConfigFactory, 6 | } from '../../lib/interfaces'; 7 | 8 | @Injectable() 9 | export class ConfigService implements ApolloDriverConfigFactory { 10 | createGqlOptions(): ApolloDriverConfig { 11 | return { 12 | typePaths: [join(__dirname, '**', '*.graphql')], 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/custom-context/custom-context.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloDriverConfig } from '../../../lib'; 4 | import { ApolloDriver } from '../../../lib/drivers'; 5 | import { CustomContextResolver } from './custom-context.resolver'; 6 | 7 | @Module({ 8 | imports: [ 9 | GraphQLModule.forRoot({ 10 | driver: ApolloDriver, 11 | autoSchemaFile: true, 12 | context: (request) => ({ 13 | foo: 'bar', 14 | request, 15 | }), 16 | }), 17 | ], 18 | providers: [CustomContextResolver], 19 | }) 20 | export class CustomContextModule {} 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/custom-context/custom-context.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Resolver, Query, Context } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class CustomContextResolver { 5 | @Query(() => String) 6 | fooFromContext(@Context() ctx: Record) { 7 | return ctx.foo; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/global-prefix-async-options.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { ApolloDriverConfig } from '../../lib'; 5 | import { ApolloDriver } from '../../lib/drivers'; 6 | import { CatsModule } from './cats/cats.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRootAsync({ 12 | driver: ApolloDriver, 13 | useFactory: async () => ({ 14 | typePaths: [join(__dirname, '**', '*.graphql')], 15 | useGlobalPrefix: true, 16 | }), 17 | }), 18 | ], 19 | }) 20 | export class GlobalPrefixAsyncOptionsModule {} 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/global-prefix.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { ApolloDriverConfig } from '../../lib'; 5 | import { ApolloDriver } from '../../lib/drivers'; 6 | import { CatsModule } from './cats/cats.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRoot({ 12 | driver: ApolloDriver, 13 | typePaths: [join(__dirname, '**', '*.graphql')], 14 | useGlobalPrefix: true, 15 | }), 16 | ], 17 | }) 18 | export class GlobalPrefixModule {} 19 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/hello/cats.types.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | getCats: [Cat] 3 | cat(id: ID!): Cat 4 | } 5 | 6 | type Mutation { 7 | createCat(name: String): Cat 8 | } 9 | 10 | type Subscription { 11 | catCreated: Cat 12 | } 13 | 14 | type Cat { 15 | id: Int 16 | name: String 17 | age: Int 18 | color: String 19 | weight: Int 20 | } 21 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/hello/dto/test.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString, IsNotEmpty, IsNumber } from 'class-validator'; 2 | 3 | export class TestDto { 4 | @IsString() 5 | @IsNotEmpty() 6 | string: string; 7 | 8 | @IsNumber() 9 | number: number; 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/hello/guards/request-scoped.guard.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CanActivate, 3 | ExecutionContext, 4 | Inject, 5 | Injectable, 6 | Scope, 7 | } from '@nestjs/common'; 8 | import { Observable } from 'rxjs'; 9 | 10 | @Injectable({ scope: Scope.REQUEST }) 11 | export class Guard implements CanActivate { 12 | static COUNTER = 0; 13 | static REQUEST_SCOPED_DATA = []; 14 | 15 | constructor(@Inject('REQUEST_ID') private requestId: number) { 16 | Guard.COUNTER++; 17 | } 18 | 19 | canActivate( 20 | context: ExecutionContext, 21 | ): boolean | Promise | Observable { 22 | Guard.REQUEST_SCOPED_DATA.push(this.requestId); 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/hello/hello.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable, Scope } from '@nestjs/common'; 2 | 3 | @Injectable({ scope: Scope.REQUEST }) 4 | export class HelloService { 5 | constructor(@Inject('META') private readonly meta) {} 6 | 7 | getCats(): any[] { 8 | return [{ id: 1, name: 'Cat', age: 5 }]; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/hello/interceptors/logging.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CallHandler, 3 | ExecutionContext, 4 | Inject, 5 | Injectable, 6 | NestInterceptor, 7 | Scope, 8 | } from '@nestjs/common'; 9 | import { Observable } from 'rxjs'; 10 | 11 | @Injectable({ scope: Scope.REQUEST }) 12 | export class Interceptor implements NestInterceptor { 13 | static COUNTER = 0; 14 | static REQUEST_SCOPED_DATA = []; 15 | 16 | constructor(@Inject('REQUEST_ID') private requestId: number) { 17 | Interceptor.COUNTER++; 18 | } 19 | 20 | intercept(context: ExecutionContext, call: CallHandler): Observable { 21 | Interceptor.REQUEST_SCOPED_DATA.push(this.requestId); 22 | return call.handle(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/hello/users/user-by-id.pipe.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ArgumentMetadata, 3 | Inject, 4 | Injectable, 5 | PipeTransform, 6 | } from '@nestjs/common'; 7 | import { UsersService } from './users.service'; 8 | 9 | @Injectable() 10 | export class UserByIdPipe implements PipeTransform { 11 | static COUNTER = 0; 12 | static REQUEST_SCOPED_DATA = []; 13 | 14 | constructor( 15 | @Inject('REQUEST_ID') private requestId: number, 16 | private readonly usersService: UsersService, 17 | ) { 18 | UserByIdPipe.COUNTER++; 19 | } 20 | 21 | transform(value: string, metadata: ArgumentMetadata) { 22 | UserByIdPipe.REQUEST_SCOPED_DATA.push(this.requestId); 23 | return this.usersService.findById(value); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/hello/users/users.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable, Scope } from '@nestjs/common'; 2 | 3 | @Injectable({ scope: Scope.REQUEST }) 4 | export class UsersService { 5 | static COUNTER = 0; 6 | constructor(@Inject('META') private readonly meta) { 7 | UsersService.COUNTER++; 8 | } 9 | 10 | findById(id: string) { 11 | return { id }; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { ApplicationModule } from './app.module'; 3 | 4 | async function bootstrap() { 5 | const app = await NestFactory.create(ApplicationModule); 6 | await app.listen(3000); 7 | } 8 | bootstrap(); 9 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/sort-auto-schema.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { ApolloDriver } from '../../lib/drivers'; 4 | import { DirectionsModule } from '../code-first/directions/directions.module'; 5 | import { RecipesModule } from '../code-first/recipes/recipes.module'; 6 | 7 | @Module({ 8 | imports: [ 9 | RecipesModule, 10 | DirectionsModule, 11 | GraphQLModule.forRoot({ 12 | driver: ApolloDriver, 13 | autoSchemaFile: 'schema.graphql', 14 | sortSchema: true, 15 | buildSchemaOptions: { 16 | addNewlineAtEnd: true, 17 | }, 18 | }), 19 | ], 20 | }) 21 | export class SortAutoSchemaModule {} 22 | -------------------------------------------------------------------------------- /packages/apollo/tests/graphql/sort-schema.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { ApolloDriver } from '../../lib/drivers'; 5 | import { CatsModule } from './cats/cats.module'; 6 | 7 | @Module({ 8 | imports: [ 9 | CatsModule, 10 | GraphQLModule.forRoot({ 11 | driver: ApolloDriver, 12 | typePaths: [join(__dirname, '**', '*.graphql')], 13 | sortSchema: true, 14 | }), 15 | ], 16 | }) 17 | export class SortSchemaModule {} 18 | -------------------------------------------------------------------------------- /packages/apollo/tests/jest-e2e.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from '@jest/types'; 2 | import { pathsToModuleNameMapper } from 'ts-jest'; 3 | import { compilerOptions } from '../tsconfig.spec.json'; 4 | 5 | const moduleNameMapper = pathsToModuleNameMapper(compilerOptions.paths, { 6 | prefix: '/', 7 | }); 8 | 9 | const config: Config.InitialOptions = { 10 | moduleFileExtensions: ['js', 'json', 'ts'], 11 | rootDir: '../.', 12 | testRegex: '.spec.ts$', 13 | moduleNameMapper, 14 | transform: { 15 | '^.+\\.(t|j)s$': [ 16 | 'ts-jest', 17 | { tsconfig: '/tsconfig.spec.json', isolatedModules: true }, 18 | ], 19 | }, 20 | coverageDirectory: '../coverage', 21 | testEnvironment: 'node', 22 | }; 23 | 24 | export default config; 25 | -------------------------------------------------------------------------------- /packages/apollo/tests/subscriptions/app/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; 2 | import { GqlExecutionContext } from '@nestjs/graphql'; 3 | 4 | @Injectable() 5 | export class AuthGuard implements CanActivate { 6 | canActivate(context: ExecutionContext): boolean { 7 | const ctx = GqlExecutionContext.create(context).getContext(); 8 | return !!ctx.user.startsWith('test'); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/tests/subscriptions/app/notification.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { NotificationResolver } from './notification.resolver'; 3 | 4 | @Module({ 5 | providers: [NotificationResolver], 6 | }) 7 | export class NotificationModule {} 8 | -------------------------------------------------------------------------------- /packages/apollo/tests/subscriptions/app/notification.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '@nestjs/graphql'; 2 | 3 | @ObjectType() 4 | export class Notification { 5 | @Field({ 6 | nullable: false, 7 | }) 8 | id: string; 9 | 10 | @Field({ 11 | nullable: false, 12 | }) 13 | recipient: string; 14 | 15 | @Field({ 16 | nullable: false, 17 | }) 18 | message: string; 19 | } 20 | -------------------------------------------------------------------------------- /packages/apollo/tests/subscriptions/utils/malformed-token.exception.ts: -------------------------------------------------------------------------------- 1 | export class MalformedTokenException extends Error { 2 | constructor() { 3 | super('Malformed token'); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/apollo/tests/utils/assertion-utils.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLResponse } from '@apollo/server'; 2 | import * as assert from 'assert'; 3 | 4 | const expectSingleResult = >( 5 | response: GraphQLResponse, 6 | ) => { 7 | assert(response.body.kind === 'single'); 8 | expect(response.body.singleResult.errors).toBeUndefined(); 9 | return expect(response.body.singleResult.data); 10 | }; 11 | 12 | export { expectSingleResult }; 13 | -------------------------------------------------------------------------------- /packages/apollo/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "rootDir": "./lib", 6 | "paths": { 7 | "@nestjs/graphql": ["../graphql/lib"], 8 | "@nestjs/graphql/*": ["../graphql/lib/*"], 9 | } 10 | }, 11 | "exclude": ["node_modules", "dist", "tests/**/*", "*.spec.ts"], 12 | "references": [ 13 | { 14 | "path": "../graphql/tsconfig.build.json" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/apollo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "types": ["node"], 5 | "paths": { 6 | "@nestjs/graphql": ["../graphql/lib"], 7 | "@nestjs/graphql/*": ["../graphql/lib/*"], 8 | } 9 | }, 10 | "files": [], 11 | "include": [], 12 | "references": [ 13 | { 14 | "path": "./tsconfig.build.json" 15 | }, 16 | { 17 | "path": "./tsconfig.spec.json" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/apollo/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist/tests", 5 | "types": ["jest", "node"], 6 | "rootDir": ".", 7 | "resolveJsonModule": true, 8 | "paths": { 9 | "@nestjs/graphql": ["../graphql/lib"], 10 | "@nestjs/graphql/*": ["../graphql/lib/*"] 11 | } 12 | }, 13 | "references": [ 14 | { 15 | "path": "../graphql/tsconfig.build.json" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/graphql/lib/decorators/hide-field.decorator.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @publicApi 3 | */ 4 | export function HideField(): PropertyDecorator { 5 | return (target: Record, propertyKey: string | symbol) => {}; 6 | } 7 | -------------------------------------------------------------------------------- /packages/graphql/lib/decorators/info.decorator.ts: -------------------------------------------------------------------------------- 1 | import { PipeTransform, Type } from '@nestjs/common'; 2 | import 'reflect-metadata'; 3 | import { GqlParamtype } from '../enums/gql-paramtype.enum'; 4 | import { createGqlPipesParamDecorator } from './param.utils'; 5 | 6 | /** 7 | * Resolver method parameter decorator. Extracts the `Info` 8 | * object from the underlying platform and populates the decorated 9 | * parameter with the value of `Info`. 10 | * 11 | * @publicApi 12 | */ 13 | export function Info(...pipes: (Type | PipeTransform)[]) { 14 | return createGqlPipesParamDecorator(GqlParamtype.INFO)(undefined, ...pipes); 15 | } 16 | -------------------------------------------------------------------------------- /packages/graphql/lib/decorators/parent.decorator.ts: -------------------------------------------------------------------------------- 1 | import { GqlParamtype } from '../enums/gql-paramtype.enum'; 2 | import { createGqlParamDecorator } from './param.utils'; 3 | 4 | /** 5 | * Resolver method parameter decorator. Extracts the parent/root 6 | * object from the underlying platform and populates the decorated 7 | * parameter with the value of parent/root. 8 | * 9 | * @publicApi 10 | */ 11 | export const Parent: () => ParameterDecorator = createGqlParamDecorator( 12 | GqlParamtype.ROOT, 13 | ); 14 | -------------------------------------------------------------------------------- /packages/graphql/lib/decorators/resolve-reference.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | import { RESOLVER_REFERENCE_METADATA } from '../graphql.constants'; 3 | 4 | /** 5 | * Property reference resolver (method) Decorator. 6 | * 7 | * @publicApi 8 | */ 9 | export function ResolveReference(): MethodDecorator { 10 | return ( 11 | target: Function | object, 12 | key?: string | symbol, 13 | descriptor?: any, 14 | ) => { 15 | SetMetadata(RESOLVER_REFERENCE_METADATA, true)(target, key, descriptor); 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /packages/graphql/lib/decorators/root.decorator.ts: -------------------------------------------------------------------------------- 1 | import { GqlParamtype } from '../enums/gql-paramtype.enum'; 2 | import { createGqlParamDecorator } from './param.utils'; 3 | 4 | /** 5 | * Resolver method parameter decorator. Extracts the parent/root 6 | * object from the underlying platform and populates the decorated 7 | * parameter with the value of parent/root. 8 | * 9 | * @publicApi 10 | */ 11 | export const Root: () => ParameterDecorator = createGqlParamDecorator( 12 | GqlParamtype.ROOT, 13 | ); 14 | -------------------------------------------------------------------------------- /packages/graphql/lib/drivers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './abstract-graphql.driver'; 2 | -------------------------------------------------------------------------------- /packages/graphql/lib/enums/class-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum ClassType { 2 | ARGS = 'args', 3 | OBJECT = 'objectType', 4 | INPUT = 'inputType', 5 | INTERFACE = 'interface', 6 | } 7 | -------------------------------------------------------------------------------- /packages/graphql/lib/enums/gql-paramtype.enum.ts: -------------------------------------------------------------------------------- 1 | export enum GqlParamtype { 2 | ROOT, 3 | ARGS = 3, 4 | CONTEXT = 1, 5 | INFO = 2, 6 | } 7 | -------------------------------------------------------------------------------- /packages/graphql/lib/enums/resolver.enum.ts: -------------------------------------------------------------------------------- 1 | export enum Resolver { 2 | QUERY = 'Query', 3 | MUTATION = 'Mutation', 4 | SUBSCRIPTION = 'Subscription', 5 | } 6 | -------------------------------------------------------------------------------- /packages/graphql/lib/federation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './graphql-federation-definitions.factory'; 2 | export * from './graphql-federation.factory'; 3 | -------------------------------------------------------------------------------- /packages/graphql/lib/graphql-schema.host.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { GraphQLSchema } from 'graphql'; 3 | 4 | @Injectable() 5 | export class GraphQLSchemaHost { 6 | private _schema: GraphQLSchema; 7 | 8 | set schema(schemaRef: GraphQLSchema) { 9 | this._schema = schemaRef; 10 | } 11 | 12 | get schema(): GraphQLSchema { 13 | if (!this._schema) { 14 | throw new Error( 15 | 'GraphQL schema has not yet been created. ' + 16 | 'Make sure to call the "GraphQLSchemaHost#schema" getter when the application is already initialized (after the "onModuleInit" hook triggered by either "app.listen()" or "app.init()" method).', 17 | ); 18 | } 19 | return this._schema; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/base-type-options.interface.ts: -------------------------------------------------------------------------------- 1 | export type NullableList = 'items' | 'itemsAndList'; 2 | 3 | type NonNullableBaseType = { 4 | /** 5 | * Determines whether field/argument/etc is nullable. 6 | */ 7 | nullable?: false | NullableList; 8 | /** 9 | * Default value. 10 | */ 11 | defaultValue?: T; 12 | }; 13 | 14 | type NullableBaseType = { 15 | /** 16 | * Determines whether field/argument/etc is nullable. 17 | */ 18 | nullable: true; 19 | /** 20 | * Default value. 21 | */ 22 | defaultValue?: T | null; 23 | }; 24 | 25 | export type BaseTypeOptions = 26 | | NonNullableBaseType 27 | | NullableBaseType; 28 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/build-federated-schema-options.interface.ts: -------------------------------------------------------------------------------- 1 | import { DocumentNode } from 'graphql'; 2 | 3 | export interface BuildFederatedSchemaOptions { 4 | typeDefs: DocumentNode; 5 | resolvers: any; 6 | } 7 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/class-decorator-factory.interface.ts: -------------------------------------------------------------------------------- 1 | import { ArgsType, InputType, InterfaceType, ObjectType } from '../decorators'; 2 | 3 | export type ClassDecoratorFactory = 4 | | typeof ArgsType 5 | | typeof ObjectType 6 | | typeof InterfaceType 7 | | typeof InputType; 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/complexity.interface.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLCompositeType, GraphQLField } from 'graphql'; 2 | 3 | export type ComplexityEstimatorArgs = { 4 | type: GraphQLCompositeType; 5 | field: GraphQLField; 6 | args: { [key: string]: any }; 7 | childComplexity: number; 8 | }; 9 | 10 | export type ComplexityEstimator = ( 11 | options: ComplexityEstimatorArgs, 12 | ) => number | void; 13 | export type Complexity = ComplexityEstimator | number; 14 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/custom-scalar.interface.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GraphQLScalarLiteralParser, 3 | GraphQLScalarSerializer, 4 | GraphQLScalarValueParser, 5 | } from 'graphql'; 6 | 7 | export interface CustomScalar { 8 | description?: string; 9 | parseValue: GraphQLScalarValueParser; 10 | serialize: GraphQLScalarSerializer; 11 | parseLiteral: GraphQLScalarLiteralParser; 12 | } 13 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/field-middleware.interface.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLResolveInfo } from 'graphql'; 2 | 3 | export interface MiddlewareContext< 4 | TSource = any, 5 | TContext = any, 6 | TArgs = { [argName: string]: any }, 7 | > { 8 | source: TSource; 9 | args: TArgs; 10 | context: TContext; 11 | info: GraphQLResolveInfo; 12 | } 13 | 14 | export type NextFn = () => Promise; 15 | 16 | export interface FieldMiddleware< 17 | TSource = any, 18 | TContext = any, 19 | TArgs = { [argName: string]: any }, 20 | TOutput = any, 21 | > { 22 | ( 23 | ctx: MiddlewareContext, 24 | next: NextFn, 25 | ): Promise | TOutput; 26 | } 27 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/gql-entrypoint-metadata.interface.ts: -------------------------------------------------------------------------------- 1 | export interface GqlEntrypointMetadata { 2 | key: string; 3 | parentType: string; 4 | } 5 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/gql-exception-filter.interface.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentsHost } from '@nestjs/common'; 2 | 3 | /** 4 | * Interface defining a GraphQL exception filter. 5 | * 6 | * @publicApi 7 | */ 8 | export interface GqlExceptionFilter { 9 | catch(exception: TInput, host: ArgumentsHost): TOutput; 10 | } 11 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/graphql-driver.interface.ts: -------------------------------------------------------------------------------- 1 | export interface GraphQLDriver { 2 | start(options: TOptions): Promise; 3 | stop(): Promise; 4 | } 5 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/graphql-exception.interface.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | GraphQLErrorOptions, 3 | GraphQLErrorExtensions, 4 | } from 'graphql/error'; 5 | 6 | export interface ExceptionOptions extends GraphQLErrorOptions { 7 | extensions: GraphQLErrorExtensions & { 8 | http: { 9 | status: number; 10 | }; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base-type-options.interface'; 2 | export * from './build-schema-options.interface'; 3 | export * from './complexity.interface'; 4 | export * from './custom-scalar.interface'; 5 | export * from './field-middleware.interface'; 6 | export * from './gql-exception-filter.interface'; 7 | export { 8 | Enhancer, 9 | GqlModuleAsyncOptions, 10 | GqlModuleOptions, 11 | GqlOptionsFactory, 12 | } from './gql-module-options.interface'; 13 | export * from './graphql-driver.interface'; 14 | export * from './resolve-type-fn.interface'; 15 | export * from './return-type-func.interface'; 16 | export * from './build-federated-schema-options.interface'; 17 | export * from './schema-file-config.interface'; 18 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/resolve-type-fn.interface.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLTypeResolver } from 'graphql'; 2 | 3 | export type ResolveTypeFn = ( 4 | ...args: Parameters> 5 | ) => any; 6 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/resolver-metadata.interface.ts: -------------------------------------------------------------------------------- 1 | export interface ResolverMetadata { 2 | name: string; 3 | type: string; 4 | methodName: string; 5 | callback?: Function | Record; 6 | } 7 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/return-type-func.interface.ts: -------------------------------------------------------------------------------- 1 | import { Type } from '@nestjs/common'; 2 | import { GraphQLScalarType } from 'graphql'; 3 | 4 | export type GqlTypeReference = 5 | | Type 6 | | GraphQLScalarType 7 | | Function 8 | | object 9 | | symbol; 10 | export type ReturnTypeFuncValue = GqlTypeReference | [GqlTypeReference]; 11 | export type ReturnTypeFunc = ( 12 | returns?: void, 13 | ) => T; 14 | -------------------------------------------------------------------------------- /packages/graphql/lib/interfaces/type-options.interface.ts: -------------------------------------------------------------------------------- 1 | import { BaseTypeOptions } from './base-type-options.interface'; 2 | 3 | export type TypeOptions = BaseTypeOptions & { 4 | isArray?: boolean; 5 | arrayDepth?: number; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/graphql/lib/plugin/compiler-plugin.ts: -------------------------------------------------------------------------------- 1 | import * as ts from 'typescript'; 2 | import { mergePluginOptions } from './merge-options'; 3 | import { isFilenameMatched } from './utils/is-filename-matched.util'; 4 | import { ModelClassVisitor } from './visitors/model-class.visitor'; 5 | 6 | const typeClassVisitor = new ModelClassVisitor(); 7 | 8 | export const before = (options?: Record, program?: ts.Program) => { 9 | options = mergePluginOptions(options); 10 | 11 | return (ctx: ts.TransformationContext): ts.Transformer => { 12 | return (sf: ts.SourceFile) => { 13 | if (isFilenameMatched(options.typeFileNameSuffix, sf.fileName)) { 14 | return typeClassVisitor.visit(sf, ctx, program, options); 15 | } 16 | return sf; 17 | }; 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/graphql/lib/plugin/index.ts: -------------------------------------------------------------------------------- 1 | export * from './compiler-plugin'; 2 | export * from './visitors/readonly.visitor'; 3 | -------------------------------------------------------------------------------- /packages/graphql/lib/plugin/plugin-constants.ts: -------------------------------------------------------------------------------- 1 | export const GRAPHQL_PACKAGE_NAMESPACE = 'graphql'; 2 | export const GRAPHQL_PACKAGE_NAME = '@nestjs/graphql'; 3 | export const METADATA_FACTORY_NAME = '_GRAPHQL_METADATA_FACTORY'; 4 | -------------------------------------------------------------------------------- /packages/graphql/lib/plugin/plugin-debug-logger.ts: -------------------------------------------------------------------------------- 1 | import { ConsoleLogger } from '@nestjs/common'; 2 | 3 | class PluginDebugLogger extends ConsoleLogger {} 4 | 5 | export const pluginDebugLogger = new PluginDebugLogger('CLI Plugin'); 6 | -------------------------------------------------------------------------------- /packages/graphql/lib/plugin/utils/is-filename-matched.util.ts: -------------------------------------------------------------------------------- 1 | export const isFilenameMatched = (patterns: string[], filename: string) => 2 | patterns.some((path) => filename.includes(path)); 3 | -------------------------------------------------------------------------------- /packages/graphql/lib/scalars/index.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLFloat, GraphQLID, GraphQLInt } from 'graphql'; 2 | 3 | export * from './iso-date.scalar'; 4 | export * from './timestamp.scalar'; 5 | 6 | export const Int = GraphQLInt; 7 | export const Float = GraphQLFloat; 8 | export const ID = GraphQLID; 9 | -------------------------------------------------------------------------------- /packages/graphql/lib/scalars/iso-date.scalar.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLScalarType, Kind, ValueNode } from 'graphql'; 2 | 3 | export const GraphQLISODateTime = new GraphQLScalarType({ 4 | name: 'DateTime', 5 | description: 6 | 'A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format.', 7 | parseValue(value: string) { 8 | return new Date(value); 9 | }, 10 | serialize(value: Date) { 11 | return value instanceof Date ? value.toISOString() : null; 12 | }, 13 | parseLiteral(ast: ValueNode) { 14 | return ast.kind === Kind.STRING ? new Date(ast.value) : null; 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/collections/index.ts: -------------------------------------------------------------------------------- 1 | export * from './array-with-global-cache.collection'; 2 | export * from './field-directive.collection'; 3 | export * from './metada-collection-model.interface'; 4 | export * from './metadata-by-name.collection'; 5 | export * from './metadata-by-target.collection'; 6 | export * from './metadata-list-by-name.collection'; 7 | export * from './target-metadata.collection'; 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/cannot-determine-arg-type.error.ts: -------------------------------------------------------------------------------- 1 | import { ArgsParamMetadata } from '../metadata'; 2 | 3 | export class CannotDetermineArgTypeError extends Error { 4 | constructor(hostType: string, param: ArgsParamMetadata) { 5 | super( 6 | `"${hostType}" cannot be found in the registry (${param.target.name}#${param.methodName}). This is often caused by missing argument name in the method signature. A potential fix: change @Args() to @Args('argumentName').`, 7 | ); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/cannot-determine-host-type.error.ts: -------------------------------------------------------------------------------- 1 | export class CannotDetermineHostTypeError extends Error { 2 | constructor(externalField: string, hostType?: string) { 3 | super( 4 | `Cannot determine a GraphQL host type ${ 5 | hostType ? ` (${hostType}?) ` : `` 6 | }for the "${externalField}" field. Make sure your class is decorated with an appropriate decorator (e.g., @ObjectType()).`, 7 | ); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/cannot-determine-input-type.error.ts: -------------------------------------------------------------------------------- 1 | import { GqlTypeReference } from '../../interfaces'; 2 | 3 | export class CannotDetermineInputTypeError extends Error { 4 | constructor(hostType: string, typeRef?: GqlTypeReference) { 5 | const inputObjectName: string | false = 6 | typeof typeRef === 'function' && typeRef.name; 7 | super( 8 | `Cannot determine a GraphQL input type ${ 9 | inputObjectName ? `("${inputObjectName}")` : null 10 | } for the "${hostType}". Make sure your class is decorated with an appropriate decorator.`, 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/cannot-determine-output-type.error.ts: -------------------------------------------------------------------------------- 1 | export class CannotDetermineOutputTypeError extends Error { 2 | constructor(hostType: string) { 3 | super( 4 | `Cannot determine a GraphQL output type for the "${hostType}". Make sure your class is decorated with an appropriate decorator.`, 5 | ); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/default-nullable-conflict.error.ts: -------------------------------------------------------------------------------- 1 | import { NullableList } from '../../interfaces'; 2 | 3 | export class DefaultNullableConflictError extends Error { 4 | constructor( 5 | hostTypeName: string, 6 | defaultVal: any, 7 | isNullable: boolean | NullableList, 8 | ) { 9 | super( 10 | `Incorrect "nullable" option value set for ${hostTypeName}. Do not combine "defaultValue: ${defaultVal}" with "nullable: ${isNullable}".`, 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/default-values-conflict.error.ts: -------------------------------------------------------------------------------- 1 | export class DefaultValuesConflictError extends Error { 2 | constructor( 3 | hostTypeName: string, 4 | fieldName: string, 5 | decoratorDefaultVal: any, 6 | initializerDefaultVal: any, 7 | ) { 8 | super( 9 | `Error caused by mis-matched default values for the "${fieldName}" field of "${hostTypeName}". The default value from the decorator "${decoratorDefaultVal}" is not equal to the property initializer value "${initializerDefaultVal}". Ensure that these values match.`, 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/directive-parsing.error.ts: -------------------------------------------------------------------------------- 1 | export class DirectiveParsingError extends Error { 2 | constructor(sdl: string) { 3 | super( 4 | `Directive SDL "${sdl}" is invalid. Please, pass a valid directive definition.`, 5 | ); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/invalid-nullable-option.error.ts: -------------------------------------------------------------------------------- 1 | import { NullableList } from '../../interfaces'; 2 | 3 | export class InvalidNullableOptionError extends Error { 4 | constructor(name: string, nullable?: boolean | NullableList) { 5 | super( 6 | `Incorrect nullable option set for ${name}. Do not combine non-list type with nullable "${nullable}".`, 7 | ); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/multiple-fields-with-same-name.error.ts: -------------------------------------------------------------------------------- 1 | export class MultipleFieldsWithSameNameError extends Error { 2 | constructor(field: string, objectTypeName: string) { 3 | super( 4 | `Cannot define multiple fields with the same name "${field}" for type "${objectTypeName}"`, 5 | ); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/return-type-cannot-be-resolved.error.ts: -------------------------------------------------------------------------------- 1 | export class ReturnTypeCannotBeResolvedError extends Error { 2 | constructor(hostTypeName: string) { 3 | super( 4 | `Return type for "${hostTypeName}" cannot be resolved. If you did not pass a custom implementation (the "resolveType" function), you must return an instance of a class instead of a plain JavaScript object.`, 5 | ); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/schema-generation.error.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from 'graphql'; 2 | 3 | export class SchemaGenerationError extends Error { 4 | constructor(public readonly details: ReadonlyArray) { 5 | super('Schema generation error (code-first approach)'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/unable-to-find-fields.error.ts: -------------------------------------------------------------------------------- 1 | export class UnableToFindFieldsError extends Error { 2 | constructor(name: string) { 3 | super( 4 | `Unable to find fields for GraphQL type ${name}. Is your class annotated with an appropriate decorator?`, 5 | ); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/undefined-resolver-type.error.ts: -------------------------------------------------------------------------------- 1 | export class UndefinedResolverTypeError extends Error { 2 | constructor(name: string) { 3 | super( 4 | `Undefined resolver type error. Make sure you are providing an explicit object type for the "${name}" (e.g., "@Resolver(() => Cat)").`, 5 | ); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/undefined-return-type.error.ts: -------------------------------------------------------------------------------- 1 | export class UndefinedReturnTypeError extends Error { 2 | constructor(decoratorName: string, methodKey: string) { 3 | super( 4 | `"${decoratorName}.${methodKey}" was defined in resolvers, but not in schema. If you use the @${decoratorName}() decorator with the code first approach enabled, remember to explicitly provide a return type function, e.g. @${decoratorName}(returns => Author).`, 5 | ); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/errors/undefined-type.error.ts: -------------------------------------------------------------------------------- 1 | import { isUndefined } from '@nestjs/common/utils/shared.utils'; 2 | 3 | export class UndefinedTypeError extends Error { 4 | constructor(name: string, key: string, index?: number) { 5 | super( 6 | `Undefined type error. Make sure you are providing an explicit type for the "${key}" ${ 7 | isUndefined(index) ? '' : `(parameter at index [${index}]) ` 8 | }of the "${name}" class.`, 9 | ); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/index.ts: -------------------------------------------------------------------------------- 1 | export * from './storages'; 2 | export * from './graphql-schema.factory'; 3 | export * from './schema-builder.module'; 4 | export * from './helpers/file-system.helper'; 5 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/metadata/class.metadata.ts: -------------------------------------------------------------------------------- 1 | import { DirectiveMetadata } from './directive.metadata'; 2 | import { PropertyMetadata } from './property.metadata'; 3 | 4 | export interface ClassMetadata { 5 | target: Function; 6 | name: string; 7 | description?: string; 8 | isAbstract?: boolean; 9 | directives?: DirectiveMetadata[]; 10 | extensions?: Record; 11 | properties?: PropertyMetadata[]; 12 | inheritDescription?: boolean; 13 | } 14 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/metadata/directive.metadata.ts: -------------------------------------------------------------------------------- 1 | export interface DirectiveMetadata { 2 | sdl: string; 3 | target: Function; 4 | } 5 | 6 | export type ClassDirectiveMetadata = DirectiveMetadata; 7 | 8 | export interface PropertyDirectiveMetadata extends DirectiveMetadata { 9 | fieldName: string; 10 | } 11 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/metadata/enum.metadata.ts: -------------------------------------------------------------------------------- 1 | export interface EnumMetadataValuesMapOptions { 2 | deprecationReason?: string; 3 | description?: string; 4 | } 5 | 6 | export type EnumMetadataValuesMap = Partial< 7 | Record 8 | >; 9 | 10 | export interface EnumMetadata { 11 | ref: T; 12 | name: string; 13 | description?: string; 14 | valuesMap?: EnumMetadataValuesMap; 15 | } 16 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/metadata/extensions.metadata.ts: -------------------------------------------------------------------------------- 1 | export interface ExtensionsMetadata { 2 | target: Function; 3 | value: Record; 4 | } 5 | 6 | export type ClassExtensionsMetadata = ExtensionsMetadata; 7 | 8 | export interface PropertyExtensionsMetadata extends ExtensionsMetadata { 9 | fieldName: string; 10 | } 11 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/metadata/index.ts: -------------------------------------------------------------------------------- 1 | export * from './class.metadata'; 2 | export * from './directive.metadata'; 3 | export * from './enum.metadata'; 4 | export * from './extensions.metadata'; 5 | export * from './param.metadata'; 6 | export * from './property.metadata'; 7 | export * from './resolver.metadata'; 8 | export * from './union.metadata'; 9 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/metadata/interface.metadata.ts: -------------------------------------------------------------------------------- 1 | import { ResolveTypeFn } from '../../interfaces'; 2 | import { ClassMetadata } from './class.metadata'; 3 | 4 | export interface InterfaceMetadata extends ClassMetadata { 5 | resolveType?: ResolveTypeFn; 6 | interfaces?: Function | Function[] | (() => Function | Function[]); 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/metadata/object-type.metadata.ts: -------------------------------------------------------------------------------- 1 | import { ClassMetadata } from './class.metadata'; 2 | 3 | export interface ObjectTypeMetadata extends ClassMetadata { 4 | interfaces?: Function | Function[] | (() => Function | Function[]); 5 | } 6 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/metadata/param.metadata.ts: -------------------------------------------------------------------------------- 1 | import { GqlTypeReference } from '../../interfaces'; 2 | import { TypeOptions } from '../../interfaces/type-options.interface'; 3 | 4 | export interface BaseArgMetadata { 5 | target: Function; 6 | methodName: string; 7 | typeFn: (type?: any) => GqlTypeReference; 8 | options: TypeOptions; 9 | index: number; 10 | } 11 | 12 | export interface ArgParamMetadata extends BaseArgMetadata { 13 | kind: 'arg'; 14 | name: string; 15 | description?: string; 16 | deprecationReason?: string; 17 | } 18 | 19 | export interface ArgsParamMetadata extends BaseArgMetadata { 20 | kind: 'args'; 21 | } 22 | 23 | export type MethodArgsMetadata = ArgParamMetadata | ArgsParamMetadata; 24 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/metadata/union.metadata.ts: -------------------------------------------------------------------------------- 1 | import { Type } from '@nestjs/common'; 2 | import { ResolveTypeFn } from '../../interfaces'; 3 | 4 | export interface UnionMetadata< 5 | T extends readonly Type[] = readonly Type[], 6 | > { 7 | name: string; 8 | typesFn: () => T; 9 | id?: symbol; 10 | description?: string; 11 | resolveType?: ResolveTypeFn; 12 | } 13 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/services/orphaned-reference.registry.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { isFunction } from '@nestjs/common/utils/shared.utils'; 3 | import { GqlTypeReference } from '../../interfaces'; 4 | 5 | const BANNED_TYPES: Function[] = [String, Date, Number, Boolean]; 6 | 7 | @Injectable() 8 | export class OrphanedReferenceRegistry { 9 | private readonly registry = new Set(); 10 | 11 | addToRegistryIfOrphaned(typeRef: GqlTypeReference) { 12 | if (!isFunction(typeRef)) { 13 | return; 14 | } 15 | if (BANNED_TYPES.includes(typeRef as Function)) { 16 | return; 17 | } 18 | this.registry.add(typeRef as Function); 19 | } 20 | 21 | getAll(): Function[] { 22 | return [...this.registry.values()]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/storages/index.ts: -------------------------------------------------------------------------------- 1 | export { TypeMetadataStorage } from './type-metadata.storage'; 2 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/utils/get-interfaces-array.util.ts: -------------------------------------------------------------------------------- 1 | import { isFunction } from '@nestjs/common/utils/shared.utils'; 2 | import { ObjectTypeMetadata } from '../metadata/object-type.metadata'; 3 | 4 | function isNativeClass(fn: Function) { 5 | return ( 6 | typeof fn === 'function' && 7 | /^class\s/.test(Function.prototype.toString.call(fn)) 8 | ); 9 | } 10 | 11 | export function getInterfacesArray( 12 | interfaces: ObjectTypeMetadata['interfaces'], 13 | ): Function[] { 14 | if (!interfaces) { 15 | return []; 16 | } 17 | if (Array.isArray(interfaces)) { 18 | return interfaces; 19 | } 20 | if (isFunction(interfaces) && !isNativeClass(interfaces)) { 21 | interfaces = (interfaces as Function)(); 22 | } 23 | return [].concat(interfaces); 24 | } 25 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/utils/is-target-equal-util.ts: -------------------------------------------------------------------------------- 1 | export type TargetHost = Record<'target', Function>; 2 | export function isTargetEqual( 3 | a: T, 4 | b: U, 5 | ) { 6 | return a.target === b.target; 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/lib/schema-builder/utils/is-throwing.util.ts: -------------------------------------------------------------------------------- 1 | export function isThrowing(func: () => unknown) { 2 | try { 3 | func(); 4 | return false; 5 | } catch { 6 | return true; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/graphql/lib/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base-explorer.service'; 2 | export * from './gql-arguments-host'; 3 | export * from './gql-execution-context'; 4 | export * from './gql-subscription.service'; 5 | export * from './resolvers-explorer.service'; 6 | export * from './scalars-explorer.service'; 7 | -------------------------------------------------------------------------------- /packages/graphql/lib/tokens.ts: -------------------------------------------------------------------------------- 1 | import { REQUEST } from '@nestjs/core'; 2 | 3 | export const CONTEXT = REQUEST; 4 | -------------------------------------------------------------------------------- /packages/graphql/lib/type-factories/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-union-type.factory'; 2 | export * from './register-enum-type.factory'; 3 | -------------------------------------------------------------------------------- /packages/graphql/lib/type-helpers/field-type.helper.ts: -------------------------------------------------------------------------------- 1 | export type FieldType = T; 2 | -------------------------------------------------------------------------------- /packages/graphql/lib/type-helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './field-type.helper'; 2 | export * from './intersection-type.helper'; 3 | export * from './omit-type.helper'; 4 | export * from './partial-type.helper'; 5 | export * from './pick-type.helper'; 6 | -------------------------------------------------------------------------------- /packages/graphql/lib/type-helpers/type-helpers.utils.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Extensions } from '../decorators'; 2 | import { PropertyMetadata } from '../schema-builder/metadata'; 3 | 4 | export function applyFieldDecorators( 5 | targetClass: Function, 6 | item: PropertyMetadata, 7 | ) { 8 | if (item.extensions) { 9 | Extensions(item.extensions)(targetClass.prototype, item.name); 10 | } 11 | if (item.directives?.length) { 12 | item.directives.map((directive) => { 13 | Directive(directive.sdl)(targetClass.prototype, item.name); 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/add-class-type-metadata.util.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | import { ClassType } from '../enums/class-type.enum'; 3 | import { CLASS_TYPE_METADATA } from '../graphql.constants'; 4 | 5 | export function addClassTypeMetadata(target: Function, classType: ClassType) { 6 | const decoratorFactory: ClassDecorator = SetMetadata( 7 | CLASS_TYPE_METADATA, 8 | classType, 9 | ); 10 | decoratorFactory(target); 11 | } 12 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/auto-schema-file.util.ts: -------------------------------------------------------------------------------- 1 | import { isObject, isString } from '@nestjs/common/utils/shared.utils'; 2 | import { AutoSchemaFileValue } from '../interfaces'; 3 | 4 | export function getPathForAutoSchemaFile( 5 | autoSchemaFile: AutoSchemaFileValue, 6 | ): string | null { 7 | if (isString(autoSchemaFile)) { 8 | return autoSchemaFile; 9 | } 10 | if (isObject(autoSchemaFile) && autoSchemaFile.path) { 11 | return autoSchemaFile.path; 12 | } 13 | return null; 14 | } 15 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/extend.util.ts: -------------------------------------------------------------------------------- 1 | import { defaultTo, isArray, isString } from 'lodash'; 2 | 3 | export function extend(obj1: unknown, obj2: unknown) { 4 | if (isString(obj1)) { 5 | return isString(obj2) 6 | ? [defaultTo(obj1, ''), defaultTo(obj2, '')] 7 | : [defaultTo(obj1, '')].concat(defaultTo(obj2, [])); 8 | } 9 | if (isArray(obj1)) { 10 | return defaultTo(obj1, []).concat(defaultTo(obj2, [])); 11 | } 12 | return { 13 | ...((obj1 as object) || {}), 14 | ...((obj2 as object) || {}), 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/generate-token.util.ts: -------------------------------------------------------------------------------- 1 | export const generateString = () => crypto.randomUUID(); 2 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auto-schema-file.util'; 2 | export * from './extend.util'; 3 | export * from './extract-metadata.util'; 4 | export * from './generate-token.util'; 5 | export * from './get-number-of-arguments.util'; 6 | export * from './normalize-route-path.util'; 7 | export * from './remove-temp.util'; 8 | export * from './stringify-without-quotes.util'; 9 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/is-pipe.util.ts: -------------------------------------------------------------------------------- 1 | import { PipeTransform, Type } from '@nestjs/common'; 2 | import { isFunction } from '@nestjs/common/utils/shared.utils'; 3 | 4 | export function isPipe( 5 | value: unknown, 6 | ): value is PipeTransform | Type { 7 | if (!value) { 8 | return false; 9 | } 10 | if (isFunction(value)) { 11 | return true; 12 | } 13 | 14 | return isFunction((value as PipeTransform).transform); 15 | } 16 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/normalize-resolver-args.ts: -------------------------------------------------------------------------------- 1 | import { isType } from 'graphql'; 2 | 3 | export function normalizeResolverArgs(args: any[]) { 4 | const newArgs = [...args]; 5 | // Reference resolver args don't have args argument 6 | const isReferenceResolver = newArgs.length === 3; 7 | // Resolve type args don't have args argument and the last argument is the parent object type 8 | const isResolveType = 9 | !isReferenceResolver && isType(newArgs[newArgs.length - 1]); 10 | 11 | // Add an undefined args argument 12 | if (isReferenceResolver || isResolveType) { 13 | newArgs.splice(1, 0, undefined); 14 | } 15 | return newArgs; 16 | } 17 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/normalize-route-path.util.ts: -------------------------------------------------------------------------------- 1 | function addStartingSlash(text: string) { 2 | if (!text) { 3 | return text; 4 | } 5 | return text[0] !== '/' ? '/' + text : text; 6 | } 7 | 8 | function stripEndingSlash(text: string) { 9 | if (!text) { 10 | return text; 11 | } 12 | return text[text.length - 1] === '/' && text.length > 1 13 | ? text.slice(0, text.length - 1) 14 | : text; 15 | } 16 | 17 | export function normalizeRoutePath(path: string) { 18 | path = addStartingSlash(path); 19 | return stripEndingSlash(path); 20 | } 21 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/remove-temp.util.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLSchema } from 'graphql'; 2 | 3 | /** 4 | * Removes "temp__" field from schema added 5 | * because of "merge-graphql-schemas" library issues. 6 | **/ 7 | export function removeTempField(schema: GraphQLSchema): GraphQLSchema { 8 | const queryTypeRef = schema.getQueryType(); 9 | if (!queryTypeRef) { 10 | return schema; 11 | } 12 | const fields = queryTypeRef.getFields(); 13 | if (!fields) { 14 | return schema; 15 | } 16 | delete fields['temp__']; 17 | return schema; 18 | } 19 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/scalar-types.utils.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLScalarType } from 'graphql'; 2 | 3 | function bindInstanceContext( 4 | instance: Partial, 5 | funcKey: keyof GraphQLScalarType, 6 | ) { 7 | return instance[funcKey] 8 | ? (instance[funcKey] as Function).bind(instance) 9 | : undefined; 10 | } 11 | 12 | export function createScalarType( 13 | name: string, 14 | instance: Partial, 15 | ) { 16 | return new GraphQLScalarType({ 17 | name, 18 | description: instance.description, 19 | parseValue: bindInstanceContext(instance, 'parseValue'), 20 | serialize: bindInstanceContext(instance, 'serialize'), 21 | parseLiteral: bindInstanceContext(instance, 'parseLiteral'), 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /packages/graphql/lib/utils/stringify-without-quotes.util.ts: -------------------------------------------------------------------------------- 1 | export function stringifyWithoutQuotes(obj: object, includeSpaces?: boolean) { 2 | let result = includeSpaces 3 | ? JSON.stringify(obj, null, 2) 4 | : JSON.stringify(obj); 5 | result = result 6 | .replace(/"([^"]+)":/g, '$1:') 7 | .replace(/(?({|,|:))/g, '$ '); 8 | 9 | if (!includeSpaces) { 10 | result = result.replace(/}/g, ' }'); 11 | } 12 | return result; 13 | } 14 | -------------------------------------------------------------------------------- /packages/graphql/plugin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const tslib_1 = require('tslib'); 4 | const plugin = require('./dist/plugin'); 5 | (0, tslib_1.__exportStar)(plugin, exports); 6 | 7 | /** Compatibility with ts-patch/ttypescript */ 8 | exports.default = (program, options) => plugin.before(options, program); 9 | -------------------------------------------------------------------------------- /packages/graphql/tests/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": [ 8 | "ts-jest", 9 | { "tsconfig": "/../tsconfig.spec.json", "isolatedModules": true } 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/cases/.gitignore: -------------------------------------------------------------------------------- 1 | actual 2 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/cases/es5-eager-imports/author.model.ts: -------------------------------------------------------------------------------- 1 | declare const ObjectType: any; 2 | 3 | @ObjectType() 4 | export class Author { 5 | name: string; 6 | email: string; 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/cases/es5-eager-imports/expected/author.model.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Author = void 0; 4 | let Author = exports.Author = class Author { 5 | static _GRAPHQL_METADATA_FACTORY() { 6 | return { name: { type: () => String }, email: { type: () => String } }; 7 | } 8 | }; 9 | exports.Author = Author = __decorate([ 10 | ObjectType() 11 | ], Author); 12 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/cases/es5-eager-imports/expected/post.model.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Post = void 0; 4 | const eager_import_0 = require("./author.model"); 5 | let Post = class Post { 6 | static _GRAPHQL_METADATA_FACTORY() { 7 | return { author: { type: () => require("./author.model").Author } }; 8 | } 9 | }; 10 | exports.Post = Post; 11 | exports.Post = Post = __decorate([ 12 | ObjectType() 13 | ], Post); 14 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/cases/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "experimentalDecorators": true, 6 | "sourceMap": true 7 | }, 8 | "include": ["**/*.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/fixtures/project/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '../../../../lib'; 3 | import { RecipesModule } from './recipes/recipes.module'; 4 | 5 | @Module({ 6 | imports: [ 7 | RecipesModule, 8 | GraphQLModule.forRoot({ 9 | driver: null, 10 | autoSchemaFile: 'schema.gql', 11 | }), 12 | ], 13 | }) 14 | export class AppModule {} 15 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/fixtures/project/common/scalars/date.scalar.ts: -------------------------------------------------------------------------------- 1 | import { Kind, ValueNode } from 'graphql'; 2 | import { Scalar } from '../../../../../../lib/decorators'; 3 | import { CustomScalar } from '../../../../../../lib/interfaces'; 4 | 5 | @Scalar('Date', (type) => Date) 6 | export class DateScalar implements CustomScalar { 7 | description = 'Date custom scalar type'; 8 | 9 | parseValue(value: number): Date { 10 | return new Date(value); // value from the client 11 | } 12 | 13 | serialize(value: Date): number { 14 | return value.getTime(); // value sent to the client 15 | } 16 | 17 | parseLiteral(ast: ValueNode): Date { 18 | if (ast.kind === Kind.INT) { 19 | return new Date(ast.value); 20 | } 21 | return null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/fixtures/project/recipes/dto/new-recipe.input.ts: -------------------------------------------------------------------------------- 1 | import { IsOptional, Length, MaxLength } from 'class-validator'; 2 | import { InputType } from '../../../../../../lib/decorators'; 3 | 4 | @InputType() 5 | export class NewRecipeInput { 6 | /** 7 | * The title of the recipe 8 | */ 9 | @MaxLength(30) 10 | title: string; 11 | 12 | @IsOptional() 13 | @Length(30, 255) 14 | description?: string; 15 | 16 | ingredients: string[]; 17 | } 18 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/fixtures/project/recipes/dto/non-exported.input.ts: -------------------------------------------------------------------------------- 1 | import { InputType } from '../../../../../../lib/decorators'; 2 | 3 | @InputType() 4 | class NonExportedInput { 5 | name: string; 6 | } 7 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/fixtures/project/recipes/dto/recipes.args.ts: -------------------------------------------------------------------------------- 1 | import { Max, Min } from 'class-validator'; 2 | import { ArgsType } from '../../../../../../lib/decorators'; 3 | 4 | @ArgsType() 5 | export class RecipesArgs { 6 | @Min(0) 7 | skip: number = 0; 8 | 9 | @Min(1) 10 | @Max(50) 11 | take: number = 25; 12 | } 13 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/fixtures/project/recipes/models/ingredient.model.ts: -------------------------------------------------------------------------------- 1 | import { ObjectType } from '../../../../../../lib/decorators'; 2 | 3 | /** 4 | * Ingredient model definition 5 | */ 6 | @ObjectType() 7 | export class Ingredient { 8 | id: string; 9 | 10 | name: string; 11 | } 12 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/fixtures/project/recipes/models/recipe.model.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '../../../../../../lib/decorators'; 2 | import { Ingredient } from './ingredient.model'; 3 | 4 | @ObjectType({ description: 'recipe ' }) 5 | export class Recipe { 6 | id: string; 7 | 8 | /** 9 | * The title of the recipe 10 | * @example Recipe title 11 | */ 12 | title: string; 13 | 14 | description?: string; 15 | 16 | /** 17 | * Creation date of the recipe 18 | */ 19 | @Field((type) => Date) 20 | creationDate: Date; 21 | 22 | ingredients: Ingredient[]; 23 | 24 | /** 25 | * Ingredients with field decorator 26 | */ 27 | @Field((type) => [Ingredient]) 28 | ingredientsWithFieldDecorator: Ingredient[]; 29 | 30 | primary: Ingredient; 31 | } 32 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/fixtures/project/recipes/recipes.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { DateScalar } from '../common/scalars/date.scalar'; 3 | import { RecipesResolver } from './recipes.resolver'; 4 | import { RecipesService } from './recipes.service'; 5 | 6 | @Module({ 7 | providers: [RecipesResolver, RecipesService, DateScalar], 8 | }) 9 | export class RecipesModule {} 10 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/fixtures/project/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "ES2021", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true 15 | }, 16 | "include": ["./**/*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/type-helpers/fixtures/base-type.fixture.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Extensions, Field, ObjectType } from '../../../../lib/decorators'; 2 | 3 | @ObjectType({ isAbstract: true }) 4 | export abstract class BaseType { 5 | @Field() 6 | @Directive('@upper') 7 | @Extensions({ extension: true }) 8 | id: string; 9 | 10 | @Field() 11 | createdAt: Date; 12 | 13 | @Field() 14 | updatedAt: Date; 15 | 16 | meta: string; 17 | } -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/type-helpers/fixtures/create-user-dto.fixture.ts: -------------------------------------------------------------------------------- 1 | import { Transform } from 'class-transformer'; 2 | import { IsBoolean, MinLength } from 'class-validator'; 3 | import { Directive, Extensions, Field, ObjectType } from '../../../../lib/decorators'; 4 | 5 | @ObjectType() 6 | export class CreateUserDto { 7 | @Transform((str) => str + '_transformed') 8 | @MinLength(10) 9 | @Field({ nullable: true }) 10 | @Directive('@upper') 11 | login: string; 12 | 13 | @Transform((str) => str + '_transformed') 14 | @MinLength(10) 15 | @Field() 16 | @Directive('@upper') 17 | @Extensions({ extension: true }) 18 | password: string; 19 | 20 | @Field({ name: 'id' }) 21 | @Extensions({ extension: true }) 22 | _id: string; 23 | 24 | @IsBoolean() 25 | active: boolean; 26 | } -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/type-helpers/fixtures/serialized-metadata.fixture.ts: -------------------------------------------------------------------------------- 1 | export const SERIALIZED_METADATA = { 2 | '@nestjs/graphql': { 3 | models: [ 4 | [ 5 | import('./base-type.fixture'), 6 | { 7 | BaseType: { 8 | meta: { 9 | type: () => String, 10 | }, 11 | }, 12 | }, 13 | ], 14 | [ 15 | import('./create-user-dto.fixture'), 16 | { 17 | CreateUserDto: { 18 | active: { 19 | type: () => Boolean, 20 | }, 21 | }, 22 | }, 23 | ], 24 | ], 25 | }, 26 | } -------------------------------------------------------------------------------- /packages/graphql/tests/plugin/type-helpers/type-helpers.test-utils.ts: -------------------------------------------------------------------------------- 1 | import { MetadataStorage } from 'class-validator'; 2 | 3 | export function getValidationMetadataByTarget(target: Function) { 4 | const classValidator: typeof import('class-validator') = require('class-validator'); 5 | const metadataStorage: MetadataStorage = (classValidator as any) 6 | .getMetadataStorage 7 | ? (classValidator as any).getMetadataStorage() 8 | : classValidator.getFromContainer(classValidator.MetadataStorage); 9 | 10 | const targetMetadata = metadataStorage.getTargetValidationMetadatas( 11 | target, 12 | null!, 13 | false, 14 | false, 15 | ); 16 | return targetMetadata; 17 | } 18 | -------------------------------------------------------------------------------- /packages/graphql/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "rootDir": "./lib", 6 | }, 7 | "exclude": ["node_modules", "dist", "tests/**/*", "*.spec.ts"], 8 | } 9 | -------------------------------------------------------------------------------- /packages/graphql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "types": ["node"], 5 | }, 6 | "files": [], 7 | "include": [], 8 | "references": [ 9 | { 10 | "path": "./tsconfig.build.json" 11 | }, 12 | { 13 | "path": "./tsconfig.spec.json" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/graphql/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "sourceMap": true, 5 | "outDir": "./dist/tests", 6 | "rootDir": ".", 7 | "types": ["jest", "node"] 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/lib/drivers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './mercurius-federation.driver'; 2 | export * from './mercurius-gateway.driver'; 3 | export * from './mercurius.driver'; 4 | -------------------------------------------------------------------------------- /packages/mercurius/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './drivers'; 2 | export * from './interfaces'; 3 | -------------------------------------------------------------------------------- /packages/mercurius/lib/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './mercurius-driver-config.interface'; 2 | export * from './mercurius-federation-driver-config.interface'; 3 | export * from './mercurius-gateway-driver-config.interface'; 4 | export * from './mercurius-plugin.interface'; 5 | -------------------------------------------------------------------------------- /packages/mercurius/lib/interfaces/mercurius-driver-config.interface.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GqlModuleAsyncOptions, 3 | GqlModuleOptions, 4 | GqlOptionsFactory, 5 | } from '@nestjs/graphql'; 6 | import { MercuriusOptions } from 'mercurius'; 7 | import { MercuriusHooks } from './mercurius-hook.interface'; 8 | import { MercuriusPlugins } from './mercurius-plugin.interface'; 9 | 10 | export type MercuriusDriverConfig = GqlModuleOptions & 11 | MercuriusOptions & 12 | MercuriusPlugins & 13 | MercuriusHooks; 14 | 15 | export type MercuriusDriverConfigFactory = 16 | GqlOptionsFactory; 17 | export type MercuriusDriverAsyncConfig = 18 | GqlModuleAsyncOptions; 19 | -------------------------------------------------------------------------------- /packages/mercurius/lib/interfaces/mercurius-federation-driver-config.interface.ts: -------------------------------------------------------------------------------- 1 | import { 2 | MercuriusDriverAsyncConfig, 3 | MercuriusDriverConfig, 4 | MercuriusDriverConfigFactory, 5 | } from './mercurius-driver-config.interface'; 6 | 7 | export type MercuriusFederationDriverConfig = MercuriusDriverConfig; 8 | export type MercuriusFederationDriverConfigFactory = 9 | MercuriusDriverConfigFactory; 10 | export type MercuriusFederationDriverAsyncConfig = MercuriusDriverAsyncConfig; 11 | -------------------------------------------------------------------------------- /packages/mercurius/lib/interfaces/mercurius-plugin.interface.ts: -------------------------------------------------------------------------------- 1 | import { 2 | FastifyPluginAsync, 3 | FastifyPluginCallback, 4 | FastifyPluginOptions, 5 | FastifyRegisterOptions, 6 | } from 'fastify'; 7 | 8 | /** 9 | * @publicApi 10 | */ 11 | export interface MercuriusPlugin< 12 | Options extends FastifyPluginOptions = unknown, 13 | > { 14 | plugin: 15 | | FastifyPluginCallback 16 | | FastifyPluginAsync 17 | | Promise<{ 18 | default: FastifyPluginCallback; 19 | }>; 20 | options?: FastifyRegisterOptions; 21 | } 22 | 23 | /** 24 | * @publicApi 25 | */ 26 | export interface MercuriusPlugins< 27 | Options extends FastifyPluginOptions = unknown, 28 | > { 29 | plugins?: MercuriusPlugin[]; 30 | } 31 | -------------------------------------------------------------------------------- /packages/mercurius/lib/utils/register-mercurius-plugin.util.ts: -------------------------------------------------------------------------------- 1 | import { FastifyInstance } from 'fastify'; 2 | import { MercuriusPlugin } from '../interfaces/mercurius-plugin.interface'; 3 | import { isArray, isNull, isUndefined } from './validation.util'; 4 | 5 | export async function registerMercuriusPlugin( 6 | app: FastifyInstance, 7 | plugins?: MercuriusPlugin[], 8 | ): Promise { 9 | if ( 10 | isUndefined(plugins) || 11 | isNull(plugins) || 12 | !isArray(plugins) || 13 | plugins.length === 0 14 | ) { 15 | return; 16 | } 17 | 18 | for (const plugin of plugins) { 19 | await app.register(plugin.plugin, plugin.options); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/mercurius/lib/utils/validation.util.ts: -------------------------------------------------------------------------------- 1 | export const isUndefined = (value: unknown): value is undefined => { 2 | return typeof value === 'undefined'; 3 | }; 4 | 5 | export const isNull = (value: unknown): value is null => value === null; 6 | 7 | export const isArray = (value: unknown): value is T[] => { 8 | return Array.isArray(value); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-duplicate-resolvers/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusDriverConfig } from '../../lib'; 4 | import { MercuriusDriver } from '../../lib/drivers'; 5 | import { ModuleAModule } from './module-a/module-a.module'; 6 | import { ModuleBModule } from './module-b/module-b.module'; 7 | import { QueryResolver } from './query.resolver'; 8 | 9 | @Module({ 10 | imports: [ 11 | GraphQLModule.forRoot({ 12 | driver: MercuriusDriver, 13 | autoSchemaFile: true, 14 | }), 15 | ModuleAModule, 16 | ModuleBModule, 17 | QueryResolver, 18 | ], 19 | controllers: [], 20 | providers: [], 21 | }) 22 | export class AppModule {} 23 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-duplicate-resolvers/module-a/module-a.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | 4 | @Module({ 5 | imports: [], 6 | controllers: [], 7 | providers: [UserResolver], 8 | }) 9 | export class ModuleAModule {} 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-duplicate-resolvers/module-a/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class UserResolver { 5 | @Mutation(() => String, { name: 'moduleALogin' }) 6 | login(@Args('code') code: string) { 7 | return code; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-duplicate-resolvers/module-b/module-b.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | 4 | @Module({ 5 | imports: [], 6 | controllers: [], 7 | providers: [UserResolver], 8 | }) 9 | export class ModuleBModule {} 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-duplicate-resolvers/module-b/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class UserResolver { 5 | @Mutation(() => String, { name: 'moduleBLogin' }) 6 | login(@Args('username') username: string) { 7 | return username; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-duplicate-resolvers/query.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class QueryResolver { 5 | @Query(() => Boolean, { name: '_' }) 6 | test() { 7 | return true; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/gateway/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './gateway.module'; 3 | import { 4 | FastifyAdapter, 5 | NestFastifyApplication, 6 | } from '@nestjs/platform-fastify'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create( 10 | AppModule, 11 | new FastifyAdapter(), 12 | ); 13 | await app.listen(3010); 14 | } 15 | bootstrap(); 16 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/posts-service/federation-posts.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { 4 | MercuriusFederationDriver, 5 | MercuriusFederationDriverConfig, 6 | } from '../../../lib'; 7 | import { PostModule } from './posts/post.module'; 8 | import { UserModule } from './users/user.module'; 9 | 10 | @Module({ 11 | imports: [ 12 | GraphQLModule.forRoot({ 13 | driver: MercuriusFederationDriver, 14 | autoSchemaFile: true, 15 | }), 16 | UserModule, 17 | PostModule, 18 | ], 19 | }) 20 | export class AppModule {} 21 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/posts-service/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './federation-posts.module'; 3 | import { 4 | FastifyAdapter, 5 | NestFastifyApplication, 6 | } from '@nestjs/platform-fastify'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create( 10 | AppModule, 11 | new FastifyAdapter(), 12 | ); 13 | await app.listen(3012); 14 | } 15 | bootstrap(); 16 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/posts-service/posts/post.entity.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Field, ID, Int, ObjectType } from '@nestjs/graphql'; 2 | 3 | @ObjectType() 4 | @Directive('@key(fields: "id")') 5 | export class Post { 6 | @Field((type) => ID) 7 | public id: number; 8 | 9 | @Field() 10 | public title: string; 11 | 12 | @Field((type) => Int) 13 | public authorId: number; 14 | 15 | constructor(post: Partial) { 16 | Object.assign(this, post); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/posts-service/posts/post.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PostService } from './post.service'; 3 | import { PostResolver } from './post.resolver'; 4 | 5 | @Module({ 6 | providers: [PostService, PostResolver], 7 | exports: [PostService], 8 | }) 9 | export class PostModule {} 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/posts-service/unions/search-result.union.ts: -------------------------------------------------------------------------------- 1 | import { createUnionType } from '@nestjs/graphql'; 2 | import { Post } from '../posts/post.entity'; 3 | import { User } from '../users/user.entity'; 4 | 5 | export const FederationSearchResultUnion = createUnionType({ 6 | name: 'FederationSearchResultUnion', 7 | description: 'Search result description', 8 | types: () => [Post, User], 9 | resolveType: (value) => { 10 | if ('posts' in value) { 11 | return User; 12 | } 13 | if ('title' in value) { 14 | return Post; 15 | } 16 | return undefined; 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/posts-service/users/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Field, ID, ObjectType } from '@nestjs/graphql'; 2 | import { Post } from '../posts/post.entity'; 3 | 4 | @ObjectType() 5 | @Directive('@extends') 6 | @Directive('@key(fields: "id")') 7 | export class User { 8 | @Field((type) => ID) 9 | @Directive('@external') 10 | public id: number; 11 | 12 | @Field((type) => [Post]) 13 | public posts: Post[]; 14 | 15 | constructor(user: Partial) { 16 | Object.assign(this, user); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/posts-service/users/user.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | import { PostModule } from '../posts/post.module'; 4 | 5 | @Module({ 6 | providers: [UserResolver], 7 | imports: [PostModule], 8 | }) 9 | export class UserModule {} 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/posts-service/users/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Parent, ResolveField, Resolver } from '@nestjs/graphql'; 2 | import { PostService } from '../posts/post.service'; 3 | import { User } from './user.entity'; 4 | 5 | @Resolver((of) => User) 6 | export class UserResolver { 7 | constructor(private readonly postService: PostService) {} 8 | 9 | @ResolveField() 10 | public posts(@Parent() user: User) { 11 | return this.postService.forAuthor(user.id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/recipes-service/federation-recipes.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusFederationDriver } from '../../../lib'; 4 | import { RecipeModule } from './recipes/recipe.module'; 5 | 6 | @Module({ 7 | imports: [ 8 | GraphQLModule.forRoot({ 9 | driver: MercuriusFederationDriver, 10 | autoSchemaFile: true, 11 | }), 12 | RecipeModule, 13 | ], 14 | }) 15 | export class AppModule {} 16 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/recipes-service/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './federation-recipes.module'; 3 | import { 4 | FastifyAdapter, 5 | NestFastifyApplication, 6 | } from '@nestjs/platform-fastify'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create( 10 | AppModule, 11 | new FastifyAdapter(), 12 | ); 13 | await app.listen(3011); 14 | } 15 | bootstrap(); 16 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/recipes-service/recipes/irecipe.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Query, Resolver } from '@nestjs/graphql'; 2 | import { IRecipe } from './recipe'; 3 | 4 | @Resolver((of) => IRecipe) 5 | export class IRecipeResolver { 6 | @Query((returns) => IRecipe) 7 | public recipe() { 8 | return { id: '1', title: 'Recipe', description: 'Interface description' }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/recipes-service/recipes/recipe.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { IRecipeResolver } from './irecipe.resolver'; 3 | 4 | @Module({ 5 | providers: [IRecipeResolver], 6 | }) 7 | export class RecipeModule {} 8 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/recipes-service/recipes/recipe.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Directive, 3 | Field, 4 | ID, 5 | InterfaceType, 6 | ObjectType, 7 | } from '@nestjs/graphql'; 8 | 9 | @InterfaceType() 10 | export abstract class Base { 11 | @Field((type) => ID) 12 | id: string; 13 | } 14 | 15 | @InterfaceType({ 16 | resolveType: (value) => { 17 | return Recipe; 18 | }, 19 | }) 20 | export abstract class IRecipe extends Base { 21 | @Field() 22 | title: string; 23 | 24 | @Field() 25 | @Directive('@external') 26 | externalField: string; 27 | } 28 | 29 | @ObjectType({ implements: IRecipe }) 30 | export class Recipe extends IRecipe { 31 | @Field() 32 | description: string; 33 | } 34 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/users-service/federation-users.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { 4 | MercuriusFederationDriver, 5 | MercuriusFederationDriverConfig, 6 | } from '../../../lib'; 7 | import { UserModule } from './users/user.module'; 8 | 9 | @Module({ 10 | imports: [ 11 | GraphQLModule.forRoot({ 12 | driver: MercuriusFederationDriver, 13 | autoSchemaFile: true, 14 | }), 15 | UserModule, 16 | ], 17 | }) 18 | export class AppModule {} 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/users-service/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './federation-users.module'; 3 | import { 4 | FastifyAdapter, 5 | NestFastifyApplication, 6 | } from '@nestjs/platform-fastify'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create( 10 | AppModule, 11 | new FastifyAdapter(), 12 | ); 13 | await app.listen(3013); 14 | } 15 | bootstrap(); 16 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/users-service/users/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Field, ID, ObjectType } from '@nestjs/graphql'; 2 | 3 | @ObjectType() 4 | @Directive('@key(fields: "id")') 5 | export class User { 6 | @Field((type) => ID) 7 | public id: number; 8 | 9 | @Field() 10 | public name: string; 11 | 12 | constructor(user: Partial) { 13 | Object.assign(this, user); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/users-service/users/user.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | import { UserService } from './user.service'; 4 | 5 | @Module({ 6 | providers: [UserResolver, UserService], 7 | }) 8 | export class UserModule {} 9 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/users-service/users/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Resolver, Query, Args, ResolveReference } from '@nestjs/graphql'; 2 | import { User } from './user.entity'; 3 | import { UserService } from './user.service'; 4 | 5 | @Resolver((of) => User) 6 | export class UserResolver { 7 | constructor(private readonly userService: UserService) {} 8 | 9 | @Query(() => User, { nullable: true }) 10 | findUser(@Args('id') id: number) { 11 | return this.userService.findOne(id); 12 | } 13 | 14 | @ResolveReference() 15 | public resolveRef(reference: any) { 16 | return this.userService.findOne(reference.id); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first-federation/users-service/users/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { User } from './user.entity'; 3 | 4 | const data = [ 5 | { 6 | id: 1, 7 | name: 'foo', 8 | }, 9 | { 10 | id: 2, 11 | name: 'bar', 12 | }, 13 | ]; 14 | 15 | @Injectable() 16 | export class UserService { 17 | public findOne(id: number) { 18 | const post = data.find((p) => p.id === id); 19 | if (post) { 20 | return new User(post); 21 | } 22 | return null; 23 | } 24 | 25 | public all() { 26 | return data.map((p) => new User(p)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusDriverConfig } from '../../lib'; 4 | import { MercuriusDriver } from '../../lib/drivers'; 5 | import { DirectionsModule } from './directions/directions.module'; 6 | import { RecipesModule } from './recipes/recipes.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | RecipesModule, 11 | DirectionsModule, 12 | GraphQLModule.forRoot({ 13 | driver: MercuriusDriver, 14 | autoSchemaFile: true, 15 | }), 16 | ], 17 | }) 18 | export class ApplicationModule {} 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/cats/cats.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Query, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class CatsResolver { 5 | @Query((returns) => String) 6 | getAnimalName(): string { 7 | return 'cat'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/common/filters/unauthorized.filter.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentsHost, Catch, UnauthorizedException } from '@nestjs/common'; 2 | import { GqlExceptionFilter } from '@nestjs/graphql'; 3 | 4 | @Catch(UnauthorizedException) 5 | export class UnauthorizedFilter implements GqlExceptionFilter { 6 | catch(exception: any, host: ArgumentsHost) { 7 | exception.message = 'Unauthorized error'; 8 | return exception; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/common/guards/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CanActivate, 3 | ExecutionContext, 4 | Injectable, 5 | UnauthorizedException, 6 | } from '@nestjs/common'; 7 | import { GqlExecutionContext } from '@nestjs/graphql'; 8 | 9 | @Injectable() 10 | export class AuthGuard implements CanActivate { 11 | async canActivate(context: ExecutionContext): Promise { 12 | const gqlContext = GqlExecutionContext.create(context); 13 | if (gqlContext) { 14 | throw new UnauthorizedException(); 15 | } 16 | return true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/common/scalars/date.scalar.ts: -------------------------------------------------------------------------------- 1 | import { Scalar } from '@nestjs/graphql'; 2 | import { Kind, ValueNode } from 'graphql'; 3 | 4 | @Scalar('Date', (type) => Date) 5 | export class DateScalar { 6 | description = 'Date custom scalar type'; 7 | 8 | parseValue(value: any) { 9 | return new Date(value); // value from the client 10 | } 11 | 12 | serialize(value: any) { 13 | return value.getTime(); // value sent to the client 14 | } 15 | 16 | parseLiteral(ast: ValueNode) { 17 | if (ast.kind === Kind.INT) { 18 | return parseInt(ast.value, 10); // ast value is always in string format 19 | } 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/directions/directions.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { DirectionsResolver } from './directions.resolver'; 3 | 4 | @Module({ 5 | providers: [DirectionsResolver], 6 | }) 7 | export class DirectionsModule {} 8 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/directions/directions.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Query, Resolver } from '@nestjs/graphql'; 2 | import { Direction } from '../enums/direction.enum'; 3 | 4 | @Resolver() 5 | export class DirectionsResolver { 6 | @Query((returns) => Direction) 7 | move( 8 | @Args({ name: 'direction', type: () => Direction }) 9 | direction: Direction, 10 | ): Direction { 11 | return direction; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/enums/direction.enum.ts: -------------------------------------------------------------------------------- 1 | import { registerEnumType } from '@nestjs/graphql'; 2 | 3 | export enum Direction { 4 | Up = 'UP', 5 | Down = 'DOWN', 6 | Left = 'LEFT', 7 | Right = 'RIGHT', 8 | Sideways = 'SIDEWAYS', 9 | } 10 | 11 | registerEnumType(Direction, { 12 | name: 'Direction', // this one is mandatory 13 | description: 'The basic directions', // this one is optional 14 | valuesMap: { 15 | Sideways: { 16 | deprecationReason: 'Replaced with Left or Right', 17 | }, 18 | Up: { 19 | description: 'The primary direction', 20 | }, 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/main.ts: -------------------------------------------------------------------------------- 1 | import { ValidationPipe } from '@nestjs/common'; 2 | import { NestFactory } from '@nestjs/core'; 3 | import { FastifyAdapter } from '@nestjs/platform-fastify'; 4 | import mercurius from 'mercurius'; 5 | import { ApplicationModule } from './app.module'; 6 | 7 | async function bootstrap() { 8 | const app = await NestFactory.create(ApplicationModule, new FastifyAdapter()); 9 | app.useGlobalPipes( 10 | new ValidationPipe({ 11 | exceptionFactory: (errors) => 12 | new mercurius.ErrorWithProps('Validation error', { errors }, 200), 13 | }), 14 | ); 15 | await app.listen(3010); 16 | } 17 | bootstrap(); 18 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/other/abstract.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Query, Resolver } from '@nestjs/graphql'; 2 | import { RecipesArgs } from '../recipes/dto/recipes.args'; 3 | import { Recipe } from '../recipes/models/recipe'; 4 | 5 | @Resolver(() => Recipe, { isAbstract: true }) 6 | export class AbstractResolver { 7 | @Query((returns) => [Recipe]) 8 | abstractRecipes(@Args() recipesArgs: RecipesArgs): Recipe[] { 9 | return []; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/other/sample-orphaned.type.ts: -------------------------------------------------------------------------------- 1 | import { Field, ID, ObjectType } from '@nestjs/graphql'; 2 | 3 | @ObjectType({ description: 'orphaned type' }) 4 | export class SampleOrphanedType { 5 | @Field((type) => ID) 6 | id: string; 7 | 8 | @Field() 9 | title: string; 10 | 11 | @Field({ nullable: true }) 12 | description?: string; 13 | 14 | @Field() 15 | creationDate: Date; 16 | 17 | @Field() 18 | get averageRating(): number { 19 | return 0.5; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/recipes/dto/filter-recipes-count.args.ts: -------------------------------------------------------------------------------- 1 | import { ArgsType, Field } from '@nestjs/graphql'; 2 | @ArgsType() 3 | export class FilterRecipesCountArgs { 4 | @Field({ nullable: true }) 5 | type?: string; 6 | 7 | @Field({ nullable: true }) 8 | status?: string; 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/recipes/dto/new-recipe.input.ts: -------------------------------------------------------------------------------- 1 | import { Field, InputType } from '@nestjs/graphql'; 2 | import { Type } from 'class-transformer'; 3 | import { Length, MaxLength } from 'class-validator'; 4 | 5 | @InputType({ description: 'new recipe input' }) 6 | export class NewRecipeInput { 7 | @Field({ description: 'recipe title' }) 8 | @MaxLength(30) 9 | title: string; 10 | 11 | @Field({ nullable: true }) 12 | @Length(30, 255) 13 | description?: string; 14 | 15 | @Type(() => String) 16 | @Field((type) => [String]) 17 | ingredients: string[]; 18 | } 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/recipes/dto/recipes.args.ts: -------------------------------------------------------------------------------- 1 | import { ArgsType, Field, Int } from '@nestjs/graphql'; 2 | import { Max, Min } from 'class-validator'; 3 | @ArgsType() 4 | export class RecipesArgs { 5 | @Field((type) => Int, { description: 'number of items to skip' }) 6 | @Min(0) 7 | skip: number = 0; 8 | 9 | @Field((type) => Int) 10 | @Min(1) 11 | @Max(50) 12 | take: number = 25; 13 | } 14 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/recipes/irecipes.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, ResolveField, Resolver } from '@nestjs/graphql'; 2 | import { IRecipe } from './models/recipe'; 3 | 4 | @Resolver((of) => IRecipe) 5 | export class IRecipesResolver { 6 | @ResolveField('interfaceResolver', () => Boolean) 7 | interfaceResolver( 8 | @Args('arg', { type: () => Number, nullable: true }) arg: number, 9 | ) { 10 | return true; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/recipes/models/category.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '@nestjs/graphql'; 2 | @ObjectType() 3 | export class Category { 4 | @Field((type) => String) 5 | name: string; 6 | 7 | @Field((type) => String, { defaultValue: 'default value' }) 8 | description: string; 9 | 10 | @Field((type) => [String], { defaultValue: [] }) 11 | tags: string[]; 12 | 13 | constructor(category: Partial) { 14 | Object.assign(this, category); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/recipes/models/ingredient.ts: -------------------------------------------------------------------------------- 1 | import { Field, ID, ObjectType } from '@nestjs/graphql'; 2 | @ObjectType() 3 | export class Ingredient { 4 | @Field((type) => ID) 5 | id: string; 6 | 7 | @Field({ 8 | defaultValue: 'default', 9 | deprecationReason: 'is deprecated', 10 | description: 'ingredient name', 11 | nullable: true, 12 | }) 13 | name: string; 14 | 15 | constructor(ingredient: Partial) { 16 | Object.assign(this, ingredient); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/recipes/recipes.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { APP_FILTER } from '@nestjs/core'; 3 | import { UnauthorizedFilter } from '../common/filters/unauthorized.filter'; 4 | import { DateScalar } from '../common/scalars/date.scalar'; 5 | import { IRecipesResolver } from './irecipes.resolver'; 6 | import { RecipesResolver } from './recipes.resolver'; 7 | import { RecipesService } from './recipes.service'; 8 | 9 | @Module({ 10 | providers: [ 11 | RecipesResolver, 12 | IRecipesResolver, 13 | RecipesService, 14 | DateScalar, 15 | { 16 | provide: APP_FILTER, 17 | useClass: UnauthorizedFilter, 18 | }, 19 | ], 20 | }) 21 | export class RecipesModule {} 22 | -------------------------------------------------------------------------------- /packages/mercurius/tests/code-first/recipes/unions/search-result.union.ts: -------------------------------------------------------------------------------- 1 | import { createUnionType } from '@nestjs/graphql'; 2 | import { Ingredient } from '../models/ingredient'; 3 | import { Recipe } from '../models/recipe'; 4 | 5 | export const SearchResultUnion = createUnionType({ 6 | name: 'SearchResultUnion', 7 | description: 'Search result description', 8 | types: () => [Ingredient, Recipe], 9 | resolveType: (value) => { 10 | if ('name' in value) { 11 | return Ingredient; 12 | } 13 | if ('title' in value) { 14 | return Recipe; 15 | } 16 | return undefined; 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/duplicate-resolvers/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { MercuriusDriverConfig } from '../../lib'; 5 | import { MercuriusDriver } from '../../lib/drivers'; 6 | import { ModuleAModule } from './module-a/module-a.module'; 7 | import { ModuleBModule } from './module-b/module-b.module'; 8 | 9 | @Module({ 10 | imports: [ 11 | GraphQLModule.forRoot({ 12 | driver: MercuriusDriver, 13 | typePaths: [join(__dirname, '*.graphql')], 14 | }), 15 | ModuleAModule, 16 | ModuleBModule, 17 | ], 18 | controllers: [], 19 | providers: [], 20 | }) 21 | export class AppModule {} 22 | -------------------------------------------------------------------------------- /packages/mercurius/tests/duplicate-resolvers/duplicate-resolver.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | _: Boolean 3 | } 4 | 5 | type Mutation { 6 | moduleALogin(code: String): String 7 | moduleBLogin(username: String): String 8 | } 9 | -------------------------------------------------------------------------------- /packages/mercurius/tests/duplicate-resolvers/module-a/module-a.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | 4 | @Module({ 5 | imports: [], 6 | controllers: [], 7 | providers: [UserResolver], 8 | }) 9 | export class ModuleAModule {} 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/duplicate-resolvers/module-a/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class UserResolver { 5 | @Mutation('moduleALogin') 6 | login(@Args('code') code: string) { 7 | return code; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/duplicate-resolvers/module-b/module-b.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserResolver } from './user.resolver'; 3 | 4 | @Module({ 5 | imports: [], 6 | controllers: [], 7 | providers: [UserResolver], 8 | }) 9 | export class ModuleBModule {} 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/duplicate-resolvers/module-b/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class UserResolver { 5 | @Mutation('moduleBLogin') 6 | login(@Args('username') username: string) { 7 | return username; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/gateway/config/config.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigService } from './config.service'; 3 | 4 | @Module({ 5 | providers: [ConfigService], 6 | exports: [ConfigService], 7 | }) 8 | export class ConfigModule {} 9 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/gateway/config/config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { 3 | MercuriusGatewayDriverConfig, 4 | MercuriusGatewayDriverConfigFactory, 5 | } from '../../../../lib'; 6 | 7 | @Injectable() 8 | export class ConfigService implements MercuriusGatewayDriverConfigFactory { 9 | public createGqlOptions(): MercuriusGatewayDriverConfig { 10 | return { 11 | gateway: { 12 | services: [ 13 | { name: 'users', url: 'http://localhost:3011/graphql' }, 14 | { name: 'posts', url: 'http://localhost:3012/graphql' }, 15 | ], 16 | }, 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/gateway/gateway-async-class.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusDriverConfig } from '../../../lib'; 4 | import { MercuriusGatewayDriver } from '../../../lib/drivers'; 5 | import { ConfigModule } from './config/config.module'; 6 | import { ConfigService } from './config/config.service'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: MercuriusGatewayDriver, 12 | useClass: ConfigService, 13 | imports: [ConfigModule], 14 | inject: [ConfigService], 15 | }), 16 | ], 17 | }) 18 | export class AppModule {} 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/gateway/gateway-async-existing.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusDriverConfig } from '../../../lib'; 4 | import { MercuriusGatewayDriver } from '../../../lib/drivers'; 5 | import { ConfigModule } from './config/config.module'; 6 | import { ConfigService } from './config/config.service'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: MercuriusGatewayDriver, 12 | useExisting: ConfigService, 13 | imports: [ConfigModule], 14 | inject: [ConfigService], 15 | }), 16 | ], 17 | }) 18 | export class AppModule {} 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/gateway/gateway-async.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusGatewayDriver } from '../../../lib/drivers'; 4 | import { MercuriusDriverConfig } from '../../../lib/interfaces'; 5 | import { ConfigModule } from './config/config.module'; 6 | import { ConfigService } from './config/config.service'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: MercuriusGatewayDriver, 12 | useFactory: async (configService: ConfigService) => ({ 13 | ...configService.createGqlOptions(), 14 | }), 15 | imports: [ConfigModule], 16 | inject: [ConfigService], 17 | }), 18 | ], 19 | }) 20 | export class AppModule {} 21 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/gateway/gateway.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusGatewayDriver } from '../../../lib/drivers'; 4 | 5 | @Module({ 6 | imports: [ 7 | GraphQLModule.forRoot({ 8 | driver: MercuriusGatewayDriver, 9 | gateway: { 10 | services: [ 11 | { name: 'users', url: 'http://localhost:3011/graphql' }, 12 | { name: 'posts', url: 'http://localhost:3012/graphql' }, 13 | ], 14 | }, 15 | }), 16 | ], 17 | }) 18 | export class AppModule {} 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/posts-service/federation-posts.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { 5 | MercuriusFederationDriver, 6 | MercuriusFederationDriverConfig, 7 | } from '../../../lib'; 8 | import { PostsModule } from './posts/posts.module'; 9 | import { upperDirectiveTransformer } from './posts/upper.directive'; 10 | 11 | @Module({ 12 | imports: [ 13 | GraphQLModule.forRoot({ 14 | driver: MercuriusFederationDriver, 15 | typePaths: [join(__dirname, '**/*.graphql')], 16 | transformSchema: (schema) => upperDirectiveTransformer(schema, 'upper'), 17 | }), 18 | PostsModule, 19 | ], 20 | }) 21 | export class AppModule {} 22 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/posts-service/posts/post-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum PostType { 2 | IMAGE = 'IMAGE', 3 | TEXT = 'TEXT', 4 | } 5 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/posts-service/posts/posts.interfaces.ts: -------------------------------------------------------------------------------- 1 | import { PostType } from './post-type.enum'; 2 | 3 | export interface Post { 4 | id: string; 5 | title: string; 6 | body: string; 7 | userId: string; 8 | publishDate: Date; 9 | type: PostType; 10 | } 11 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/posts-service/posts/posts.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PostsResolvers } from './posts.resolvers'; 3 | import { UsersResolvers } from './users.resolvers'; 4 | import { PostsService } from './posts.service'; 5 | import { DateScalar } from './date.scalar'; 6 | 7 | @Module({ 8 | providers: [PostsResolvers, PostsService, UsersResolvers, DateScalar], 9 | }) 10 | export class PostsModule {} 11 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/posts-service/posts/posts.types.graphql: -------------------------------------------------------------------------------- 1 | directive @upper on FIELD_DEFINITION 2 | 3 | scalar Date 4 | 5 | enum PostType { 6 | TEXT 7 | IMAGE 8 | } 9 | 10 | type Post @key(fields: "id") { 11 | id: ID! 12 | title: String! 13 | body: String! 14 | user: User 15 | publishDate: Date 16 | type: PostType 17 | } 18 | 19 | extend type User @key(fields: "id") { 20 | id: ID! @external 21 | posts: [Post] 22 | } 23 | 24 | extend type Query { 25 | getPosts(type: PostType): [Post] 26 | } 27 | 28 | extend type Mutation { 29 | publishPost(id: ID!, publishDate: Date!): Post 30 | } 31 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/posts-service/posts/users.resolvers.ts: -------------------------------------------------------------------------------- 1 | import { ResolveField, Resolver } from '@nestjs/graphql'; 2 | import { PostsService } from './posts.service'; 3 | @Resolver('User') 4 | export class UsersResolvers { 5 | constructor(private readonly postsService: PostsService) {} 6 | 7 | @ResolveField('posts') 8 | getPosts(reference: any) { 9 | return this.postsService.findByUserId(reference.id); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/config/config.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigService } from './config.service'; 3 | 4 | @Module({ 5 | providers: [ConfigService], 6 | exports: [ConfigService], 7 | }) 8 | export class ConfigModule {} 9 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/config/config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { join } from 'path'; 3 | import { 4 | MercuriusDriverConfigFactory, 5 | MercuriusFederationDriverConfig, 6 | } from '../../../../lib'; 7 | 8 | @Injectable() 9 | export class ConfigService implements MercuriusDriverConfigFactory { 10 | public createGqlOptions(): Partial { 11 | return { 12 | typePaths: [join(__dirname, '../**/*.graphql')], 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/federation-users.async-class.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusFederationDriver } from '../../../lib'; 4 | import { ConfigModule } from './config/config.module'; 5 | import { ConfigService } from './config/config.service'; 6 | import { UsersModule } from './users/users.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: MercuriusFederationDriver, 12 | useClass: ConfigService, 13 | imports: [ConfigModule], 14 | inject: [ConfigService], 15 | }), 16 | UsersModule, 17 | ], 18 | }) 19 | export class AppModule {} 20 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/federation-users.async-existing.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusFederationDriver } from '../../../lib/drivers'; 4 | import { ConfigModule } from './config/config.module'; 5 | import { ConfigService } from './config/config.service'; 6 | import { UsersModule } from './users/users.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: MercuriusFederationDriver, 12 | useExisting: ConfigService, 13 | imports: [ConfigModule], 14 | inject: [ConfigService], 15 | }), 16 | UsersModule, 17 | ], 18 | }) 19 | export class AppModule {} 20 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/federation-users.async.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusFederationDriver } from '../../../lib/drivers'; 4 | import { ConfigModule } from './config/config.module'; 5 | import { ConfigService } from './config/config.service'; 6 | import { UsersModule } from './users/users.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | GraphQLModule.forRootAsync({ 11 | driver: MercuriusFederationDriver, 12 | useFactory: async (configService: ConfigService) => ({ 13 | ...configService.createGqlOptions(), 14 | }), 15 | imports: [ConfigModule], 16 | inject: [ConfigService], 17 | }), 18 | UsersModule, 19 | ], 20 | }) 21 | export class AppModule {} 22 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/federation-users.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { 5 | MercuriusFederationDriver, 6 | MercuriusFederationDriverConfig, 7 | } from '../../../lib'; 8 | import { UsersModule } from './users/users.module'; 9 | 10 | @Module({ 11 | imports: [ 12 | GraphQLModule.forRoot({ 13 | driver: MercuriusFederationDriver, 14 | typePaths: [join(__dirname, '**/*.graphql')], 15 | }), 16 | UsersModule, 17 | ], 18 | }) 19 | export class AppModule {} 20 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/users/users.interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | id: string; 3 | name: string; 4 | } 5 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/users/users.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UsersResolvers } from './users.resolvers'; 3 | import { UsersService } from './users.service'; 4 | 5 | @Module({ 6 | providers: [UsersResolvers, UsersService], 7 | }) 8 | export class UsersModule {} 9 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/users/users.resolvers.ts: -------------------------------------------------------------------------------- 1 | import { Args, Query, Resolver, ResolveReference } from '@nestjs/graphql'; 2 | import { UsersService } from './users.service'; 3 | @Resolver('User') 4 | export class UsersResolvers { 5 | constructor(private readonly usersService: UsersService) {} 6 | 7 | @Query() 8 | getUser(@Args('id') id: string) { 9 | return this.usersService.findById(id); 10 | } 11 | 12 | @ResolveReference() 13 | resolveReference(reference: { __typename: string; id: string }) { 14 | return this.usersService.findById(reference.id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/users/users.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { User } from './users.interfaces'; 3 | 4 | @Injectable() 5 | export class UsersService { 6 | private readonly users: User[] = [ 7 | { 8 | id: '5', 9 | name: 'GraphQL', 10 | }, 11 | ]; 12 | 13 | findById(id: string) { 14 | return Promise.resolve(this.users.find((p) => p.id === id)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql-federation/users-service/users/users.types.graphql: -------------------------------------------------------------------------------- 1 | type User @key(fields: "id") { 2 | id: ID! 3 | name: String! 4 | } 5 | 6 | extend type Query { 7 | getUser(id: ID!): User 8 | } -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { MercuriusDriverConfig } from '../../lib'; 5 | import { MercuriusDriver } from '../../lib/drivers'; 6 | import { CatsModule } from './cats/cats.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRoot({ 12 | driver: MercuriusDriver, 13 | typePaths: [join(__dirname, '**', '*.graphql')], 14 | }), 15 | ], 16 | }) 17 | export class ApplicationModule {} 18 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/async-options-existing.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusDriverConfig } from '../../lib'; 4 | import { MercuriusDriver } from '../../lib/drivers'; 5 | import { CatsModule } from './cats/cats.module'; 6 | import { ConfigModule } from './config.module'; 7 | import { ConfigService } from './config.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | CatsModule, 12 | GraphQLModule.forRootAsync({ 13 | driver: MercuriusDriver, 14 | imports: [ConfigModule], 15 | useExisting: ConfigService, 16 | }), 17 | ], 18 | }) 19 | export class AsyncExistingApplicationModule {} 20 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/async-options.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { MercuriusDriverConfig } from '../../lib'; 5 | import { MercuriusDriver } from '../../lib/drivers'; 6 | import { CatsModule } from './cats/cats.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRootAsync({ 12 | driver: MercuriusDriver, 13 | useFactory: async () => ({ 14 | typePaths: [join(__dirname, '**', '*.graphql')], 15 | }), 16 | }), 17 | ], 18 | }) 19 | export class AsyncApplicationModule {} 20 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/cats/cats-request-scoped.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Scope } from '@nestjs/common'; 2 | import { Cat } from './interfaces/cat.interface'; 3 | 4 | @Injectable({ scope: Scope.REQUEST }) 5 | export class CatsRequestScopedService { 6 | static COUNTER = 0; 7 | private readonly cats: Cat[] = [{ id: 1, name: 'Cat', age: 5 }]; 8 | 9 | constructor() { 10 | CatsRequestScopedService.COUNTER++; 11 | } 12 | 13 | create(cat: Cat): Cat { 14 | this.cats.push(cat); 15 | return cat; 16 | } 17 | 18 | findAll(): Cat[] { 19 | return this.cats; 20 | } 21 | 22 | findOneById(id: number): Cat { 23 | return this.cats.find((cat) => cat.id === id); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/cats/cats.guard.ts: -------------------------------------------------------------------------------- 1 | import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; 2 | import { GqlExecutionContext } from '@nestjs/graphql'; 3 | 4 | @Injectable() 5 | export class CatsGuard implements CanActivate { 6 | canActivate(context: ExecutionContext): boolean { 7 | const ctx = GqlExecutionContext.create(context); 8 | return true; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/cats/cats.module.ts: -------------------------------------------------------------------------------- 1 | import { DynamicModule, Module, Scope } from '@nestjs/common'; 2 | import { CatsRequestScopedService } from './cats-request-scoped.service'; 3 | import { CatsResolvers } from './cats.resolvers'; 4 | import { CatsService } from './cats.service'; 5 | 6 | @Module({ 7 | providers: [CatsService, CatsResolvers], 8 | }) 9 | export class CatsModule { 10 | static enableRequestScope(): DynamicModule { 11 | return { 12 | module: CatsModule, 13 | providers: [ 14 | { 15 | provide: CatsService, 16 | useClass: CatsRequestScopedService, 17 | scope: Scope.REQUEST, 18 | }, 19 | ], 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/cats/cats.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { Cat } from './interfaces/cat.interface'; 3 | 4 | @Injectable() 5 | export class CatsService { 6 | static COUNTER = 0; 7 | private readonly cats: Cat[] = [{ id: 1, name: 'Cat', age: 5 }]; 8 | 9 | constructor() { 10 | CatsService.COUNTER++; 11 | } 12 | 13 | create(cat: Cat): Cat { 14 | this.cats.push(cat); 15 | return cat; 16 | } 17 | 18 | findAll(): Cat[] { 19 | return this.cats; 20 | } 21 | 22 | findOneById(id: number): Cat { 23 | return this.cats.find((cat) => cat.id === id); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/cats/cats.types.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | getCats: [Cat] 3 | cat(id: ID!): Cat 4 | } 5 | 6 | type Mutation { 7 | createCat(name: String): Cat 8 | } 9 | 10 | type Subscription { 11 | catCreated: Cat 12 | } 13 | 14 | type Cat { 15 | id: Int 16 | name: String 17 | age: Int 18 | color: String 19 | weight: Int 20 | } 21 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/cats/interfaces/cat.interface.ts: -------------------------------------------------------------------------------- 1 | export interface Cat { 2 | readonly id: number; 3 | readonly name: string; 4 | readonly age: number; 5 | } 6 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/common/scalars/date.scalar.ts: -------------------------------------------------------------------------------- 1 | import { Kind } from 'graphql'; 2 | import { Scalar } from '../../../../lib'; 3 | 4 | @Scalar('Date') 5 | export class DateScalar { 6 | description = 'Date custom scalar type'; 7 | 8 | parseValue(value) { 9 | return new Date(value); // value from the client 10 | } 11 | 12 | serialize(value) { 13 | return value.getTime(); // value sent to the client 14 | } 15 | 16 | parseLiteral(ast) { 17 | if (ast.kind === Kind.INT) { 18 | return parseInt(ast.value, 10); // ast value is always in string format 19 | } 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/config.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigService } from './config.service'; 3 | 4 | @Module({ 5 | providers: [ConfigService], 6 | exports: [ConfigService], 7 | }) 8 | export class ConfigModule {} 9 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { join } from 'path'; 3 | import { 4 | MercuriusDriverConfig, 5 | MercuriusDriverConfigFactory, 6 | } from '../../lib/interfaces'; 7 | 8 | @Injectable() 9 | export class ConfigService implements MercuriusDriverConfigFactory { 10 | createGqlOptions(): MercuriusDriverConfig { 11 | return { 12 | typePaths: [join(__dirname, '**', '*.graphql')], 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/global-prefix-async-options.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { MercuriusDriverConfig } from '../../lib'; 5 | import { MercuriusDriver } from '../../lib/drivers'; 6 | import { CatsModule } from './cats/cats.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRootAsync({ 12 | driver: MercuriusDriver, 13 | useFactory: async () => ({ 14 | typePaths: [join(__dirname, '**', '*.graphql')], 15 | useGlobalPrefix: true, 16 | }), 17 | }), 18 | ], 19 | }) 20 | export class GlobalPrefixAsyncOptionsModule {} 21 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/global-prefix.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { MercuriusDriverConfig } from '../../lib'; 5 | import { MercuriusDriver } from '../../lib/drivers'; 6 | import { CatsModule } from './cats/cats.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRoot({ 12 | driver: MercuriusDriver, 13 | typePaths: [join(__dirname, '**', '*.graphql')], 14 | useGlobalPrefix: true, 15 | }), 16 | ], 17 | }) 18 | export class GlobalPrefixModule {} 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/hello/cats.types.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | getCats: [Cat] 3 | cat(id: ID!): Cat 4 | } 5 | 6 | type Mutation { 7 | createCat(name: String): Cat 8 | } 9 | 10 | type Subscription { 11 | catCreated: Cat 12 | } 13 | 14 | type Cat { 15 | id: Int 16 | name: String 17 | age: Int 18 | color: String 19 | weight: Int 20 | } 21 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/hello/dto/test.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString, IsNotEmpty, IsNumber } from 'class-validator'; 2 | 3 | export class TestDto { 4 | @IsString() 5 | @IsNotEmpty() 6 | string: string; 7 | 8 | @IsNumber() 9 | number: number; 10 | } 11 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/hello/guards/request-scoped.guard.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CanActivate, 3 | ExecutionContext, 4 | Inject, 5 | Injectable, 6 | Scope, 7 | } from '@nestjs/common'; 8 | import { Observable } from 'rxjs'; 9 | 10 | @Injectable({ scope: Scope.REQUEST }) 11 | export class Guard implements CanActivate { 12 | static COUNTER = 0; 13 | static REQUEST_SCOPED_DATA = []; 14 | 15 | constructor(@Inject('REQUEST_ID') private requestId: number) { 16 | Guard.COUNTER++; 17 | } 18 | 19 | canActivate( 20 | context: ExecutionContext, 21 | ): boolean | Promise | Observable { 22 | Guard.REQUEST_SCOPED_DATA.push(this.requestId); 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/hello/hello.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable, Scope } from '@nestjs/common'; 2 | 3 | @Injectable({ scope: Scope.REQUEST }) 4 | export class HelloService { 5 | constructor(@Inject('META') private readonly meta) {} 6 | 7 | getCats(): any[] { 8 | return [{ id: 1, name: 'Cat', age: 5 }]; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/hello/interceptors/logging.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CallHandler, 3 | ExecutionContext, 4 | Inject, 5 | Injectable, 6 | NestInterceptor, 7 | Scope, 8 | } from '@nestjs/common'; 9 | import { Observable } from 'rxjs'; 10 | 11 | @Injectable({ scope: Scope.REQUEST }) 12 | export class Interceptor implements NestInterceptor { 13 | static COUNTER = 0; 14 | static REQUEST_SCOPED_DATA = []; 15 | 16 | constructor(@Inject('REQUEST_ID') private requestId: number) { 17 | Interceptor.COUNTER++; 18 | } 19 | 20 | intercept(context: ExecutionContext, call: CallHandler): Observable { 21 | Interceptor.REQUEST_SCOPED_DATA.push(this.requestId); 22 | return call.handle(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/hello/users/user-by-id.pipe.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ArgumentMetadata, 3 | Inject, 4 | Injectable, 5 | PipeTransform, 6 | } from '@nestjs/common'; 7 | import { UsersService } from './users.service'; 8 | 9 | @Injectable() 10 | export class UserByIdPipe implements PipeTransform { 11 | static COUNTER = 0; 12 | static REQUEST_SCOPED_DATA = []; 13 | 14 | constructor( 15 | @Inject('REQUEST_ID') private requestId: number, 16 | private readonly usersService: UsersService, 17 | ) { 18 | UserByIdPipe.COUNTER++; 19 | } 20 | 21 | transform(value: string, metadata: ArgumentMetadata) { 22 | UserByIdPipe.REQUEST_SCOPED_DATA.push(this.requestId); 23 | return this.usersService.findById(value); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/hello/users/users.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable, Scope } from '@nestjs/common'; 2 | 3 | @Injectable({ scope: Scope.REQUEST }) 4 | export class UsersService { 5 | static COUNTER = 0; 6 | constructor(@Inject('META') private readonly meta) { 7 | UsersService.COUNTER++; 8 | } 9 | 10 | findById(id: string) { 11 | return { id }; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { FastifyAdapter } from '@nestjs/platform-fastify'; 3 | import { ApplicationModule } from './app.module'; 4 | 5 | async function bootstrap() { 6 | const app = await NestFactory.create(ApplicationModule, new FastifyAdapter()); 7 | await app.listen(3010); 8 | } 9 | bootstrap(); 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/sort-auto-schema.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusDriver } from '../../lib/drivers'; 4 | import { DirectionsModule } from '../code-first/directions/directions.module'; 5 | import { RecipesModule } from '../code-first/recipes/recipes.module'; 6 | 7 | @Module({ 8 | imports: [ 9 | RecipesModule, 10 | DirectionsModule, 11 | GraphQLModule.forRoot({ 12 | driver: MercuriusDriver, 13 | autoSchemaFile: 'schema.graphql', 14 | sortSchema: true, 15 | }), 16 | ], 17 | }) 18 | export class SortAutoSchemaModule {} 19 | -------------------------------------------------------------------------------- /packages/mercurius/tests/graphql/sort-schema.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { join } from 'path'; 4 | import { MercuriusDriver } from '../../lib/drivers'; 5 | import { CatsModule } from './cats/cats.module'; 6 | 7 | @Module({ 8 | imports: [ 9 | CatsModule, 10 | GraphQLModule.forRoot({ 11 | driver: MercuriusDriver, 12 | typePaths: [join(__dirname, '**', '*.graphql')], 13 | sortSchema: true, 14 | }), 15 | ], 16 | }) 17 | export class SortSchemaModule {} 18 | -------------------------------------------------------------------------------- /packages/mercurius/tests/hooks/base-array/hooks.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusDriver } from '../../../lib/drivers'; 4 | import { MercuriusDriverConfig } from '../../../lib/interfaces/mercurius-driver-config.interface'; 5 | import { CatsModule } from '../cats/cats.module'; 6 | import { GqlConfigService } from './graphql.config'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRootAsync({ 12 | driver: MercuriusDriver, 13 | useClass: GqlConfigService, 14 | }), 15 | ], 16 | }) 17 | export class ApplicationModule {} 18 | -------------------------------------------------------------------------------- /packages/mercurius/tests/hooks/base/hooks.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusDriver } from '../../../lib/drivers'; 4 | import { MercuriusDriverConfig } from '../../../lib/interfaces/mercurius-driver-config.interface'; 5 | import { CatsModule } from '../cats/cats.module'; 6 | import { GqlConfigService } from './graphql.config'; 7 | 8 | @Module({ 9 | imports: [ 10 | CatsModule, 11 | GraphQLModule.forRootAsync({ 12 | driver: MercuriusDriver, 13 | useClass: GqlConfigService, 14 | }), 15 | ], 16 | }) 17 | export class ApplicationModule {} 18 | -------------------------------------------------------------------------------- /packages/mercurius/tests/hooks/cats/cats.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { CatsResolver } from './cats.resolver'; 3 | 4 | @Module({ 5 | providers: [CatsResolver], 6 | }) 7 | export class CatsModule {} 8 | -------------------------------------------------------------------------------- /packages/mercurius/tests/hooks/cats/cats.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Query, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class CatsResolver { 5 | @Query((returns) => String) 6 | public getAnimalName(): string { 7 | return 'cat'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/hooks/mocks/logger.mock.ts: -------------------------------------------------------------------------------- 1 | import { LoggerService } from '@nestjs/common'; 2 | 3 | export class MockLogger implements LoggerService { 4 | public log = jest.fn(); 5 | public error = jest.fn(); 6 | public warn = jest.fn(); 7 | public debug = jest.fn(); 8 | public verbose = jest.fn(); 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/jest-e2e.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from '@jest/types'; 2 | import { pathsToModuleNameMapper } from 'ts-jest'; 3 | import { compilerOptions } from '../tsconfig.spec.json'; 4 | 5 | const moduleNameMapper = pathsToModuleNameMapper(compilerOptions.paths, { 6 | prefix: '/', 7 | }); 8 | 9 | const config: Config.InitialOptions = { 10 | moduleFileExtensions: ['js', 'json', 'ts'], 11 | rootDir: '../.', 12 | testRegex: '.spec.ts$', 13 | moduleNameMapper, 14 | transform: { 15 | '^.+\\.(t|j)s$': [ 16 | 'ts-jest', 17 | { tsconfig: '/tsconfig.spec.json', isolatedModules: true }, 18 | ], 19 | }, 20 | coverageDirectory: '../coverage', 21 | testEnvironment: 'node', 22 | }; 23 | 24 | export default config; 25 | -------------------------------------------------------------------------------- /packages/mercurius/tests/plugins/code-first-plugin/dogs/dogs.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { DogsResolver } from './dogs.resolver'; 3 | 4 | @Module({ 5 | providers: [DogsResolver], 6 | }) 7 | export class DogsModule {} 8 | -------------------------------------------------------------------------------- /packages/mercurius/tests/plugins/code-first-plugin/dogs/dogs.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Query, Resolver } from '@nestjs/graphql'; 2 | 3 | @Resolver() 4 | export class DogsResolver { 5 | @Query((returns) => String) 6 | getAnimalName(): string { 7 | return 'dog'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mercurius/tests/plugins/code-first-plugin/main.ts: -------------------------------------------------------------------------------- 1 | import { ValidationPipe } from '@nestjs/common'; 2 | import { NestFactory } from '@nestjs/core'; 3 | import { FastifyAdapter } from '@nestjs/platform-fastify'; 4 | import mercurius from 'mercurius'; 5 | import { ApplicationModule } from './app.module'; 6 | 7 | async function bootstrap() { 8 | const app = await NestFactory.create(ApplicationModule, new FastifyAdapter()); 9 | app.useGlobalPipes( 10 | new ValidationPipe({ 11 | exceptionFactory: (errors) => 12 | new mercurius.ErrorWithProps('Validation error', { errors }, 200), 13 | }), 14 | ); 15 | await app.listen(3010); 16 | } 17 | bootstrap(); 18 | -------------------------------------------------------------------------------- /packages/mercurius/tests/plugins/graphql-federation-plugin/gateway/gateway.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { MercuriusGatewayDriver } from '../../../../lib/drivers'; 4 | import { mockPlugin } from '../../mocks/mock.plugin'; 5 | 6 | @Module({ 7 | imports: [ 8 | GraphQLModule.forRoot({ 9 | driver: MercuriusGatewayDriver, 10 | gateway: { 11 | services: [ 12 | { name: 'users', url: 'http://localhost:3011/graphql' }, 13 | { name: 'posts', url: 'http://localhost:3012/graphql' }, 14 | ], 15 | }, 16 | plugins: [ 17 | { 18 | plugin: mockPlugin, 19 | }, 20 | ], 21 | }), 22 | ], 23 | }) 24 | export class AppModule {} 25 | -------------------------------------------------------------------------------- /packages/mercurius/tests/plugins/mocks/interfaces/plugin-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface PluginOptions { 2 | url: string; 3 | } 4 | -------------------------------------------------------------------------------- /packages/mercurius/tests/plugins/mocks/interfaces/plugin-response.interface.ts: -------------------------------------------------------------------------------- 1 | export interface PluginResponse { 2 | from: string; 3 | } 4 | -------------------------------------------------------------------------------- /packages/mercurius/tests/plugins/mocks/mock.plugin.ts: -------------------------------------------------------------------------------- 1 | import { FastifyInstance } from 'fastify'; 2 | import { PluginOptions } from './interfaces/plugin-options.interface'; 3 | import { BASE_PLUGIN_URL } from './utils/constants'; 4 | import { pluginResponse } from './utils/plugin-response'; 5 | 6 | export async function mockPlugin( 7 | fastify: FastifyInstance, 8 | options?: PluginOptions, 9 | ) { 10 | const url = options?.url ?? BASE_PLUGIN_URL; 11 | 12 | fastify.get(url, async (request, reply) => { 13 | return pluginResponse(url); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /packages/mercurius/tests/plugins/mocks/utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const NEW_PLUGIN_URL = '/new-plugin-url'; 2 | export const BASE_PLUGIN_URL = '/mock-plugin'; 3 | -------------------------------------------------------------------------------- /packages/mercurius/tests/plugins/mocks/utils/plugin-response.ts: -------------------------------------------------------------------------------- 1 | import { PluginResponse } from '../interfaces/plugin-response.interface'; 2 | 3 | export function pluginResponse(url: string): PluginResponse { 4 | return { 5 | from: url, 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /packages/mercurius/tests/subscriptions-federation/app/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; 2 | import { GqlExecutionContext } from '@nestjs/graphql'; 3 | 4 | @Injectable() 5 | export class AuthGuard implements CanActivate { 6 | canActivate(context: ExecutionContext): boolean { 7 | const ctx = GqlExecutionContext.create(context).getContext(); 8 | return !!ctx.user?.startsWith?.('test'); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/mercurius/tests/subscriptions-federation/app/notification.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { NotificationResolver } from './notification.resolver'; 3 | 4 | @Module({ 5 | providers: [NotificationResolver], 6 | }) 7 | export class NotificationModule {} 8 | -------------------------------------------------------------------------------- /packages/mercurius/tests/subscriptions-federation/app/notification.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '@nestjs/graphql'; 2 | 3 | @ObjectType() 4 | export class Notification { 5 | @Field({ 6 | nullable: false, 7 | }) 8 | id: string; 9 | 10 | @Field({ 11 | nullable: false, 12 | }) 13 | recipient: string; 14 | 15 | @Field({ 16 | nullable: false, 17 | }) 18 | message: string; 19 | } 20 | -------------------------------------------------------------------------------- /packages/mercurius/tests/subscriptions/app/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; 2 | import { GqlExecutionContext } from '@nestjs/graphql'; 3 | 4 | @Injectable() 5 | export class AuthGuard implements CanActivate { 6 | canActivate(context: ExecutionContext): boolean { 7 | const ctx = GqlExecutionContext.create(context).getContext(); 8 | return !!ctx.user?.startsWith?.('test'); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/mercurius/tests/subscriptions/app/notification.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { NotificationResolver } from './notification.resolver'; 3 | 4 | @Module({ 5 | providers: [NotificationResolver], 6 | }) 7 | export class NotificationModule {} 8 | -------------------------------------------------------------------------------- /packages/mercurius/tests/subscriptions/app/notification.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '@nestjs/graphql'; 2 | 3 | @ObjectType() 4 | export class Notification { 5 | @Field({ 6 | nullable: false, 7 | }) 8 | id: string; 9 | 10 | @Field({ 11 | nullable: false, 12 | }) 13 | recipient: string; 14 | 15 | @Field({ 16 | nullable: false, 17 | }) 18 | message: string; 19 | } 20 | -------------------------------------------------------------------------------- /packages/mercurius/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "rootDir": "./lib", 6 | "paths": { 7 | "@nestjs/graphql": ["../graphql/lib"], 8 | "@nestjs/graphql/*": ["../graphql/lib/*"], 9 | } 10 | }, 11 | "exclude": ["node_modules", "dist", "tests/**/*", "*.spec.ts"], 12 | "references": [ 13 | { 14 | "path": "../graphql/tsconfig.build.json" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/mercurius/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "types": ["node"], 5 | "paths": { 6 | "@nestjs/graphql": ["../graphql/lib"], 7 | "@nestjs/graphql/*": ["../graphql/lib/*"], 8 | } 9 | }, 10 | "files": [], 11 | "include": [], 12 | "references": [ 13 | { 14 | "path": "./tsconfig.build.json" 15 | }, 16 | { 17 | "path": "./tsconfig.spec.json" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/mercurius/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist/tests", 5 | "types": ["jest", "node"], 6 | "rootDir": ".", 7 | "resolveJsonModule": true, 8 | "paths": { 9 | "@nestjs/graphql": ["../graphql/lib"], 10 | "@nestjs/graphql/*": ["../graphql/lib/*"] 11 | } 12 | }, 13 | "references": [ 14 | { 15 | "path": "../graphql/tsconfig.build.json" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "commonjs", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "noImplicitAny": false, 8 | "importHelpers": true, 9 | "removeComments": false, 10 | "noLib": false, 11 | "emitDecoratorMetadata": true, 12 | "experimentalDecorators": true, 13 | "target": "ES2021", 14 | "sourceMap": false, 15 | "skipLibCheck": true, 16 | "resolveJsonModule": true 17 | }, 18 | } -------------------------------------------------------------------------------- /packages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./apollo/tsconfig.build.json", 6 | }, 7 | { 8 | "path": "./graphql/tsconfig.build.json", 9 | }, 10 | { 11 | "path": "./mercurius/tsconfig.build.json", 12 | }, 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "semanticCommits": true, 3 | "labels": ["dependencies"], 4 | "packageRules": [{ 5 | "depTypeList": ["devDependencies"], 6 | "automerge": true 7 | }], 8 | "extends": [ 9 | "config:base" 10 | ] 11 | } 12 | --------------------------------------------------------------------------------