Skip to content

Commit 238c933

Browse files
committed
Add ToFullString() method on QueryLayer and ResourceFieldAttribute
1 parent 27e3434 commit 238c933

File tree

4 files changed

+199
-14
lines changed

4 files changed

+199
-14
lines changed

src/JsonApiDotNetCore.Annotations/Resources/Annotations/ResourceFieldAttribute.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ protected void AssertIsIdentifiable(object? resource)
129129
return _publicName ?? (_property != null ? _property.Name : base.ToString());
130130
}
131131

132+
public string ToFullString()
133+
{
134+
return $"{_type?.PublicName}:{ToString()}";
135+
}
136+
132137
/// <inheritdoc />
133138
public override bool Equals(object? obj)
134139
{

src/JsonApiDotNetCore/Queries/FieldSelection.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,40 +34,51 @@ public FieldSelectors GetOrCreateSelectors(ResourceType resourceType)
3434
}
3535

3636
public override string ToString()
37+
{
38+
return InnerToString(false);
39+
}
40+
41+
public string ToFullString()
42+
{
43+
return InnerToString(true);
44+
}
45+
46+
private string InnerToString(bool toFullString)
3747
{
3848
var builder = new StringBuilder();
3949

4050
var writer = new IndentingStringWriter(builder);
41-
WriteSelection(writer);
51+
WriteSelection(writer, toFullString);
4252

4353
return builder.ToString();
4454
}
4555

46-
internal void WriteSelection(IndentingStringWriter writer)
56+
internal void WriteSelection(IndentingStringWriter writer, bool toFullString)
4757
{
4858
using (writer.Indent())
4959
{
5060
foreach (ResourceType type in GetResourceTypes())
5161
{
5262
writer.WriteLine($"{nameof(FieldSelectors)}<{type.ClrType.Name}>");
53-
WriterSelectors(writer, type);
63+
WriterSelectors(writer, toFullString, type);
5464
}
5565
}
5666
}
5767

58-
private void WriterSelectors(IndentingStringWriter writer, ResourceType type)
68+
private void WriterSelectors(IndentingStringWriter writer, bool toFullString, ResourceType type)
5969
{
6070
using (writer.Indent())
6171
{
6272
foreach ((ResourceFieldAttribute field, QueryLayer? nextLayer) in GetOrCreateSelectors(type))
6373
{
6474
if (nextLayer == null)
6575
{
66-
writer.WriteLine(field.ToString());
76+
writer.WriteLine(toFullString ? field.ToFullString() : field.ToString());
6777
}
6878
else
6979
{
70-
nextLayer.WriteLayer(writer, $"{field.PublicName}: ");
80+
string prefix = $"{(toFullString ? field.ToFullString() : field.ToString())}: ";
81+
nextLayer.WriteLayer(writer, toFullString, prefix);
7182
}
7283
}
7384
}

src/JsonApiDotNetCore/Queries/QueryLayer.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,45 +29,55 @@ public QueryLayer(ResourceType resourceType)
2929
}
3030

3131
public override string ToString()
32+
{
33+
return InnerToString(false);
34+
}
35+
36+
public string ToFullString()
37+
{
38+
return InnerToString(true);
39+
}
40+
41+
private string InnerToString(bool toFullString)
3242
{
3343
var builder = new StringBuilder();
3444

3545
var writer = new IndentingStringWriter(builder);
36-
WriteLayer(writer, null);
46+
WriteLayer(writer, toFullString, null);
3747

3848
return builder.ToString();
3949
}
4050

41-
internal void WriteLayer(IndentingStringWriter writer, string? prefix)
51+
internal void WriteLayer(IndentingStringWriter writer, bool toFullString, string? prefix)
4252
{
4353
writer.WriteLine($"{prefix}{nameof(QueryLayer)}<{ResourceType.ClrType.Name}>");
4454

4555
using (writer.Indent())
4656
{
4757
if (Include is { Elements.Count: > 0 })
4858
{
49-
writer.WriteLine($"{nameof(Include)}: {Include}");
59+
writer.WriteLine($"{nameof(Include)}: {(toFullString ? Include.ToFullString() : Include.ToString())}");
5060
}
5161

5262
if (Filter != null)
5363
{
54-
writer.WriteLine($"{nameof(Filter)}: {Filter}");
64+
writer.WriteLine($"{nameof(Filter)}: {(toFullString ? Filter.ToFullString() : Filter.ToString())}");
5565
}
5666

5767
if (Sort != null)
5868
{
59-
writer.WriteLine($"{nameof(Sort)}: {Sort}");
69+
writer.WriteLine($"{nameof(Sort)}: {(toFullString ? Sort.ToFullString() : Sort.ToString())}");
6070
}
6171

6272
if (Pagination != null)
6373
{
64-
writer.WriteLine($"{nameof(Pagination)}: {Pagination}");
74+
writer.WriteLine($"{nameof(Pagination)}: {(toFullString ? Pagination.ToFullString() : Pagination.ToString())}");
6575
}
6676

6777
if (Selection is { IsEmpty: false })
6878
{
6979
writer.WriteLine(nameof(Selection));
70-
Selection.WriteSelection(writer);
80+
Selection.WriteSelection(writer, toFullString);
7181
}
7282
}
7383
}

test/JsonApiDotNetCoreTests/UnitTests/Queries/QueryExpressionTests.cs

Lines changed: 160 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using FluentAssertions;
33
using JetBrains.Annotations;
44
using JsonApiDotNetCore.Configuration;
5+
using JsonApiDotNetCore.Queries;
56
using JsonApiDotNetCore.Queries.Expressions;
67
using JsonApiDotNetCore.Resources;
78
using JsonApiDotNetCore.Resources.Annotations;
@@ -179,6 +180,104 @@ public void Expressions_can_accept_visitor(QueryExpression left, QueryExpression
179180
right.Accept(EmptyQueryExpressionVisitor.Instance, null).Should().BeNull();
180181
}
181182

183+
[Fact]
184+
public void Can_convert_QueryLayer_to_string()
185+
{
186+
// Arrange
187+
QueryLayer queryLayer = TestQueryLayerFactory.Instance.Default();
188+
189+
// Act
190+
string text = queryLayer.ToString();
191+
192+
// Assert
193+
text.Should().Be("""
194+
QueryLayer<DerivedTestResource>
195+
{
196+
Include: parent.children
197+
Filter: and(contains(text,'example'),not(equals(text,'example')))
198+
Sort: -count(children)
199+
Pagination: Page number: 2, size: 5
200+
Selection
201+
{
202+
FieldSelectors<DerivedTestResource>
203+
{
204+
text
205+
parent: QueryLayer<DerivedTestResource>
206+
{
207+
Selection
208+
{
209+
FieldSelectors<DerivedTestResource>
210+
{
211+
text
212+
}
213+
}
214+
}
215+
children: QueryLayer<DerivedTestResource>
216+
{
217+
Selection
218+
{
219+
FieldSelectors<DerivedTestResource>
220+
{
221+
text
222+
}
223+
}
224+
}
225+
}
226+
}
227+
}
228+
229+
""");
230+
}
231+
232+
[Fact]
233+
public void Can_convert_QueryLayer_to_full_string()
234+
{
235+
// Arrange
236+
QueryLayer queryLayer = TestQueryLayerFactory.Instance.Default();
237+
238+
// Act
239+
string text = queryLayer.ToFullString();
240+
241+
// Assert
242+
text.Should().Be("""
243+
QueryLayer<DerivedTestResource>
244+
{
245+
Include: baseTestResources:parent.baseTestResources:children
246+
Filter: and(contains(baseTestResources:text,'example'),not(equals(baseTestResources:text,'example')))
247+
Sort: -count(baseTestResources:children)
248+
Pagination: Page number: 2, size: 5
249+
Selection
250+
{
251+
FieldSelectors<DerivedTestResource>
252+
{
253+
derivedTestResources:text
254+
derivedTestResources:parent: QueryLayer<DerivedTestResource>
255+
{
256+
Selection
257+
{
258+
FieldSelectors<DerivedTestResource>
259+
{
260+
derivedTestResources:text
261+
}
262+
}
263+
}
264+
derivedTestResources:children: QueryLayer<DerivedTestResource>
265+
{
266+
Selection
267+
{
268+
FieldSelectors<DerivedTestResource>
269+
{
270+
derivedTestResources:text
271+
}
272+
}
273+
}
274+
}
275+
}
276+
}
277+
278+
""");
279+
}
280+
182281
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
183282
private class BaseTestResource : Identifiable<Guid>
184283
{
@@ -202,6 +301,7 @@ private sealed class TestExpressionFactory
202301
private readonly AttrAttribute _textAttribute;
203302
private readonly RelationshipAttribute _parentRelationship;
204303
private readonly RelationshipAttribute _childrenRelationship;
304+
205305
public static TestExpressionFactory Instance { get; } = new();
206306

207307
private TestExpressionFactory()
@@ -262,7 +362,7 @@ public LiteralConstantExpression LiteralConstant()
262362

263363
public LogicalExpression Logical()
264364
{
265-
return new LogicalExpression(LogicalOperator.Or, Comparison(), MatchText());
365+
return new LogicalExpression(LogicalOperator.And, MatchText(), Not());
266366
}
267367

268368
public MatchTextExpression MatchText()
@@ -364,4 +464,63 @@ private EmptyQueryExpressionVisitor()
364464
{
365465
}
366466
}
467+
468+
private sealed class TestQueryLayerFactory
469+
{
470+
public static TestQueryLayerFactory Instance { get; } = new();
471+
472+
private TestQueryLayerFactory()
473+
{
474+
}
475+
476+
public QueryLayer Default()
477+
{
478+
var options = new JsonApiOptions();
479+
480+
var builder = new ResourceGraphBuilder(options, NullLoggerFactory.Instance);
481+
builder.Add<BaseTestResource, Guid>();
482+
builder.Add<DerivedTestResource, Guid>();
483+
IResourceGraph resourceGraph = builder.Build();
484+
485+
ResourceType resourceType = resourceGraph.GetResourceType<DerivedTestResource>();
486+
AttrAttribute textAttribute = resourceType.GetAttributeByPropertyName(nameof(DerivedTestResource.Text));
487+
RelationshipAttribute parentRelationship = resourceType.GetRelationshipByPropertyName(nameof(DerivedTestResource.Parent));
488+
RelationshipAttribute childrenRelationship = resourceType.GetRelationshipByPropertyName(nameof(DerivedTestResource.Children));
489+
490+
return new QueryLayer(resourceType)
491+
{
492+
Include = TestExpressionFactory.Instance.Include(),
493+
Filter = TestExpressionFactory.Instance.Logical(),
494+
Sort = TestExpressionFactory.Instance.Sort(),
495+
Pagination = TestExpressionFactory.Instance.Pagination(),
496+
Selection = new FieldSelection
497+
{
498+
[resourceType] = new FieldSelectors
499+
{
500+
[textAttribute] = null,
501+
[parentRelationship] = new QueryLayer(resourceType)
502+
{
503+
Selection = new FieldSelection
504+
{
505+
[resourceType] = new FieldSelectors
506+
{
507+
[textAttribute] = null
508+
}
509+
}
510+
},
511+
[childrenRelationship] = new QueryLayer(resourceType)
512+
{
513+
Selection = new FieldSelection
514+
{
515+
[resourceType] = new FieldSelectors
516+
{
517+
[textAttribute] = null
518+
}
519+
}
520+
}
521+
}
522+
}
523+
};
524+
}
525+
}
367526
}

0 commit comments

Comments
 (0)