Skip to content
This repository has been archived by the owner on May 11, 2021. It is now read-only.

Commit

Permalink
feat(graphql): add example generation (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
believer authored Oct 1, 2019
1 parent 1692248 commit ac14efc
Show file tree
Hide file tree
Showing 7 changed files with 431 additions and 6 deletions.
29 changes: 24 additions & 5 deletions src/commands/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface GraphQLProps {
name?: string
}

export const graphql = async ({ name }: GraphQLProps) => {
export const graphql = async ({ name, flags }: GraphQLProps) => {
if (!name) {
console.log(`No name provided`)
return
Expand Down Expand Up @@ -55,10 +55,29 @@ export const graphql = async ({ name }: GraphQLProps) => {

await createFolder(`${name}/lib`)

await create({
templateName: 'graphql/server.ts',
output: `${name}/lib/server.ts`,
})
if (flags.examples) {
await create({
templateName: 'graphql/serverExample.ts',
output: `${name}/lib/server.ts`,
})

await createFolder(`${name}/lib/resolvers`)
await create({
templateName: 'graphql/resolversExample.ts',
output: `${name}/lib/resolvers/queue.ts`,
})

await createFolder(`${name}/lib/__generated__`)
await create({
templateName: 'graphql/graphql.d.ts',
output: `${name}/lib/__generated__/graphql.d.ts`,
})
} else {
await create({
templateName: 'graphql/server.ts',
output: `${name}/lib/server.ts`,
})
}

spinner.stop()

Expand Down
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface CLIFlags {
javascript: boolean
ide?: string
language?: string
examples?: boolean
}

export interface CLIProps {
Expand Down Expand Up @@ -68,6 +69,7 @@ const cli = meow(
--javascript JavaScript app (react)
--ide IDE for snippets (snippets)
--language Language for snippets (snippets)
--examples GraphQL examples (examples)
`,
{
flags: {
Expand All @@ -81,6 +83,9 @@ const cli = meow(
language: {
type: 'string',
},
examples: {
type: 'boolean',
},
},
}
)
Expand Down
206 changes: 206 additions & 0 deletions src/templates/graphql/graphql.d.ts.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql';
export type Maybe<T> = T | null;
export type RequireFields<T, K extends keyof T> = { [X in Exclude<keyof T, K>]?: T[X] } & { [P in K]-?: NonNullable<T[P]> };
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: string,
String: string,
Boolean: boolean,
Int: number,
Float: number,
/** The `Upload` scalar type represents a file upload. */
Upload: any,
};


export enum CacheControlScope {
Public = 'PUBLIC',
Private = 'PRIVATE'
}

export type Mutation = {
__typename?: 'Mutation',
_empty?: Maybe<Scalars['String']>,
addTrack: Array<Track>,
};


export type MutationAddTrackArgs = {
input: TrackInput
};

export type Query = {
__typename?: 'Query',
_empty?: Maybe<Scalars['String']>,
currentQueue: Array<Track>,
};

export type Subscription = {
__typename?: 'Subscription',
_empty?: Maybe<Scalars['String']>,
trackAdded: Track,
};

export type Track = {
__typename?: 'Track',
title: Scalars['String'],
artist: Scalars['String'],
album: Scalars['String'],
};

export type TrackInput = {
title: Scalars['String'],
artist: Scalars['String'],
album: Scalars['String'],
};



export type ResolverTypeWrapper<T> = Promise<T> | T;

export type ResolverFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => Promise<TResult> | TResult;


export type StitchingResolver<TResult, TParent, TContext, TArgs> = {
fragment: string;
resolve: ResolverFn<TResult, TParent, TContext, TArgs>;
};

export type Resolver<TResult, TParent = {}, TContext = {}, TArgs = {}> =
| ResolverFn<TResult, TParent, TContext, TArgs>
| StitchingResolver<TResult, TParent, TContext, TArgs>;

export type SubscriptionSubscribeFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => AsyncIterator<TResult> | Promise<AsyncIterator<TResult>>;

export type SubscriptionResolveFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => TResult | Promise<TResult>;

export interface SubscriptionSubscriberObject<TResult, TKey extends string, TParent, TContext, TArgs> {
subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>;
resolve?: SubscriptionResolveFn<TResult, { [key in TKey]: TResult }, TContext, TArgs>;
}

export interface SubscriptionResolverObject<TResult, TParent, TContext, TArgs> {
subscribe: SubscriptionSubscribeFn<any, TParent, TContext, TArgs>;
resolve: SubscriptionResolveFn<TResult, any, TContext, TArgs>;
}

export type SubscriptionObject<TResult, TKey extends string, TParent, TContext, TArgs> =
| SubscriptionSubscriberObject<TResult, TKey, TParent, TContext, TArgs>
| SubscriptionResolverObject<TResult, TParent, TContext, TArgs>;

export type SubscriptionResolver<TResult, TKey extends string, TParent = {}, TContext = {}, TArgs = {}> =
| ((...args: any[]) => SubscriptionObject<TResult, TKey, TParent, TContext, TArgs>)
| SubscriptionObject<TResult, TKey, TParent, TContext, TArgs>;

export type TypeResolveFn<TTypes, TParent = {}, TContext = {}> = (
parent: TParent,
context: TContext,
info: GraphQLResolveInfo
) => Maybe<TTypes>;

export type NextResolverFn<T> = () => Promise<T>;

export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs = {}> = (
next: NextResolverFn<TResult>,
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => TResult | Promise<TResult>;

/** Mapping between all available schema types and the resolvers types */
export type ResolversTypes = {
Query: ResolverTypeWrapper<{}>,
String: ResolverTypeWrapper<Scalars['String']>,
Track: ResolverTypeWrapper<Track>,
Mutation: ResolverTypeWrapper<{}>,
TrackInput: TrackInput,
Subscription: ResolverTypeWrapper<{}>,
Boolean: ResolverTypeWrapper<Scalars['Boolean']>,
CacheControlScope: CacheControlScope,
Upload: ResolverTypeWrapper<Scalars['Upload']>,
Int: ResolverTypeWrapper<Scalars['Int']>,
};

/** Mapping between all available schema types and the resolvers parents */
export type ResolversParentTypes = {
Query: {},
String: Scalars['String'],
Track: Track,
Mutation: {},
TrackInput: TrackInput,
Subscription: {},
Boolean: Scalars['Boolean'],
CacheControlScope: CacheControlScope,
Upload: Scalars['Upload'],
Int: Scalars['Int'],
};

export type CacheControlDirectiveResolver<Result, Parent, ContextType = any, Args = { maxAge?: Maybe<Maybe<Scalars['Int']>>,
scope?: Maybe<Maybe<CacheControlScope>> }> = DirectiveResolverFn<Result, Parent, ContextType, Args>;

export type MutationResolvers<ContextType = any, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation']> = {
_empty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>,
addTrack?: Resolver<Array<ResolversTypes['Track']>, ParentType, ContextType, RequireFields<MutationAddTrackArgs, 'input'>>,
};

export type QueryResolvers<ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = {
_empty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>,
currentQueue?: Resolver<Array<ResolversTypes['Track']>, ParentType, ContextType>,
};

export type SubscriptionResolvers<ContextType = any, ParentType extends ResolversParentTypes['Subscription'] = ResolversParentTypes['Subscription']> = {
_empty?: SubscriptionResolver<Maybe<ResolversTypes['String']>, "_empty", ParentType, ContextType>,
trackAdded?: SubscriptionResolver<ResolversTypes['Track'], "trackAdded", ParentType, ContextType>,
};

export type TrackResolvers<ContextType = any, ParentType extends ResolversParentTypes['Track'] = ResolversParentTypes['Track']> = {
title?: Resolver<ResolversTypes['String'], ParentType, ContextType>,
artist?: Resolver<ResolversTypes['String'], ParentType, ContextType>,
album?: Resolver<ResolversTypes['String'], ParentType, ContextType>,
};

export interface UploadScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['Upload'], any> {
name: 'Upload'
}

export type Resolvers<ContextType = any> = {
Mutation?: MutationResolvers<ContextType>,
Query?: QueryResolvers<ContextType>,
Subscription?: SubscriptionResolvers<ContextType>,
Track?: TrackResolvers<ContextType>,
Upload?: GraphQLScalarType,
};


/**
* @deprecated
* Use "Resolvers" root object instead. If you wish to get "IResolvers", add "typesPrefix: I" to your config.
*/
export type IResolvers<ContextType = any> = Resolvers<ContextType>;
export type DirectiveResolvers<ContextType = any> = {
cacheControl?: CacheControlDirectiveResolver<any, any, ContextType>,
};


/**
* @deprecated
* Use "DirectiveResolvers" root object instead. If you wish to get "IDirectiveResolvers", add "typesPrefix: I" to your config.
*/
export type IDirectiveResolvers<ContextType = any> = DirectiveResolvers<ContextType>;

7 changes: 6 additions & 1 deletion src/templates/graphql/package.json.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@
"license": "MIT",
"dependencies": {
"apollo-server-express": "2.9.4",
"express": "4.17.1"
"express": "4.17.1",
"lodash.merge": "4.6.2"
},
"devDependencies": {
"@graphql-codegen/cli": "1.7.0",
"@graphql-codegen/typescript": "1.7.0",
"@graphql-codegen/typescript-resolvers": "1.7.0",
"@types/lodash.merge": "4.6.6",
"ts-node-dev": "1.0.0-pre.43",
"typescript": "3.6.3"
}
Expand Down
63 changes: 63 additions & 0 deletions src/templates/graphql/resolversExample.ts.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { gql } from 'apollo-server-express'
import { queue, pubsub } from '../server'
import {
QueryResolvers,
MutationResolvers,
SubscriptionResolvers,
} from '../__generated__/graphql'

const TRACK_ADDED = 'TRACK_ADDED'

export const typeDefs = gql`
type Track {
title: String!
artist: String!
album: String!
}

input TrackInput {
title: String!
artist: String!
album: String!
}

extend type Query {
currentQueue: [Track!]!
}

extend type Mutation {
addTrack(input: TrackInput!): [Track!]!
}

extend type Subscription {
trackAdded: Track!
}
`

interface Resolvers {
Query: QueryResolvers
Mutation: MutationResolvers
Subscription: SubscriptionResolvers
}

export const resolvers: Resolvers = {
Query: {
currentQueue: () => queue,
},

Mutation: {
addTrack: (_, { input }) => {
pubsub.publish(TRACK_ADDED, { trackAdded: input })
queue.push(input)

return queue
},
},

Subscription: {
trackAdded: {
subscribe: () => pubsub.asyncIterator([TRACK_ADDED]),
},
},
}

Loading

0 comments on commit ac14efc

Please sign in to comment.