From 35335543850db28cde13dec4e8089f33d2063944 Mon Sep 17 00:00:00 2001 From: James Dibble Date: Wed, 23 Jul 2025 22:54:15 +0100 Subject: [PATCH] Project from an operation result --- LinQL.GraphQL.Client.Tests/QueryTests.cs | 20 +++++++++++++++++++ .../Translation/TranslationProviderTests.cs | 14 +++++++++++++ .../TranslationProviderTests.Project.snap | 13 ++++++++++++ ...iderTests.ProjectAcrossMultipleLevels.snap | 13 ++++++++++++ ...sts.ProjectSameOperationMultipleTimes.snap | 14 +++++++++++++ LinQL/SelectExtentions.cs | 10 ++++++++++ 6 files changed, 84 insertions(+) create mode 100644 LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.Project.snap create mode 100644 LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.ProjectAcrossMultipleLevels.snap create mode 100644 LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.ProjectSameOperationMultipleTimes.snap diff --git a/LinQL.GraphQL.Client.Tests/QueryTests.cs b/LinQL.GraphQL.Client.Tests/QueryTests.cs index eaa8f8f..5462cc7 100644 --- a/LinQL.GraphQL.Client.Tests/QueryTests.cs +++ b/LinQL.GraphQL.Client.Tests/QueryTests.cs @@ -42,6 +42,16 @@ public async Task TestSendQuery() result.Data.Should().Be(12345); } + [Fact] + public async Task TestSendProjectionQuery() + { + var result = await this.client.SendAsync((TestQuery q) => q.ExecuteEchoOperation("echo").Project(e => new { e.Echo, e.Number })); + + result.Errors.Should().BeNull(); + result.Data.Number.Should().Be(42); + result.Data.Echo.Should().Be("echo"); + } + [Fact] public async Task TestSendMutation() { @@ -60,8 +70,12 @@ public void Dispose() public class TestQueryType { public int GetNumber() => 12345; + + public TestObjectType EchoOperation(string toEcho) => new(toEcho, 42); } + public record TestObjectType(string Echo, int Number); + public class TestMutationType { public NumberResult SetNumber([GraphQLArgument(GQLType = "Int")] int input) => new() { Number = input }; @@ -79,6 +93,12 @@ public class TestQuery : RootType [GraphQLOperation, GraphQLField(Name = "number")] public int GetNumber() => this.Number; + + [GraphQLOperation, GraphQLField(Name = "echoOperation")] + public TestObjectType ExecuteEchoOperation([GraphQLArgument(GQLType = "String!")] string toEcho) + => this.EchoOperation; + + public TestObjectType EchoOperation { get; set; } } [OperationType(RootOperationType.Mutation)] diff --git a/LinQL.Tests/Translation/TranslationProviderTests.cs b/LinQL.Tests/Translation/TranslationProviderTests.cs index ebaa370..cdd0911 100644 --- a/LinQL.Tests/Translation/TranslationProviderTests.cs +++ b/LinQL.Tests/Translation/TranslationProviderTests.cs @@ -181,6 +181,8 @@ public void SelectInterfaceArrayMultipleTypesSelectAll() private record Projection(int Number, string? Text); + private record NestedProjection(float Float, Projection Projection); + [Fact] public void ProjectArrayOfInterface() => this.Test(x => x.ArrayOfInterfaces.Select(a => new Projection(a.Number, a.Text))); @@ -205,6 +207,18 @@ private void TestInclude(Expression> expression Snapshot.Match(request.Query); } + [Fact] + public void Project() + => this.Test(x => x.Operation.GetNumber("project me").Project(y => new Projection(y.Number, y.Text))); + + [Fact] + public void ProjectAcrossMultipleLevels() + => this.Test(x => new Projection(x.Number, x.Operation.GetNumber("project me").Project(y => y.Text))); + + [Fact] + public void ProjectSameOperationMultipleTimes() + => this.Test(x => new NestedProjection(x.Operation.Float, x.Operation.GetNumber("project me").Project(y => new Projection(y.Number, y.Text)))); + private void Test(Expression> expression) where TRoot : RootType => this.TestInclude(expression, _ => { }); diff --git a/LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.Project.snap b/LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.Project.snap new file mode 100644 index 0000000..7a3466c --- /dev/null +++ b/LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.Project.snap @@ -0,0 +1,13 @@ +query linql( + $var1: String! +) + { + operation { + getNumber( + value: $var1 + ) { + number + text + } + } +} diff --git a/LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.ProjectAcrossMultipleLevels.snap b/LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.ProjectAcrossMultipleLevels.snap new file mode 100644 index 0000000..dd77c15 --- /dev/null +++ b/LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.ProjectAcrossMultipleLevels.snap @@ -0,0 +1,13 @@ +query linql( + $var1: String! +) + { + number + operation { + getNumber( + value: $var1 + ) { + text + } + } +} diff --git a/LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.ProjectSameOperationMultipleTimes.snap b/LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.ProjectSameOperationMultipleTimes.snap new file mode 100644 index 0000000..b818a26 --- /dev/null +++ b/LinQL.Tests/Translation/__snapshots__/TranslationProviderTests.ProjectSameOperationMultipleTimes.snap @@ -0,0 +1,14 @@ +query linql( + $var1: String! +) + { + operation { + float + getNumber( + value: $var1 + ) { + number + text + } + } +} diff --git a/LinQL/SelectExtentions.cs b/LinQL/SelectExtentions.cs index 8e44ed6..deeab67 100644 --- a/LinQL/SelectExtentions.cs +++ b/LinQL/SelectExtentions.cs @@ -60,4 +60,14 @@ public static OneOf On(this OneOf th /// The type. /// The type. public static T SelectAll(this T that) => that; + + /// + /// Instruct the query to get all scalar fields on this type. + /// + /// The type to select from. + /// The type to project to. + /// The type. + /// The expression required to create from . + /// The projection. + public static TResult Project(this T that, Expression> projection) => projection.CompileFast()(that); }