Skip to content

Commit

Permalink
Refactor Generate(Type)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndriySvyryd committed Jul 8, 2024
1 parent 7cb0b4d commit d53a4fd
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 27 deletions.
8 changes: 8 additions & 0 deletions src/EFCore.Design/Properties/DesignStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/EFCore.Design/Properties/DesignStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,9 @@ Change your target project to the migrations project by using the Package Manage
<data name="UnableToScaffoldIndexMissingProperty" xml:space="preserve">
<value>Unable to scaffold the index '{indexName}'. The following columns could not be scaffolded: {columnNames}.</value>
</data>
<data name="UnableToTranslateType" xml:space="preserve">
<value>Unable to translate type '{type}'</value>
</data>
<data name="UncompilableProject" xml:space="preserve">
<value>The project '{project}' does not support compilation.</value>
</data>
Expand Down
87 changes: 60 additions & 27 deletions src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1307,131 +1307,164 @@ protected virtual IdentifierNameSyntax TranslateLabelTarget(LabelTarget labelTar
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected virtual TypeSyntax Generate(Type type)
=> TryGenerate(type, out var result)
? result
: throw new NotSupportedException(DesignStrings.UnableToTranslateType(type.DisplayName(fullName: false)));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected virtual bool TryGenerate(Type type, [NotNullWhen(true)] out TypeSyntax? result)
{
result = null;
if (type.IsAnonymousType())
{
return null!;
return false;
}

if (type.IsGenericType)
{
if (type.IsConstructedGenericType
&& type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return NullableType(Generate(type.GenericTypeArguments[0]));
result = NullableType(Generate(type.GenericTypeArguments[0]));
return true;
}

if (type.GenericTypeArguments.Any(t => t.IsAnonymousType()))
{
return null!;
return false;
}

var generic = GenericName(
Identifier(type.Name.Substring(0, type.Name.IndexOf('`'))),
TypeArgumentList(SeparatedList(type.GenericTypeArguments.Select(Generate))));
if (type.IsNested)
{
return QualifiedName(
result = QualifiedName(
(NameSyntax)Generate(type.DeclaringType!),
generic);
return true;
}

AddNamespace(type);

return generic;
result = generic;
return true;
}

if (type.IsArray)
{
return ArrayType(Generate(type.GetElementType()!))
result = ArrayType(Generate(type.GetElementType()!))
.WithRankSpecifiers(SingletonList(ArrayRankSpecifier(SingletonSeparatedList<ExpressionSyntax>(OmittedArraySizeExpression()))));
return true;
}

if (type == typeof(string))
{
return PredefinedType(Token(SyntaxKind.StringKeyword));
result = PredefinedType(Token(SyntaxKind.StringKeyword));
return true;
}

if (type == typeof(bool))
{
return PredefinedType(Token(SyntaxKind.BoolKeyword));
result = PredefinedType(Token(SyntaxKind.BoolKeyword));
return true;
}

if (type == typeof(byte))
{
return PredefinedType(Token(SyntaxKind.ByteKeyword));
result = PredefinedType(Token(SyntaxKind.ByteKeyword));
return true;
}

if (type == typeof(sbyte))
{
return PredefinedType(Token(SyntaxKind.SByteKeyword));
result = PredefinedType(Token(SyntaxKind.SByteKeyword));
return true;
}

if (type == typeof(int))
{
return PredefinedType(Token(SyntaxKind.IntKeyword));
result = PredefinedType(Token(SyntaxKind.IntKeyword));
return true;
}

if (type == typeof(uint))
{
return PredefinedType(Token(SyntaxKind.UIntKeyword));
result = PredefinedType(Token(SyntaxKind.UIntKeyword));
return true;
}

if (type == typeof(short))
{
return PredefinedType(Token(SyntaxKind.ShortKeyword));
result = PredefinedType(Token(SyntaxKind.ShortKeyword));
return true;
}

if (type == typeof(ushort))
{
return PredefinedType(Token(SyntaxKind.UShortKeyword));
result = PredefinedType(Token(SyntaxKind.UShortKeyword));
return true;
}

if (type == typeof(long))
{
return PredefinedType(Token(SyntaxKind.LongKeyword));
result = PredefinedType(Token(SyntaxKind.LongKeyword));
return true;
}

if (type == typeof(ulong))
{
return PredefinedType(Token(SyntaxKind.ULongKeyword));
result = PredefinedType(Token(SyntaxKind.ULongKeyword));
return true;
}

if (type == typeof(float))
{
return PredefinedType(Token(SyntaxKind.FloatKeyword));
result = PredefinedType(Token(SyntaxKind.FloatKeyword));
return true;
}

if (type == typeof(double))
{
return PredefinedType(Token(SyntaxKind.DoubleKeyword));
result = PredefinedType(Token(SyntaxKind.DoubleKeyword));
return true;
}

if (type == typeof(decimal))
{
return PredefinedType(Token(SyntaxKind.DecimalKeyword));
result = PredefinedType(Token(SyntaxKind.DecimalKeyword));
return true;
}

if (type == typeof(char))
{
return PredefinedType(Token(SyntaxKind.CharKeyword));
result = PredefinedType(Token(SyntaxKind.CharKeyword));
return true;
}

if (type == typeof(object))
{
return PredefinedType(Token(SyntaxKind.ObjectKeyword));
result = PredefinedType(Token(SyntaxKind.ObjectKeyword));
return true;
}

if (type == typeof(void))
{
return PredefinedType(Token(SyntaxKind.VoidKeyword));
result = PredefinedType(Token(SyntaxKind.VoidKeyword));
return true;
}

if (type.IsNested)
{
return QualifiedName(
result = QualifiedName(
(NameSyntax)Generate(type.DeclaringType!),
IdentifierName(type.Name));
return true;
}

if (type.IsNested)
Expand All @@ -1443,7 +1476,8 @@ protected virtual TypeSyntax Generate(Type type)
_collectedNamespaces.Add(type.Namespace);
}

return IdentifierName(type.Name);
result = IdentifierName(type.Name);
return true;
}

/// <inheritdoc />
Expand Down Expand Up @@ -1486,12 +1520,11 @@ protected override Expression VisitLambda<T>(Expression<T> lambda)
Result = ParenthesizedLambdaExpression(
attributeLists: List<AttributeListSyntax>(),
modifiers: TokenList(),
returnType: lambda.ReturnType == typeof(void) ? null : Generate(lambda.ReturnType),
returnType: lambda.ReturnType == typeof(void) || !TryGenerate(lambda.ReturnType, out var returnSyntax) ? null : returnSyntax,
ParameterList(
SeparatedList(
lambda.Parameters.Select(
p =>
Parameter(Identifier(LookupVariableName(p)))
p => Parameter(Identifier(LookupVariableName(p)))
.WithType(p.Type.IsAnonymousType() ? null : Generate(p.Type))))),
blockBody,
expressionBody);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
shadowCount: 5,
relationshipCount: 4,
storeGeneratedCount: 2);
runtimeEntityType.AddAnnotation("Cosmos:ContainerName", "Dependents");
runtimeEntityType.AddAnnotation("DiscriminatorMappingComplete", false);

Customize(runtimeEntityType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
shadowCount: 6,
relationshipCount: 4,
storeGeneratedCount: 2);
runtimeEntityType.AddAnnotation("DiscriminatorMappingComplete", false);

Customize(runtimeEntityType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ public virtual Task Basic_cosmos_model()
Assert.Equal([id, partitionId, blob, storeId, jObject, eTag], dataEntity.GetProperties());
});

protected override void BuildBigModel(ModelBuilder modelBuilder, bool jsonColumns)
{
base.BuildBigModel(modelBuilder, jsonColumns);

modelBuilder.Entity<DependentBase<byte?>>(
eb => eb.ToContainer("Dependents"));
modelBuilder.Entity<DependentDerived<byte?>>(
eb => eb.HasDiscriminator().IsComplete(false));
}

protected override void AssertBigModel(IModel model, bool jsonColumns)
{
base.AssertBigModel(model, jsonColumns);
Expand Down

0 comments on commit d53a4fd

Please sign in to comment.