Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite internals + simplify decorators api
- Loading branch information
Showing
63 changed files
with
3,076 additions
and
726 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#CHANGELOG | ||
|
||
## 0.0.3 | ||
- move graphql to peerDependencies | ||
- upgrade dependencies | ||
|
||
## 0.4.0 | ||
- complete rewrite of internals | ||
- upgrade dependencies | ||
- remove `@args` and `@argsType` decorators in favor of `@params` and `@input`. [**Breaking change**] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# ROADMAP | ||
|
||
### Add support for inheritance | ||
- investigate possible pitfalls | ||
|
||
```typescript | ||
class PersistedObject { | ||
@id() | ||
id:string | ||
|
||
@field(CustomGraphQLDateScalar) | ||
createdAt:Date | ||
|
||
@field(CustomGraphQLDateScalar) | ||
updatedAt:Date | ||
} | ||
|
||
@type() | ||
class User extends PersistedObject {} | ||
``` | ||
|
||
should generate: | ||
|
||
```graphql | ||
type User { | ||
id: ID | ||
createdAt: CustomGraphQLDateScalar | ||
updateAt: CustomGraphQLDateScalar | ||
} | ||
``` | ||
|
||
### Infer basic types from ts metadata | ||
- investigate if it makes sense, because this feature would be very limited - only for couple of types. | ||
|
||
### Improve error handling and error messages | ||
- add assertions for all setters in fields metadata | ||
- add validation of field configuration | ||
- add more descriptive logs for all errors thrown from Metadata classes during native object creation | ||
- assert one metadata object is attached to class | ||
|
||
### Refactoring | ||
- use one convention for private fields | ||
- currently all metadata classes knows how to build graphql types - investigate if extracting this into separate "strategy like" classes makes sens | ||
- getOrCreateForClass and getForClass can be merged to one method | ||
```typescript | ||
class SomeMetadata { | ||
static getForClass(attachIfMissing:boolean = false){} | ||
} | ||
``` |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,47 @@ | ||
import {FieldConfig, FieldsMetadata} from "../metadata/FieldsMetadata"; | ||
import {invariant} from "../utils/core"; | ||
import * as _ from 'lodash'; | ||
import {GraphQLID} from "graphql"; | ||
import {ArgsType, FieldType} from "./typesInferention"; | ||
|
||
|
||
function patchField(target, propertyKey, partialConfig:Partial<FieldConfig>) { | ||
let fieldsMetadata:FieldsMetadata = FieldsMetadata.getOrCreateForClass(target.constructor); | ||
fieldsMetadata.patchConfig(propertyKey, partialConfig); | ||
} | ||
|
||
export const id = ():PropertyDecorator => { | ||
return (target:Object, propertyKey:string) => patchField(target, propertyKey, { | ||
type: GraphQLID | ||
}) | ||
}; | ||
|
||
export const field = (type:FieldType):PropertyDecorator => { | ||
invariant(!!type, `@field decorator called with undefined or null value`); | ||
return (target:Object, propertyKey:string) => patchField(target, propertyKey, {type}) | ||
}; | ||
|
||
export const fieldLazy = (thunkType:() => (FieldType)):PropertyDecorator => { | ||
invariant(_.isFunction(thunkType), `@fieldThunk decorator called with non function param`); | ||
return (target:Object, propertyKey:string) => patchField(target, propertyKey, {thunkType}) | ||
}; | ||
|
||
export const nonNull = ():PropertyDecorator => { | ||
return (target:Object, propertyKey:string) => patchField(target, propertyKey, {nonNull: true}) | ||
}; | ||
|
||
export const nonNullItems = ():PropertyDecorator => { | ||
return (target:Object, propertyKey:string) => patchField(target, propertyKey, {nonNullItem: true}) | ||
}; | ||
|
||
export const description = (description:string):PropertyDecorator => { | ||
return (target:Object, propertyKey:string) => patchField(target, propertyKey, {description}) | ||
}; | ||
|
||
export const args = (argsType:ArgsType):PropertyDecorator => { | ||
return (target:Object, propertyKey:string) => patchField(target, propertyKey, {args: argsType}) | ||
}; | ||
|
||
export const resolve = (resolve:Function):PropertyDecorator => { | ||
return (target:Object, propertyKey:string) => patchField(target, propertyKey, {resolve}) | ||
}; | ||
|
||
export const list = (type:FieldType):PropertyDecorator => { | ||
invariant(!!type, `@array decorator called with undefined or null value`); | ||
return (target:Object, propertyKey:string) => { | ||
patchField(target, propertyKey, { | ||
array: true, | ||
type | ||
}) | ||
} | ||
}; | ||
|
||
export const listLazy = (thunkType:() => FieldType):PropertyDecorator => { | ||
invariant(!!thunkType, `@arrayThunk decorator called with undefined or null value`); | ||
return (target:Object, propertyKey:string) => { | ||
patchField(target, propertyKey, { | ||
array: true, | ||
thunkType | ||
}) | ||
} | ||
}; | ||
import {GraphQLFieldResolver, GraphQLID} from "graphql"; | ||
import {FieldType} from "../types-conversion/TypeProxy"; | ||
import {ArgsType} from "../types-conversion/ArgumentsTypeProxy"; | ||
import {createFieldDecorator} from "./helpers"; | ||
|
||
export const id = ():PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setType(GraphQLID) | ||
}); | ||
|
||
export const field = (type:FieldType):PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setType(type); | ||
}); | ||
|
||
export const fieldThunk = (thunkType:() => (FieldType)):PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setTypeThunk(thunkType); | ||
}); | ||
|
||
export const nonNull = ():PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setNonNullConstraint() | ||
}); | ||
|
||
export const nonNullItems = ():PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setNonNullItemsConstraint() | ||
}); | ||
export const description = (description:string):PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setDescription(description) | ||
}); | ||
|
||
export const params = (argsType:ArgsType):PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setParamsType(argsType) | ||
}); | ||
|
||
export const paramsThunk = (argsType:() => ArgsType):PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setParamsThunk(argsType) | ||
}); | ||
|
||
export const resolve = <T>(resolve:GraphQLFieldResolver<any, any>):PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setResolver(resolve); | ||
}); | ||
|
||
export const list = (type:FieldType):PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setListType(type) | ||
}); | ||
|
||
export const listThunk = (thunkType:() => FieldType):PropertyDecorator => createFieldDecorator(fieldConfig => { | ||
fieldConfig.setListTypeThunk(thunkType) | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import {FieldsMetadata} from "../fields-metadata/FieldsMetadata"; | ||
import {FieldConfig} from "../fields-metadata/FieldConfig"; | ||
|
||
export function createFieldDecorator(updateFieldsMetadata:(fieldConfig:FieldConfig) => void):PropertyDecorator { | ||
return (target:Object, propertyKey:string) => { | ||
try { | ||
let meta = FieldsMetadata.getOrCreateForClass(target.constructor); | ||
updateFieldsMetadata(meta.getField(propertyKey)); | ||
} catch (e) { | ||
throw new Error(`Class: ${target.constructor.name}, property: ${propertyKey}. Error message: ${e.message}`) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,10 @@ | ||
import {Type as Klass} from "../utils/types"; | ||
import {InputConfig, InputObjectTypeMetadata} from "../metadata/InputObjectTypeMetadata"; | ||
import {ClassType as Klass} from "../utils/types"; | ||
import {InputConfig, ParamsMetadata} from "../types-metadata/ParamsMetadata"; | ||
|
||
|
||
export const input = (config:InputConfig = {}) => { | ||
export const input = (config:Partial<InputConfig> = {}) => { | ||
return <T_FUNCTION extends Klass<any>>(klass:T_FUNCTION):T_FUNCTION => { | ||
let inputMetadata = InputObjectTypeMetadata.getOrCreateForClass(klass); | ||
inputMetadata.setConfig(config); | ||
|
||
let paramsMetadata = ParamsMetadata.getOrCreateForClass(klass); | ||
paramsMetadata.setConfig(config); | ||
return klass; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,9 @@ | ||
import {InterfaceTypeMetadata, TypeConfig} from "../metadata/InterfaceTypeMetadata"; | ||
import {InterfaceTypeMetadata, InterfaceTypeConfig} from "../types-metadata/InterfaceTypeMetadata"; | ||
|
||
export const interfaceType = (config:TypeConfig<any, any> = {}):ClassDecorator => { | ||
export const interfaceType = (config:Partial<InterfaceTypeConfig> = {}):ClassDecorator => { | ||
return <TFunction extends Function>(klass:TFunction):TFunction => { | ||
let objectTypeMetadata = InterfaceTypeMetadata.getOrCreateForClass(klass); | ||
objectTypeMetadata.setConfig(config); | ||
|
||
return klass; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,9 @@ | ||
import {ObjectTypeMetadata, TypeConfig} from "../metadata/ObjectTypeMetadata"; | ||
import {TypeConfigParams, TypeMetadata} from "../types-metadata/TypeMetadata"; | ||
|
||
export const type = (config:TypeConfig<any, any> = {}):ClassDecorator => { | ||
export const type = (config:Partial<TypeConfigParams> = {}):ClassDecorator => { | ||
return <TFunction extends Function>(klass:TFunction):TFunction => { | ||
let objectTypeMetadata = ObjectTypeMetadata.getOrCreateForClass(klass); | ||
let objectTypeMetadata = TypeMetadata.getOrCreateForClass(klass); | ||
objectTypeMetadata.setConfig(config); | ||
|
||
return klass; | ||
}; | ||
}; |
Oops, something went wrong.