Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ public NpgsqlJsonDomTranslator(
typeof(string),
_stringTypeMapping);

// The PostgreSQL traversal operator always returns text - for these scalar-returning methods, apply a conversion from string.
return method.Name == nameof(JsonElement.GetString)
? traversalToText
: ConvertFromText(traversalToText, method.ReturnType);
: _sqlExpressionFactory.Convert(
traversalToText, method.ReturnType, _typeMappingSource.FindMapping(method.ReturnType, _model));
}

if (method == GetArrayLength)
Expand All @@ -152,30 +154,4 @@ public NpgsqlJsonDomTranslator(

return null;
}

// The PostgreSQL traversal operator always returns text, so we need to convert to int, bool, etc.
private SqlExpression ConvertFromText(SqlExpression expression, Type returnType)
{
switch (Type.GetTypeCode(returnType))
{
case TypeCode.Boolean:
case TypeCode.Byte:
case TypeCode.DateTime:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.SByte:
case TypeCode.Single:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return _sqlExpressionFactory.Convert(expression, returnType, _typeMappingSource.FindMapping(returnType, _model));
default:
return returnType == typeof(Guid)
? _sqlExpressionFactory.Convert(expression, returnType, _typeMappingSource.FindMapping(returnType, _model))
: expression;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ public NpgsqlJsonPocoTranslator(
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual SqlExpression? TranslateMemberAccess(SqlExpression instance, SqlExpression member, Type returnType)
=> instance switch
{
return instance switch
{
// The first time we see a JSON traversal it's on a column - create a JsonTraversalExpression.
// Traversals on top of that get appended into the same expression.
Expand All @@ -119,6 +120,25 @@ PgJsonTraversalExpression prevPathTraversal
_ => null
};

// The PostgreSQL traversal operator always returns text.
// If the type returned is a scalar (int, bool, etc.), we need to apply a conversion from string.
SqlExpression ConvertFromText(SqlExpression expression, Type returnType)
=> _typeMappingSource.FindMapping(returnType.UnwrapNullableType(), _model) switch
{
// Type mapping not found - this isn't a scalar
null => expression,

// Arrays are dealt with as JSON arrays, not array scalars
NpgsqlArrayTypeMapping => expression,

// Text types don't a a conversion to string
{ StoreTypeNameBase: "text" or "varchar" or "char" } => expression,

// For any other type mapping, this is a scalar; apply a conversion to the type from string.
var mapping => _sqlExpressionFactory.Convert(expression, returnType, mapping)
};
}

/// <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
Expand Down Expand Up @@ -159,38 +179,4 @@ PgJsonTraversalExpression prevPathTraversal
return null;
}
}

// The PostgreSQL traversal operator always returns text, so we need to convert to int, bool, etc.
private SqlExpression ConvertFromText(SqlExpression expression, Type returnType)
{
var unwrappedReturnType = returnType.UnwrapNullableType();

switch (Type.GetTypeCode(unwrappedReturnType))
{
case TypeCode.Boolean:
case TypeCode.Byte:
case TypeCode.DateTime:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.SByte:
case TypeCode.Single:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return _sqlExpressionFactory.Convert(expression, returnType, _typeMappingSource.FindMapping(returnType, _model));
}

if (unwrappedReturnType == typeof(Guid)
|| unwrappedReturnType == typeof(DateTimeOffset)
|| unwrappedReturnType == typeof(DateOnly)
|| unwrappedReturnType == typeof(TimeOnly))
{
return _sqlExpressionFactory.Convert(expression, returnType, _typeMappingSource.FindMapping(returnType, _model));
}

return expression;
}
}