Skip to content

Commit

Permalink
feat(context): add optional graphqlResolveInfo to context variables
Browse files Browse the repository at this point in the history
closes #59
  • Loading branch information
schettn authored Dec 26, 2024
1 parent 625fc45 commit fcf9616
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 0 deletions.
175 changes: 175 additions & 0 deletions examples/graphql-resolve-info/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Logs

logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)

report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

# Runtime data

pids
_.pid
_.seed
\*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover

lib-cov

# Coverage directory used by tools like istanbul

coverage
\*.lcov

# nyc test coverage

.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)

.grunt

# Bower dependency directory (https://bower.io/)

bower_components

# node-waf configuration

.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)

build/Release

# Dependency directories

node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)

web_modules/

# TypeScript cache

\*.tsbuildinfo

# Optional npm cache directory

.npm

# Optional eslint cache

.eslintcache

# Optional stylelint cache

.stylelintcache

# Microbundle cache

.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history

.node_repl_history

# Output of 'npm pack'

\*.tgz

# Yarn Integrity file

.yarn-integrity

# dotenv environment variable files

.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)

.cache
.parcel-cache

# Next.js build output

.next
out

# Nuxt.js build / generate output

.nuxt
dist

# Gatsby files

.cache/

# Comment in the public line in if your project uses Gatsby and not Next.js

# https://nextjs.org/blog/next-9-1#public-directory-support

# public

# vuepress build output

.vuepress/dist

# vuepress v2.x temp and cache directory

.temp
.cache

# Docusaurus cache and generated files

.docusaurus

# Serverless directories

.serverless/

# FuseBox cache

.fusebox/

# DynamoDB Local files

.dynamodb/

# TernJS port file

.tern-port

# Stores VSCode versions used for testing VSCode extensions

.vscode-test

# yarn v2

.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.\*

# wrangler project

.dev.vars
.wrangler/

# Pylon project
.pylon
24 changes: 24 additions & 0 deletions examples/graphql-resolve-info/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "graphql-resolve-info",
"private": true,
"version": "0.0.1",
"type": "module",
"description": "Generated with `npm create pylon`",
"scripts": {
"dev": "pylon dev -c \"bun run .pylon/index.js\"",
"build": "pylon build"
},
"dependencies": {
"@getcronit/pylon": "^2.0.0",
"bun-types": "^1.1.18",
"graphql-parse-resolve-info": "^4.13.0"
},
"devDependencies": {
"@getcronit/pylon-dev": "^1.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/getcronit/pylon.git"
},
"homepage": "https://pylon.cronit.io"
}
7 changes: 7 additions & 0 deletions examples/graphql-resolve-info/pylon.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import '@getcronit/pylon'

declare module '@getcronit/pylon' {
interface Bindings {}

interface Variables {}
}
43 changes: 43 additions & 0 deletions examples/graphql-resolve-info/src/get-resolved-fields.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { getContext } from '@getcronit/pylon';
import { GraphQLResolveInfo } from 'graphql';
import { ResolveTree, FieldsByTypeName, parseResolveInfo } from 'graphql-parse-resolve-info';

type GraphQLMappedFields = {
flatFields: string[];
nestedFields: { [fieldName: string]: GraphQLMappedFields; };
};
function isFlatField(tree: ResolveTree) {
return Object.keys(tree.fieldsByTypeName).length === 0;
}
const fetchResolveInfoNestedFields = (resolvedInfo: ResolveTree | FieldsByTypeName) => {
const resourceTreeMap: FieldsByTypeName[any] = Object.values(resolvedInfo.fieldsByTypeName)[0];
return Object.keys(resourceTreeMap).reduce(
(map: GraphQLMappedFields, field) => {
if (isFlatField(resourceTreeMap[field])) {
map.flatFields.push(field);
} else {
map.nestedFields[field] = fetchResolveInfoNestedFields(resourceTreeMap[field]);
}

return map;
},
{ flatFields: [], nestedFields: {} }
);
};

const getFieldsFromResolvedInfo = (info: GraphQLResolveInfo) => {
return fetchResolveInfoNestedFields(parseResolveInfo(info)!);
};


export const getResolvedFields = () => {
const ctx = getContext()

const info = ctx.get("graphqlResolveInfo")

if(!info){
throw new Error("This must be used inside a GraphQL operation")
}

return getFieldsFromResolvedInfo(info)
}
34 changes: 34 additions & 0 deletions examples/graphql-resolve-info/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { app } from '@getcronit/pylon'
import { getResolvedFields } from './get-resolved-fields'

const getUser = (): {
firstName: string,
lastName: string,
username: string
} => {
const fields = getResolvedFields()

return {
firstName: fields.nestedFields.user.flatFields.includes("firstName") ? "John" : "",
lastName: fields.nestedFields.user.flatFields.includes("lastName") ? "Doe" : "",
username: fields.nestedFields.user.flatFields.includes("username") ? "johndoe" : ""
}
}

export const graphql = {
Query: {
data: () => {

const user = getUser()

console.log("Got user", user)

return {
user,
}
}
},
Mutation: {}
}

export default app
8 changes: 8 additions & 0 deletions examples/graphql-resolve-info/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "@getcronit/pylon/tsconfig.pylon.json",
"compilerOptions": {
// add Bun type definitions
"types": ["bun-types"]
},
"include": ["pylon.d.ts", "src/**/*.ts"]
}
2 changes: 2 additions & 0 deletions packages/pylon/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {AuthState} from './auth'
import {AsyncLocalStorage} from 'async_hooks'
import {sendFunctionEvent} from '@getcronit/pylon-telemetry'
import {env} from 'hono/adapter'
import type { GraphQLResolveInfo } from 'graphql'

export interface Bindings {
NODE_ENV: string
Expand All @@ -15,6 +16,7 @@ export interface Bindings {
export interface Variables {
auth: AuthState
sentry: Toucan
graphqlResolveInfo?: GraphQLResolveInfo
}

export type Env = {
Expand Down
3 changes: 3 additions & 0 deletions packages/pylon/src/define-pylon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,15 @@ export const resolversToGraphQLResolvers = (
return Sentry.withScope(async scope => {
const ctx = asyncContext.getStore()


if (!ctx) {
consola.warn(
'Context is not defined. Make sure AsyncLocalStorage is supported in your environment.'
)
}

ctx?.set("graphqlResolveInfo", info)

const auth = ctx?.get('auth')

if (auth?.active) {
Expand Down

1 comment on commit fcf9616

@github-actions
Copy link

Choose a reason for hiding this comment

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

Deploy preview for pylon-docs ready!

✅ Preview
https://pylon-docs-rvx9isq4v-schettns-projects.vercel.app

Built with commit fcf9616.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.