diff --git a/src/Tgstation.Server.Host/Extensions/QueryContextExtensions.cs b/src/Tgstation.Server.Host/Extensions/QueryContextExtensions.cs
index cd8e9e2ed0..3a4bacb966 100644
--- a/src/Tgstation.Server.Host/Extensions/QueryContextExtensions.cs
+++ b/src/Tgstation.Server.Host/Extensions/QueryContextExtensions.cs
@@ -12,6 +12,48 @@ namespace Tgstation.Server.Host.Extensions
///
static class QueryContextExtensions
{
+ ///
+ /// Convert a to an equivalent one that operates on a given of the original .
+ ///
+ /// The parent .
+ /// The child .
+ /// The to transform.
+ /// A new for that is functionally identical to the original .
+ public static QueryContext UpcastFrom(this QueryContext queryContext)
+ where TChild : TParent
+ {
+ ArgumentNullException.ThrowIfNull(queryContext);
+
+ var parameter = Expression.Parameter(typeof(TChild), "child");
+ Expression>? selector = null;
+ if (queryContext.Selector != null)
+ {
+ Expression> upcast = parent => (TChild)parent!;
+ selector = Expression.Lambda>(
+ Expression.Invoke(
+ upcast,
+ Expression.Invoke(
+ queryContext.Selector,
+ parameter)),
+ parameter);
+ }
+
+ Expression>? predicate = null;
+ if (queryContext.Predicate != null)
+ predicate = Expression.Lambda>(
+ queryContext.Predicate,
+ parameter);
+
+ SortDefinition? sortDefinition = null;
+ if (queryContext.Sorting?.Operations.Length > 0)
+ throw new NotImplementedException();
+
+ return new QueryContext(
+ selector,
+ predicate,
+ sortDefinition);
+ }
+
///
/// Translate a given into one with the target wrapped in an .
///
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/User.cs b/src/Tgstation.Server.Host/GraphQL/Types/User.cs
index 8b6a08c5db..16917f1086 100644
--- a/src/Tgstation.Server.Host/GraphQL/Types/User.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Types/User.cs
@@ -127,7 +127,7 @@ namespace Tgstation.Server.Host.GraphQL.Types
/// The that created this , if any.
public async ValueTask CreatedBy(
[Service] IGraphQLAuthorityInvoker userAuthority,
- QueryContext? queryContext,
+ QueryContext? queryContext,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(userAuthority);
@@ -135,7 +135,7 @@ namespace Tgstation.Server.Host.GraphQL.Types
// This one is particular and cannot be data-loaded due to necessitating a different parameter
var user = await userAuthority.InvokeTransformable(
authority => authority.GetId(CreatedById, true, cancellationToken),
- queryContext);
+ queryContext?.UpcastFrom());
if (user == null)
throw new InvalidOperationException($"Query for created by of user ID {CreatedById} returned null!");