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 @@ -632,5 +632,15 @@ private readonly record struct Context(
private static bool ShouldReuseExistingInstance(Type type)
=> type.GetConstructor(Type.EmptyTypes) is not null
&& type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
.Any(t => t.GetParameters().Length > 0);
.Any(t =>
t.GetParameters().Length > 0
&& !IsRecordCopyConstructor(t, type));

private static bool IsRecordCopyConstructor(ConstructorInfo constructor, Type declaringType)
{
var parameters = constructor.GetParameters();

return parameters.Length == 1
&& parameters[0].ParameterType == declaringType;
}
}
72 changes: 72 additions & 0 deletions src/HotChocolate/Data/test/Data.Tests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,6 +1100,38 @@ name @include(if: $withName)
.Match();
}

[Fact]
public async Task QueryContext_Selector_For_Record_With_Init_Properties_Should_Not_Be_Identity()
{
// arrange
var capture = new QueryContextRecordSelectorCapture();
var executor = await new ServiceCollection()
.AddSingleton(capture)
.AddGraphQL()
.AddQueryContext()
.AddFiltering()
.AddSorting()
.AddQueryType<QueryContextRecordSelectorQuery>()
.BuildRequestExecutorAsync();

// act
var result = await executor.ExecuteAsync(
"""
{
recordSelector {
id
}
}
""");

// assert
var operationResult = result.ExpectOperationResult();
Assert.Empty(operationResult.Errors);
Assert.False(
capture.IsIdentitySelector,
$"Expected a projected selector but got identity selector: {capture.Selector}");
}

[Fact]
public async Task AsSortDefinition_QueryContext_Custom_Field_Without_Member_Does_Not_Fail()
{
Expand Down Expand Up @@ -1427,6 +1459,46 @@ public string Name
}
}

public sealed class QueryContextRecordSelectorCapture
{
public bool IsIdentitySelector { get; set; }

public string? Selector { get; set; }
}

public class QueryContextRecordSelectorQuery
{
public QueryContextRecordSelectorEntity GetRecordSelector(
QueryContext<QueryContextRecordSelectorEntity> query,
[Service] QueryContextRecordSelectorCapture capture)
{
var entity = new QueryContextRecordSelectorEntity
{
Id = Guid.NewGuid(),
FirstName = "A",
LastName = "B",
BirthDate = new DateOnly(2000, 1, 1)
};

capture.Selector = query.Selector?.ToString();
capture.IsIdentitySelector = query.Selector is not null
&& ReferenceEquals(query.Selector.Compile()(entity), entity);

return entity;
}
}

public sealed record QueryContextRecordSelectorEntity
{
public Guid Id { get; init; }

public string FirstName { get; init; } = string.Empty;

public string LastName { get; init; } = string.Empty;

public DateOnly BirthDate { get; init; }
}

public class QueryContextCustomSortQuery
{
[UseSorting(typeof(CustomSortBookSortType))]
Expand Down
Loading