Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve introspection support #83

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a9eaba3
Fix introspection result for enums. #47
MarianPalkus Jun 7, 2017
b69f557
[WIP] rewrite implementation of interfaces and union types. #47
MarianPalkus Jul 5, 2017
209a27a
[WIP] update implementation of graphql interfaces and union types. Re…
MarianPalkus Jul 6, 2017
eb6a0ff
[WIP]: fix handling of type conditions on non-abstract types. #47
MarianPalkus Jul 6, 2017
28bd998
Clean up.
MarianPalkus Jul 6, 2017
64cddcf
Increase max recursion depth to support full introspection query.
MarianPalkus Jul 6, 2017
32ff5de
Update uni test for introspection.
MarianPalkus Jul 6, 2017
a21cd33
[WIP] Contiune work in on full introspection support and fix issues r…
MarianPalkus Aug 22, 2017
9c4d9ee
Update project files to support mac os development.
MarianPalkus Aug 27, 2017
63d15af
Fix unit tests.
MarianPalkus Aug 27, 2017
48dd229
Fix unit tests.
MarianPalkus Aug 27, 2017
0373e39
Add star wars unit tests (according to tests of graphql-js implementa…
MarianPalkus Sep 3, 2017
f3468c9
Fix issue related to fields of type lists of scalar.
MarianPalkus Sep 3, 2017
7d1d388
Add star wars unit tests (according to tests of graphql-js implementa…
MarianPalkus Sep 3, 2017
c845928
Add more star wars unit tests.
MarianPalkus Sep 3, 2017
29977d9
Add more star wars unit tests.
MarianPalkus Sep 3, 2017
acf49e1
Update EF unit tests.
MarianPalkus Sep 3, 2017
9295ece
Make unit test green.
MarianPalkus Sep 14, 2017
21e6c17
Revert special handling of EF proxies in executor.
MarianPalkus Sep 14, 2017
7dbb076
[wip] start implementation of introspection mutation type.
MarianPalkus Sep 14, 2017
32809f4
Fix typo.
MarianPalkus Sep 18, 2017
192afd3
Fix unit tests assertion.
MarianPalkus Sep 18, 2017
2ad4c56
Fix EF unit test setup for star wars schema.
MarianPalkus Sep 18, 2017
d6bcda5
Updates docs/queries_and_mutations/inline-fragments.md
MarianPalkus Sep 19, 2017
d0e1e18
Updates schema-and-types/interfaces.md
MarianPalkus Sep 19, 2017
1627a47
Solved conflicts with docs version
MarianPalkus Sep 19, 2017
e291a23
Updates README.md
MarianPalkus Sep 19, 2017
e01201f
Merge e291a233493429248b7908218b7afad190089342 into introspection
MarianPalkus Sep 19, 2017
4f2345e
Updates docs/queries_and_mutations/changelog.md
MarianPalkus Sep 19, 2017
6787460
Updates docs/queries_and_mutations/inline-fragments.md
MarianPalkus Sep 19, 2017
efa1d5b
Updates schema-and-types/union-types.md
MarianPalkus Sep 19, 2017
8f48c83
Updates schema-and-types/union-types.md
MarianPalkus Sep 19, 2017
9810ea2
Add unit test for union type.
MarianPalkus Sep 19, 2017
e7bfd22
Merge branch 'introspection' of https://github.com/MarianPalkus/graph…
MarianPalkus Sep 19, 2017
6e77e59
Updates docs/queries_and_mutations/changelog.md
MarianPalkus Sep 19, 2017
d7ff330
Merge 6e77e59eb4f9d18c4029968e114446583fe91132 into introspection
MarianPalkus Sep 19, 2017
c72d436
Merge remote-tracking branch 'upstream/master' into introspection
MarianPalkus Oct 9, 2017
e1dbed9
Update schema API for union types.
MarianPalkus Nov 6, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 81 additions & 17 deletions GraphQL.Net/DynamicTypeBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using GraphQL.Parser;

namespace GraphQL.Net
{
Expand All @@ -17,45 +20,106 @@ static DynamicTypeBuilder()
ModuleBuilder = assemblyBuilder.DefineDynamicModule(AssemblyName + ".dll");
}

public static Type CreateDynamicType(string name, Dictionary<string, Type> properties)
public static Type CreateDynamicType(string name, IEnumerable<GraphQLField> fields)
{
var typeBuilder = ModuleBuilder.DefineType(AssemblyName + "." + name,
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Serializable | TypeAttributes.BeforeFieldInit);

var graphQlFields = fields as GraphQLField[] ?? fields.ToArray();
if (graphQlFields.Count() != graphQlFields.Select(f => f.Name).Distinct().Count())
{
var firstDuplicatedFieldName = graphQlFields.GroupBy(f => f.Name)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.FirstOrDefault();
throw new Exception("Duplicated field name '" + firstDuplicatedFieldName + "' on type '" + name + "'.");
}
var properties = ConvertFieldsToProperties(graphQlFields);
foreach (var prop in properties)
CreateProperty(typeBuilder, prop.Key, prop.Value);
return typeBuilder.CreateType();
}

private static void CreateProperty(TypeBuilder typeBuilder, string name, Type type)
public static Type CreateDynamicUnionTypeOrInterface(string name, IEnumerable<GraphQLField> fields,
IEnumerable<GraphQLType> possibleTypes, Func<string, string, string> createPossibleTypePropertyName)
{
var fieldBuilder = typeBuilder.DefineField("_" + name.ToLower(), type, FieldAttributes.Private);
var propertyBuilder = typeBuilder.DefineProperty(name, PropertyAttributes.HasDefault, type, null);
var typeBuilder = ModuleBuilder.DefineType(AssemblyName + "." + name,
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass |
TypeAttributes.Serializable | TypeAttributes.BeforeFieldInit);
// Create an union type containing all properties of its possible types.
// Prefix all properties of a possible type to avoid conflicts of property names
var subTypeProperties = possibleTypes
.SelectMany(
t => t.Fields.Select(f => new {Name = createPossibleTypePropertyName(t.Name, f.Name), Type = GetFieldPropertyType(f)}));
var properties =
subTypeProperties.Concat(fields.Select(f => new {Name = f.Name, Type = GetFieldPropertyType(f)}));
foreach (var prop in properties)
CreateProperty(typeBuilder, prop.Name, prop.Type);

propertyBuilder.SetGetMethod(CreateGetMethod(typeBuilder, fieldBuilder, name, type));
propertyBuilder.SetSetMethod(CreateSetMethod(typeBuilder, fieldBuilder, name, type));
return typeBuilder.CreateType();
}

private static Type GetFieldPropertyType(GraphQLField field)
{
return field.Type.TypeKind == TypeKind.SCALAR
? (field.IsList
? typeof(IEnumerable<>).MakeGenericType(field.Type.CLRType)
: TypeHelpers.MakeNullable(field.Type.CLRType))
: typeof(object);
}

private static IDictionary<string, Type> ConvertFieldsToProperties(IEnumerable<GraphQLField> fields)
{
return fields.Where(f => !f.IsPost).ToDictionary(f => f.Name, GetFieldPropertyType);
}

const MethodAttributes MethodAttrs = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
private static MethodBuilder CreateGetMethod(TypeBuilder typeBuilder, FieldInfo fieldBuilder, string name, Type type)
private static void CreateProperty(TypeBuilder typeBuilder, string name, Type type, bool isAbstract = false)
{
FieldBuilder fieldBuilder = null;
if (!isAbstract) {
fieldBuilder = typeBuilder.DefineField("_" + name.ToLower(), type, FieldAttributes.Private);
}
var propertyBuilder = typeBuilder.DefineProperty(name, PropertyAttributes.HasDefault, type, null);
propertyBuilder.SetGetMethod(CreateGetMethod(typeBuilder, fieldBuilder, name, type, isAbstract));
propertyBuilder.SetSetMethod(CreateSetMethod(typeBuilder, fieldBuilder, name, type, isAbstract));
}

const MethodAttributes MethodAttrs = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.HideBySig;

private static MethodBuilder CreateGetMethod(TypeBuilder typeBuilder, FieldInfo fieldBuilder, string name,
Type type, bool isAbstract)
{
if (isAbstract)
{
return typeBuilder.DefineMethod("get_" + name, MethodAttributes.Virtual | MethodAttributes.Abstract | MethodAttributes.Public, type, Type.EmptyTypes);
}

var methodBuilder = typeBuilder.DefineMethod("get_" + name, MethodAttrs, type, Type.EmptyTypes);
var generator = methodBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, fieldBuilder);
generator.Emit(OpCodes.Ret);

return methodBuilder;
}

private static MethodBuilder CreateSetMethod(TypeBuilder typeBuilder, FieldInfo fieldBuilder, string name, Type type)
private static MethodBuilder CreateSetMethod(TypeBuilder typeBuilder, FieldInfo fieldBuilder, string name, Type type,
bool isAbstract)
{
var methodBuilder = typeBuilder.DefineMethod("set" + name, MethodAttrs, null, new[] { type });
var generator = methodBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, fieldBuilder);
generator.Emit(OpCodes.Ret);

var attrs = MethodAttrs;
if (isAbstract)
{
attrs = attrs | MethodAttributes.Abstract | MethodAttributes.Virtual;
}
var methodBuilder = typeBuilder.DefineMethod("set" + name, attrs, null, new[] { type });
if (!isAbstract)
{
var generator = methodBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, fieldBuilder);
generator.Emit(OpCodes.Ret);
}
return methodBuilder;
}
}
Expand Down
Loading