Skip to content

Commit

Permalink
feat(alias): casting-response
Browse files Browse the repository at this point in the history
fix #64
  • Loading branch information
aexol committed Aug 5, 2019
1 parent 5ed3cb7 commit b518240
Show file tree
Hide file tree
Showing 13 changed files with 637 additions and 458 deletions.
189 changes: 103 additions & 86 deletions examples/javascript-node/src/graphql-zeus.d.ts
Original file line number Diff line number Diff line change
@@ -1,70 +1,86 @@
export interface Query {
cardById: (props: { cardId?: string }) => Card;
/** Draw a card<br> */
drawCard: Card;
/** list All Cards availbla<br> */
listCards: Card[];
export type Query = {
cardById:(props:{ cardId?:string}) => Card,
/** Draw a card<br> */
drawCard:Card,
/** list All Cards availbla<br> */
listCards:Card[]
}

/** Card used in card game<br> */
export interface Card {
/** The attack power<br> */
Attack: number;
/** <div>How many children the greek god had</div> */
Children?: number;
/** The defense power<br> */
Defense: number;
/** Attack other cards on the table , returns Cards after attack<br> */
attack: (props: {
/** Attacked card/card ids<br> */
cardID?: string[];
}) => Card[];
cardImage?: S3Object;
/** Description of a card<br> */
description: string;
id: string;
/** The name of a card<br> */
name: string;
skills?: SpecialSkills[];
export type Card = {
/** The attack power<br> */
Attack:number,
/** <div>How many children the greek god had</div> */
Children?:number,
/** The defense power<br> */
Defense:number,
/** Attack other cards on the table , returns Cards after attack<br> */
attack:(props:{ /** Attacked card/card ids<br> */
cardID?:string[]}) => Card[],
cardImage?:S3Object,
/** Description of a card<br> */
description:string,
id:string,
/** The name of a card<br> */
name:string,
skills?:SpecialSkills[]
}

/** Aws S3 File */
export interface S3Object {
bucket: string;
key: string;
region: string;
export type S3Object = {
bucket:string,
key:string,
region:string
}

export enum SpecialSkills {
THUNDER = 'THUNDER',
RAIN = 'RAIN',
FIRE = 'FIRE'
FIRE = "FIRE",
THUNDER = "THUNDER",
RAIN = "RAIN"
}

export interface Mutation {
/** add Card to Cards database<br> */
addCard: (props: { card: createCard }) => Card;
export type Mutation = {
/** add Card to Cards database<br> */
addCard:(props:{ card:createCard}) => Card
}

export interface createCard {
/** The name of a card<br> */
name: string;
/** Description of a card<br> */
description: string;
/** <div>How many children the greek god had</div> */
Children?: number;
/** The attack power<br> */
Attack: number;
/** The defense power<br> */
Defense: number;
skills?: SpecialSkills[];
export type createCard = {
skills?:SpecialSkills[],
/** The name of a card<br> */
name:string,
/** Description of a card<br> */
description:string,
/** <div>How many children the greek god had</div> */
Children?:number,
/** The attack power<br> */
Attack:number,
/** The defense power<br> */
Defense:number
}



type Func<P extends any[], R> = (...args: P) => R;
type AnyFunc = Func<any, any>;

type AliasType<T> = T & {
__alias?: Record<string, T>;
};

type AliasedReturnType<T> = T & {
[x: string]: T;
};
type IsType<M, T, Z, L> = T extends M ? Z : L;
type IsObject<T, Z, L> = IsType<Record<string, unknown>, T, Z, L>;
type IsObject<T, Z, L> = IsType<
{
[x in keyof T]: unknown;
},
T,
Z,
L
>;
type IsSimpleObject<T, Z, L> = IsType<Record<string, unknown> | Record<string, unknown>[], T, Z, L>;
type IsScalar<T, Z, L> = IsType<string | boolean | number, T, Z, L>;

type ArgsType<F extends AnyFunc> = F extends Func<infer P, any> ? P : never;
type GetTypeFromArray<T> = T extends Array<infer R> ? R : T;
Expand All @@ -77,17 +93,19 @@ interface GraphQLResponse {
}>;
}

export type ResolveReturned<T> = {
[P in keyof T]?: T[P] extends (Array<infer R> | undefined)
? Array<ResolveReturned<R>>
: T[P] extends AnyFunc
? ResolveReturned<ReturnType<T[P]>>
: IsObject<
T[P],
ResolveReturned<T[P]>,
T[P] extends AnyFunc ? ResolveReturned<ReturnType<T[P]>> : T[P]
>;
};
export type ResolveReturned<T> = AliasedReturnType<
{
[P in keyof T]?: T[P] extends (Array<infer R> | undefined)
? Array<ResolveReturned<R>>
: T[P] extends AnyFunc
? ResolveReturned<ReturnType<T[P]>>
: IsObject<
T[P],
ResolveReturned<T[P]>,
T[P] extends AnyFunc ? ResolveReturned<ReturnType<T[P]>> : T[P]
>;
}
>;

export type State<T> = ResolveReturned<T>;

Expand All @@ -96,18 +114,20 @@ type ResolveInternalFunctionReturn<T> = T extends Array<infer R> ? R : T;
type ResolveValue<T> = T extends Array<infer R>
? SelectionSet<R>
: T extends AnyFunc
? IsObject<
? IsScalar<
ReturnType<T>,
[FirstArgument<T>, SelectionSet<ResolveInternalFunctionReturn<ReturnType<T>>>],
[FirstArgument<T>]
[FirstArgument<T>],
[FirstArgument<T>, AliasType<SelectionSet<ResolveInternalFunctionReturn<ReturnType<T>>>>]
>
: IsObject<T, SelectionSet<T>, T extends undefined ? undefined : true>;
: IsSimpleObject<T, AliasType<SelectionSet<T>>, T extends undefined ? undefined : true>;

export type SelectionSet<T> = IsObject<
export type SelectionSet<T> = IsSimpleObject<
T,
{
[P in keyof T]?: ResolveValue<T[P]>;
},
AliasType<
{
[P in keyof T]?: AliasType<ResolveValue<T[P]>>;
}
>,
T extends undefined ? undefined : true
>;

Expand All @@ -118,32 +138,29 @@ type ApiFieldToGraphQL<T> = (o: ResolveValue<T>) => Promise<ResolveReturned<T>>;

type fetchOptions = ArgsType<typeof fetch>;


export declare function Chain(
...options: fetchOptions
): {
Query: OperationToGraphQL<Query>;
Mutation: OperationToGraphQL<Mutation>;
};
):{
Query: OperationToGraphQL<Query>,Mutation: OperationToGraphQL<Mutation>
}

export declare function Api(
...options: fetchOptions
): {
):{
Query: {
cardById: ApiFieldToGraphQL<Query['cardById']>;
drawCard: ApiFieldToGraphQL<Query['drawCard']>;
listCards: ApiFieldToGraphQL<Query['listCards']>;
};
Mutation: {
addCard: ApiFieldToGraphQL<Mutation['addCard']>;
};
};
cardById: ApiFieldToGraphQL<Query['cardById']>,
drawCard: ApiFieldToGraphQL<Query['drawCard']>,
listCards: ApiFieldToGraphQL<Query['listCards']>
},Mutation: {
addCard: ApiFieldToGraphQL<Mutation['addCard']>
}
}

export declare const Zeus: {
Query: (o: GraphQLReturner<Query>) => string;
Mutation: (o: GraphQLReturner<Mutation>) => string;
};
Query: (o: GraphQLReturner<AliasType<Query>>) => string,Mutation: (o: GraphQLReturner<AliasType<Mutation>>) => string
}

export declare const Cast: {
Query: (o: any) => ResolveReturned<Query>;
Mutation: (o: any) => ResolveReturned<Mutation>;
};
Query: (o:any) => ResolveReturned<AliasType<Query>>,Mutation: (o:any) => ResolveReturned<AliasType<Mutation>>
}
60 changes: 40 additions & 20 deletions examples/javascript-node/src/graphql-zeus.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ export const AllTypesProps = {
}
},
createCard:{
skills:{
type:"SpecialSkills",
array:true,
arrayRequired:false,
required:true
},
name:{
type:"String",
array:false,
Expand Down Expand Up @@ -60,12 +66,6 @@ export const AllTypesProps = {
array:false,
arrayRequired:false,
required:true
},
skills:{
type:"SpecialSkills",
array:true,
arrayRequired:false,
required:true
}
}
}
Expand Down Expand Up @@ -216,7 +216,7 @@ export class GraphQLError extends Error {
const objectToTree = (o) =>
`{${Object.keys(o).map((k) => `${resolveKV(k, o[k])}`).join(' ')}}`;

const traverseToSeekArrays = (parent, a)=> {
const traverseToSeekArrays = (parent, a) => {
if (!a) return '';
if (Object.keys(a).length === 0) {
return '';
Expand All @@ -232,10 +232,9 @@ const traverseToSeekArrays = (parent, a)=> {
const aliasOperations = a[k][aliasKey];
const aliasOperationName = Object.keys(aliasOperations)[0];
const aliasOperation = aliasOperations[aliasOperationName];
b[`${aliasKey}: ${aliasOperationName}`] = traverseToSeekArrays(
[...parent, aliasOperationName],
aliasOperation
);
b[
`${aliasOperationName}__alias__${aliasKey}: ${aliasOperationName}`
] = traverseToSeekArrays([...parent, aliasOperationName], aliasOperation);
});
} else {
b[k] = traverseToSeekArrays([...parent, k], a[k]);
Expand All @@ -248,13 +247,38 @@ const traverseToSeekArrays = (parent, a)=> {
return objectToTree(b);
};


const buildQuery = (type, a) =>
traverseToSeekArrays([type], a).replace(/\"([^{^,^\n^\"]*)\":([^{^,^\n^\"]*)/g, '$1:$2');

const queryConstruct = (t) => (o) => `${t.toLowerCase()}${buildQuery(t, o)}`;

const fullChainConstruct = (options) => (t) => (o) => apiFetch(options, queryConstruct(t)(o));
const seekForAliases = (o) => {
if (typeof o === 'object' && o) {
const keys = Object.keys(o);
if (keys.length < 1) {
return;
}
keys.forEach((k) => {
const value = o[k];
if (k.indexOf('__alias__') !== -1) {
const [operation, alias] = k.split('__alias__');
o[alias] = {
[operation]: value
};
delete o[k];
} else {
if (Array.isArray(value)) {
value.forEach(seekForAliases);
} else {
if (typeof value === 'object') {
seekForAliases(value);
}
}
}
});
}
};

const apiFetch = (options, query, name) => {
let fetchFunction;
Expand All @@ -277,10 +301,8 @@ const apiFetch = (options, query, name) => {
if (response.errors) {
throw new GraphQLError(response);
}
if (!name) {
return response.data;
}
return response.data && response.data[name];
seekForAliases(response.data)
return response.data;
});
}
return fetchFunction(`${options[0]}`, {
Expand All @@ -296,10 +318,8 @@ const apiFetch = (options, query, name) => {
if (response.errors) {
throw new GraphQLError(response);
}
if (!name) {
return response.data;
}
return response.data && response.data[name];
seekForAliases(response.data)
return response.data;
});
};

Expand Down
Loading

0 comments on commit b518240

Please sign in to comment.