diff --git a/package-versions.props b/package-versions.props
index e77a2ae86b..cc85cee892 100644
--- a/package-versions.props
+++ b/package-versions.props
@@ -40,7 +40,6 @@
9.0.*
9.0.*
- 9.0.0-*
@@ -50,6 +49,5 @@
8.0.*
8.0.*
- $(EntityFrameworkCoreVersion)
diff --git a/src/Examples/DapperExample/DapperExample.csproj b/src/Examples/DapperExample/DapperExample.csproj
index ed7bd358eb..0685dc0343 100644
--- a/src/Examples/DapperExample/DapperExample.csproj
+++ b/src/Examples/DapperExample/DapperExample.csproj
@@ -16,6 +16,6 @@
-
+
diff --git a/src/Examples/DapperExample/TranslationToSql/Builders/SelectStatementBuilder.cs b/src/Examples/DapperExample/TranslationToSql/Builders/SelectStatementBuilder.cs
index 23a2b7d2d0..0a1e3b5a0d 100644
--- a/src/Examples/DapperExample/TranslationToSql/Builders/SelectStatementBuilder.cs
+++ b/src/Examples/DapperExample/TranslationToSql/Builders/SelectStatementBuilder.cs
@@ -552,7 +552,7 @@ public override SqlTreeNode VisitResourceFieldChain(ResourceFieldChainExpression
throw new JsonApiException(new ErrorObject(HttpStatusCode.BadRequest)
{
Title = "Sorting or filtering on the requested attribute is unavailable.",
- Detail = $"Sorting or filtering on attribute '{attribute.PublicName}' is unavailable because it is unmapped."
+ Detail = $"Sorting or filtering on attribute '{attribute}' is unavailable because it is unmapped."
});
}
diff --git a/src/JsonApiDotNetCore.Annotations/Resources/Annotations/ResourceFieldAttribute.cs b/src/JsonApiDotNetCore.Annotations/Resources/Annotations/ResourceFieldAttribute.cs
index 593b0a905d..6f54635827 100644
--- a/src/JsonApiDotNetCore.Annotations/Resources/Annotations/ResourceFieldAttribute.cs
+++ b/src/JsonApiDotNetCore.Annotations/Resources/Annotations/ResourceFieldAttribute.cs
@@ -129,6 +129,11 @@ protected void AssertIsIdentifiable(object? resource)
return _publicName ?? (_property != null ? _property.Name : base.ToString());
}
+ public string ToFullString()
+ {
+ return $"{_type?.PublicName}:{ToString()}";
+ }
+
///
public override bool Equals(object? obj)
{
diff --git a/src/JsonApiDotNetCore/Configuration/ResourceGraphBuilder.cs b/src/JsonApiDotNetCore/Configuration/ResourceGraphBuilder.cs
index 95365ed6a9..a10d6a904c 100644
--- a/src/JsonApiDotNetCore/Configuration/ResourceGraphBuilder.cs
+++ b/src/JsonApiDotNetCore/Configuration/ResourceGraphBuilder.cs
@@ -130,7 +130,7 @@ private static void ValidateAttributesInDerivedType(ResourceType resourceType)
if (resourceType.FindAttributeByPublicName(attribute.PublicName) == null)
{
throw new InvalidConfigurationException(
- $"Attribute '{attribute.PublicName}' from base type '{resourceType.BaseType.ClrType}' does not exist in derived type '{resourceType.ClrType}'.");
+ $"Attribute '{attribute}' from base type '{resourceType.BaseType.ClrType}' does not exist in derived type '{resourceType.ClrType}'.");
}
}
}
@@ -142,7 +142,7 @@ private static void ValidateRelationshipsInDerivedType(ResourceType resourceType
if (resourceType.FindRelationshipByPublicName(relationship.PublicName) == null)
{
throw new InvalidConfigurationException(
- $"Relationship '{relationship.PublicName}' from base type '{resourceType.BaseType.ClrType}' does not exist in derived type '{resourceType.ClrType}'.");
+ $"Relationship '{relationship}' from base type '{resourceType.BaseType.ClrType}' does not exist in derived type '{resourceType.ClrType}'.");
}
}
}
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/AnyExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/AnyExpression.cs
index 306a98d1aa..6b44b7d52f 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/AnyExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/AnyExpression.cs
@@ -56,9 +56,9 @@ private string InnerToString(bool toFullString)
builder.Append(Keywords.Any);
builder.Append('(');
- builder.Append(toFullString ? TargetAttribute.ToFullString() : TargetAttribute);
+ builder.Append(toFullString ? TargetAttribute.ToFullString() : TargetAttribute.ToString());
builder.Append(',');
- builder.Append(string.Join(",", Constants.Select(constant => toFullString ? constant.ToFullString() : constant.ToString()).OrderBy(value => value)));
+ builder.Append(string.Join(',', Constants.Select(constant => toFullString ? constant.ToFullString() : constant.ToString()).OrderBy(value => value)));
builder.Append(')');
return builder.ToString();
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/HasExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/HasExpression.cs
index 5c40039d4e..1d5f381a3b 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/HasExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/HasExpression.cs
@@ -58,12 +58,12 @@ private string InnerToString(bool toFullString)
var builder = new StringBuilder();
builder.Append(Keywords.Has);
builder.Append('(');
- builder.Append(toFullString ? TargetCollection.ToFullString() : TargetCollection);
+ builder.Append(toFullString ? TargetCollection.ToFullString() : TargetCollection.ToString());
if (Filter != null)
{
builder.Append(',');
- builder.Append(toFullString ? Filter.ToFullString() : Filter);
+ builder.Append(toFullString ? Filter.ToFullString() : Filter.ToString());
}
builder.Append(')');
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/IncludeElementExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/IncludeElementExpression.cs
index 9e98deefe3..3ee86e6ea2 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/IncludeElementExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/IncludeElementExpression.cs
@@ -57,12 +57,12 @@ public override string ToFullString()
private string InnerToString(bool toFullString)
{
var builder = new StringBuilder();
- builder.Append(toFullString ? $"{Relationship.LeftType.PublicName}:{Relationship.PublicName}" : Relationship.PublicName);
+ builder.Append(toFullString ? $"{Relationship.LeftType}:{Relationship}" : Relationship.ToString());
if (Children.Count > 0)
{
builder.Append('{');
- builder.Append(string.Join(",", Children.Select(child => toFullString ? child.ToFullString() : child.ToString()).OrderBy(name => name)));
+ builder.Append(string.Join(',', Children.Select(child => toFullString ? child.ToFullString() : child.ToString()).OrderBy(name => name)));
builder.Append('}');
}
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/IncludeExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/IncludeExpression.cs
index 50b152caf7..71d6bf84c2 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/IncludeExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/IncludeExpression.cs
@@ -50,7 +50,7 @@ public override string ToFullString()
private string InnerToString(bool toFullString)
{
IReadOnlyCollection chains = IncludeChainConverter.Instance.GetRelationshipChains(this);
- return string.Join(",", chains.Select(field => toFullString ? field.ToFullString() : field.ToString()).Distinct().OrderBy(name => name));
+ return string.Join(',', chains.Select(field => toFullString ? field.ToFullString() : field.ToString()).Distinct().OrderBy(name => name));
}
public override bool Equals(object? obj)
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/IsTypeExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/IsTypeExpression.cs
index e2f68ee8ec..b8d85c4f6f 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/IsTypeExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/IsTypeExpression.cs
@@ -71,7 +71,7 @@ private string InnerToString(bool toFullString)
if (TargetToOneRelationship != null)
{
- builder.Append(toFullString ? TargetToOneRelationship.ToFullString() : TargetToOneRelationship);
+ builder.Append(toFullString ? TargetToOneRelationship.ToFullString() : TargetToOneRelationship.ToString());
}
builder.Append(',');
@@ -80,7 +80,7 @@ private string InnerToString(bool toFullString)
if (Child != null)
{
builder.Append(',');
- builder.Append(toFullString ? Child.ToFullString() : Child);
+ builder.Append(toFullString ? Child.ToFullString() : Child.ToString());
}
builder.Append(')');
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/LogicalExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/LogicalExpression.cs
index 47af9f8b74..456526e4af 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/LogicalExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/LogicalExpression.cs
@@ -78,7 +78,7 @@ private string InnerToString(bool toFullString)
builder.Append(Operator.ToString().Camelize());
builder.Append('(');
- builder.Append(string.Join(",", Terms.Select(term => toFullString ? term.ToFullString() : term.ToString())));
+ builder.Append(string.Join(',', Terms.Select(term => toFullString ? term.ToFullString() : term.ToString())));
builder.Append(')');
return builder.ToString();
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/MatchTextExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/MatchTextExpression.cs
index 390940e9d1..96568b7a67 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/MatchTextExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/MatchTextExpression.cs
@@ -71,8 +71,8 @@ private string InnerToString(bool toFullString)
builder.Append('(');
builder.Append(toFullString
- ? string.Join(",", TargetAttribute.ToFullString(), TextValue.ToFullString())
- : string.Join(",", TargetAttribute, TextValue));
+ ? string.Join(',', TargetAttribute.ToFullString(), TextValue.ToFullString())
+ : string.Join(',', TargetAttribute.ToString(), TextValue.ToString()));
builder.Append(')');
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/PaginationQueryStringValueExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/PaginationQueryStringValueExpression.cs
index 2a70ea7d8c..70c3905136 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/PaginationQueryStringValueExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/PaginationQueryStringValueExpression.cs
@@ -32,12 +32,12 @@ public override TResult Accept(QueryExpressionVisitor element.ToString()));
+ return string.Join(',', Elements.Select(element => element.ToString()));
}
public override string ToFullString()
{
- return string.Join(",", Elements.Select(element => element.ToFullString()));
+ return string.Join(',', Elements.Select(element => element.ToFullString()));
}
public override bool Equals(object? obj)
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/ResourceFieldChainExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/ResourceFieldChainExpression.cs
index 35d5ecc4a1..a34872dc6b 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/ResourceFieldChainExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/ResourceFieldChainExpression.cs
@@ -45,12 +45,12 @@ public override TResult Accept(QueryExpressionVisitor field.PublicName));
+ return string.Join('.', Fields.Select(field => field.ToString()));
}
public override string ToFullString()
{
- return string.Join(".", Fields.Select(field => $"{field.Type.PublicName}:{field.PublicName}"));
+ return string.Join('.', Fields.Select(field => field.ToFullString()));
}
public override bool Equals(object? obj)
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/SortElementExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/SortElementExpression.cs
index 293c1d9c71..0270be01d8 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/SortElementExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/SortElementExpression.cs
@@ -59,7 +59,7 @@ private string InnerToString(bool toFullString)
builder.Append('-');
}
- builder.Append(toFullString ? Target.ToFullString() : Target);
+ builder.Append(toFullString ? Target.ToFullString() : Target.ToString());
return builder.ToString();
}
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/SortExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/SortExpression.cs
index d51ab6dff0..68033328aa 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/SortExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/SortExpression.cs
@@ -43,12 +43,12 @@ public override TResult Accept(QueryExpressionVisitor child.ToString()));
+ return string.Join(',', Elements.Select(child => child.ToString()));
}
public override string ToFullString()
{
- return $"{string.Join(",", Elements.Select(child => child.ToFullString()))}{(IsAutoGenerated ? " (auto-generated)" : "")}";
+ return $"{string.Join(',', Elements.Select(child => child.ToFullString()))}{(IsAutoGenerated ? " (auto-generated)" : "")}";
}
public override bool Equals(object? obj)
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/SparseFieldSetExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/SparseFieldSetExpression.cs
index e075c3f915..ddf11f2f0a 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/SparseFieldSetExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/SparseFieldSetExpression.cs
@@ -33,12 +33,12 @@ public override TResult Accept(QueryExpressionVisitor field.PublicName).OrderBy(name => name));
+ return string.Join(',', Fields.Select(field => field.ToString()).OrderBy(name => name));
}
public override string ToFullString()
{
- return string.Join(".", Fields.Select(field => $"{field.Type.PublicName}:{field.PublicName}").OrderBy(name => name));
+ return string.Join(',', Fields.Select(field => $"{field.ToFullString()}").OrderBy(name => name));
}
public override bool Equals(object? obj)
diff --git a/src/JsonApiDotNetCore/Queries/Expressions/SparseFieldTableExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/SparseFieldTableExpression.cs
index fc1e9fb88b..0c84ae956e 100644
--- a/src/JsonApiDotNetCore/Queries/Expressions/SparseFieldTableExpression.cs
+++ b/src/JsonApiDotNetCore/Queries/Expressions/SparseFieldTableExpression.cs
@@ -49,9 +49,9 @@ private string InnerToString(bool toFullString)
builder.Append(',');
}
- builder.Append(resourceType.PublicName);
+ builder.Append(resourceType);
builder.Append('(');
- builder.Append(toFullString ? fieldSet.ToFullString() : fieldSet);
+ builder.Append(toFullString ? fieldSet.ToFullString() : fieldSet.ToString());
builder.Append(')');
}
diff --git a/src/JsonApiDotNetCore/Queries/FieldSelection.cs b/src/JsonApiDotNetCore/Queries/FieldSelection.cs
index b929db2c80..4c7ba3c6e8 100644
--- a/src/JsonApiDotNetCore/Queries/FieldSelection.cs
+++ b/src/JsonApiDotNetCore/Queries/FieldSelection.cs
@@ -34,28 +34,38 @@ public FieldSelectors GetOrCreateSelectors(ResourceType resourceType)
}
public override string ToString()
+ {
+ return InnerToString(false);
+ }
+
+ public string ToFullString()
+ {
+ return InnerToString(true);
+ }
+
+ private string InnerToString(bool toFullString)
{
var builder = new StringBuilder();
var writer = new IndentingStringWriter(builder);
- WriteSelection(writer);
+ WriteSelection(writer, toFullString);
return builder.ToString();
}
- internal void WriteSelection(IndentingStringWriter writer)
+ internal void WriteSelection(IndentingStringWriter writer, bool toFullString)
{
using (writer.Indent())
{
foreach (ResourceType type in GetResourceTypes())
{
writer.WriteLine($"{nameof(FieldSelectors)}<{type.ClrType.Name}>");
- WriterSelectors(writer, type);
+ WriterSelectors(writer, toFullString, type);
}
}
}
- private void WriterSelectors(IndentingStringWriter writer, ResourceType type)
+ private void WriterSelectors(IndentingStringWriter writer, bool toFullString, ResourceType type)
{
using (writer.Indent())
{
@@ -63,11 +73,12 @@ private void WriterSelectors(IndentingStringWriter writer, ResourceType type)
{
if (nextLayer == null)
{
- writer.WriteLine(field.ToString());
+ writer.WriteLine(toFullString ? field.ToFullString() : field.ToString());
}
else
{
- nextLayer.WriteLayer(writer, $"{field.PublicName}: ");
+ string prefix = $"{(toFullString ? field.ToFullString() : field.ToString())}: ";
+ nextLayer.WriteLayer(writer, toFullString, prefix);
}
}
}
diff --git a/src/JsonApiDotNetCore/Queries/Parsing/FilterParser.cs b/src/JsonApiDotNetCore/Queries/Parsing/FilterParser.cs
index f89bf3dc39..914abd7802 100644
--- a/src/JsonApiDotNetCore/Queries/Parsing/FilterParser.cs
+++ b/src/JsonApiDotNetCore/Queries/Parsing/FilterParser.cs
@@ -452,7 +452,7 @@ private static ResourceType ResolveDerivedType(ResourceType baseType, string der
if (derivedType == null)
{
- throw new QueryParseException($"Resource type '{derivedTypeName}' does not exist or does not derive from '{baseType.PublicName}'.", position);
+ throw new QueryParseException($"Resource type '{derivedTypeName}' does not exist or does not derive from '{baseType}'.", position);
}
return derivedType;
@@ -571,7 +571,7 @@ protected override void ValidateField(ResourceFieldAttribute field, int position
if (field.IsFilterBlocked())
{
string kind = field is AttrAttribute ? "attribute" : "relationship";
- throw new QueryParseException($"Filtering on {kind} '{field.PublicName}' is not allowed.", position);
+ throw new QueryParseException($"Filtering on {kind} '{field}' is not allowed.", position);
}
}
diff --git a/src/JsonApiDotNetCore/Queries/Parsing/SortParser.cs b/src/JsonApiDotNetCore/Queries/Parsing/SortParser.cs
index e8df9b4a88..814a3e4c9e 100644
--- a/src/JsonApiDotNetCore/Queries/Parsing/SortParser.cs
+++ b/src/JsonApiDotNetCore/Queries/Parsing/SortParser.cs
@@ -142,7 +142,7 @@ protected override void ValidateField(ResourceFieldAttribute field, int position
if (field is AttrAttribute attribute && !attribute.Capabilities.HasFlag(AttrCapabilities.AllowSort))
{
- throw new QueryParseException($"Sorting on attribute '{attribute.PublicName}' is not allowed.", position);
+ throw new QueryParseException($"Sorting on attribute '{attribute}' is not allowed.", position);
}
}
}
diff --git a/src/JsonApiDotNetCore/Queries/Parsing/SparseFieldSetParser.cs b/src/JsonApiDotNetCore/Queries/Parsing/SparseFieldSetParser.cs
index 9bf6a89daa..fb49e9c1dd 100644
--- a/src/JsonApiDotNetCore/Queries/Parsing/SparseFieldSetParser.cs
+++ b/src/JsonApiDotNetCore/Queries/Parsing/SparseFieldSetParser.cs
@@ -55,7 +55,7 @@ protected override void ValidateField(ResourceFieldAttribute field, int position
if (field.IsViewBlocked())
{
string kind = field is AttrAttribute ? "attribute" : "relationship";
- throw new QueryParseException($"Retrieving the {kind} '{field.PublicName}' is not allowed.", position);
+ throw new QueryParseException($"Retrieving the {kind} '{field}' is not allowed.", position);
}
}
}
diff --git a/src/JsonApiDotNetCore/Queries/QueryLayer.cs b/src/JsonApiDotNetCore/Queries/QueryLayer.cs
index 49a9ee92a2..adc4ad2b09 100644
--- a/src/JsonApiDotNetCore/Queries/QueryLayer.cs
+++ b/src/JsonApiDotNetCore/Queries/QueryLayer.cs
@@ -29,16 +29,26 @@ public QueryLayer(ResourceType resourceType)
}
public override string ToString()
+ {
+ return InnerToString(false);
+ }
+
+ public string ToFullString()
+ {
+ return InnerToString(true);
+ }
+
+ private string InnerToString(bool toFullString)
{
var builder = new StringBuilder();
var writer = new IndentingStringWriter(builder);
- WriteLayer(writer, null);
+ WriteLayer(writer, toFullString, null);
return builder.ToString();
}
- internal void WriteLayer(IndentingStringWriter writer, string? prefix)
+ internal void WriteLayer(IndentingStringWriter writer, bool toFullString, string? prefix)
{
writer.WriteLine($"{prefix}{nameof(QueryLayer)}<{ResourceType.ClrType.Name}>");
@@ -46,28 +56,28 @@ internal void WriteLayer(IndentingStringWriter writer, string? prefix)
{
if (Include is { Elements.Count: > 0 })
{
- writer.WriteLine($"{nameof(Include)}: {Include}");
+ writer.WriteLine($"{nameof(Include)}: {(toFullString ? Include.ToFullString() : Include.ToString())}");
}
if (Filter != null)
{
- writer.WriteLine($"{nameof(Filter)}: {Filter}");
+ writer.WriteLine($"{nameof(Filter)}: {(toFullString ? Filter.ToFullString() : Filter.ToString())}");
}
if (Sort != null)
{
- writer.WriteLine($"{nameof(Sort)}: {Sort}");
+ writer.WriteLine($"{nameof(Sort)}: {(toFullString ? Sort.ToFullString() : Sort.ToString())}");
}
if (Pagination != null)
{
- writer.WriteLine($"{nameof(Pagination)}: {Pagination}");
+ writer.WriteLine($"{nameof(Pagination)}: {(toFullString ? Pagination.ToFullString() : Pagination.ToString())}");
}
if (Selection is { IsEmpty: false })
{
writer.WriteLine(nameof(Selection));
- Selection.WriteSelection(writer);
+ Selection.WriteSelection(writer, toFullString);
}
}
}
diff --git a/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceIdentityAdapter.cs b/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceIdentityAdapter.cs
index d0def4e9cd..27b870edba 100644
--- a/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceIdentityAdapter.cs
+++ b/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceIdentityAdapter.cs
@@ -86,8 +86,8 @@ private static void AssertIsCompatibleResourceType(ResourceType actual, Resource
if (expected != null && !expected.ClrType.IsAssignableFrom(actual.ClrType))
{
string message = relationshipName != null
- ? $"Type '{actual.PublicName}' is not convertible to type '{expected.PublicName}' of relationship '{relationshipName}'."
- : $"Type '{actual.PublicName}' is not convertible to type '{expected.PublicName}'.";
+ ? $"Type '{actual}' is not convertible to type '{expected}' of relationship '{relationshipName}'."
+ : $"Type '{actual}' is not convertible to type '{expected}'.";
throw new ModelConversionException(state.Position, "Incompatible resource type found.", message, HttpStatusCode.Conflict);
}
@@ -245,7 +245,7 @@ protected static void AssertIsKnownRelationship([NotNull] RelationshipAttribute?
if (relationship == null)
{
throw new ModelConversionException(state.Position, "Unknown relationship found.",
- $"Relationship '{relationshipName}' does not exist on resource type '{resourceType.PublicName}'.");
+ $"Relationship '{relationshipName}' does not exist on resource type '{resourceType}'.");
}
}
@@ -262,7 +262,7 @@ protected internal static void AssertToManyInAddOrRemoveRelationship(Relationshi
? "Only to-many relationships can be targeted through this operation."
: "Only to-many relationships can be targeted through this endpoint.";
- throw new ModelConversionException(state.Position, message, $"Relationship '{relationship.PublicName}' is not a to-many relationship.",
+ throw new ModelConversionException(state.Position, message, $"Relationship '{relationship}' is not a to-many relationship.",
HttpStatusCode.Forbidden);
}
}
@@ -294,7 +294,7 @@ private static void AssertSetRelationshipNotBlocked(RelationshipAttribute relati
if (relationship.IsSetBlocked())
{
throw new ModelConversionException(state.Position, "Relationship cannot be assigned.",
- $"The relationship '{relationship.PublicName}' on resource type '{relationship.LeftType.PublicName}' cannot be assigned to.");
+ $"The relationship '{relationship}' on resource type '{relationship.LeftType}' cannot be assigned to.");
}
}
@@ -303,7 +303,7 @@ private static void AssertAddToRelationshipNotBlocked(HasManyAttribute relations
if (!relationship.Capabilities.HasFlag(HasManyCapabilities.AllowAdd))
{
throw new ModelConversionException(state.Position, "Relationship cannot be added to.",
- $"The relationship '{relationship.PublicName}' on resource type '{relationship.LeftType.PublicName}' cannot be added to.");
+ $"The relationship '{relationship}' on resource type '{relationship.LeftType}' cannot be added to.");
}
}
@@ -312,7 +312,7 @@ private static void AssertRemoveFromRelationshipNotBlocked(HasManyAttribute rela
if (!relationship.Capabilities.HasFlag(HasManyCapabilities.AllowRemove))
{
throw new ModelConversionException(state.Position, "Relationship cannot be removed from.",
- $"The relationship '{relationship.PublicName}' on resource type '{relationship.LeftType.PublicName}' cannot be removed from.");
+ $"The relationship '{relationship}' on resource type '{relationship.LeftType}' cannot be removed from.");
}
}
}
diff --git a/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceObjectAdapter.cs b/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceObjectAdapter.cs
index 5f9b4dd05c..71fafe7363 100644
--- a/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceObjectAdapter.cs
+++ b/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceObjectAdapter.cs
@@ -76,7 +76,7 @@ private static void AssertIsKnownAttribute([NotNull] AttrAttribute? attr, string
if (attr == null)
{
throw new ModelConversionException(state.Position, "Unknown attribute found.",
- $"Attribute '{attributeName}' does not exist on resource type '{resourceType.PublicName}'.");
+ $"Attribute '{attributeName}' does not exist on resource type '{resourceType}'.");
}
}
@@ -101,7 +101,7 @@ private static void AssertSetAttributeInCreateResourceNotBlocked(AttrAttribute a
if (state.Request.WriteOperation == WriteOperationKind.CreateResource && !attr.Capabilities.HasFlag(AttrCapabilities.AllowCreate))
{
throw new ModelConversionException(state.Position, "Attribute value cannot be assigned when creating resource.",
- $"The attribute '{attr.PublicName}' on resource type '{resourceType.PublicName}' cannot be assigned to.");
+ $"The attribute '{attr}' on resource type '{resourceType}' cannot be assigned to.");
}
}
@@ -110,7 +110,7 @@ private static void AssertSetAttributeInUpdateResourceNotBlocked(AttrAttribute a
if (state.Request.WriteOperation == WriteOperationKind.UpdateResource && !attr.Capabilities.HasFlag(AttrCapabilities.AllowChange))
{
throw new ModelConversionException(state.Position, "Attribute value cannot be assigned when updating resource.",
- $"The attribute '{attr.PublicName}' on resource type '{resourceType.PublicName}' cannot be assigned to.");
+ $"The attribute '{attr}' on resource type '{resourceType}' cannot be assigned to.");
}
}
@@ -119,7 +119,7 @@ private static void AssertNotReadOnly(AttrAttribute attr, ResourceType resourceT
if (attr.Property.SetMethod == null)
{
throw new ModelConversionException(state.Position, "Attribute is read-only.",
- $"Attribute '{attr.PublicName}' on resource type '{resourceType.PublicName}' is read-only.");
+ $"Attribute '{attr}' on resource type '{resourceType}' is read-only.");
}
}
diff --git a/src/JsonApiDotNetCore/Serialization/Response/ResourceObjectTreeNode.cs b/src/JsonApiDotNetCore/Serialization/Response/ResourceObjectTreeNode.cs
index 2ded4ae896..7417adc6ff 100644
--- a/src/JsonApiDotNetCore/Serialization/Response/ResourceObjectTreeNode.cs
+++ b/src/JsonApiDotNetCore/Serialization/Response/ResourceObjectTreeNode.cs
@@ -244,7 +244,7 @@ public override string ToString()
}
else if (_childrenByRelationship != null)
{
- builder.Append($", children: {string.Join(',', _childrenByRelationship.Select(pair => $"{pair.Key.PublicName} ({pair.Value.Count})"))}");
+ builder.Append($", children: {string.Join(',', _childrenByRelationship.Select(pair => $"{pair.Key} ({pair.Value.Count})"))}");
}
return builder.ToString();
diff --git a/test/DapperTests/IntegrationTests/QueryStrings/IncludeTests.cs b/test/DapperTests/IntegrationTests/QueryStrings/IncludeTests.cs
index 84625b463f..0aa63dff83 100644
--- a/test/DapperTests/IntegrationTests/QueryStrings/IncludeTests.cs
+++ b/test/DapperTests/IntegrationTests/QueryStrings/IncludeTests.cs
@@ -79,8 +79,8 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
value.Should().NotBeNull();
value.Data.ManyValue.Should().HaveCount(2);
value.Data.ManyValue.Should().AllSatisfy(resource => resource.Type.Should().Be("tags"));
- value.Data.ManyValue[0].Id.Should().Be(todoItems[0].Tags.ElementAt(0).StringId);
- value.Data.ManyValue[1].Id.Should().Be(todoItems[0].Tags.ElementAt(1).StringId);
+ value.Data.ManyValue.Should().ContainSingle(resource => resource.Id == todoItems[0].Tags.ElementAt(0).StringId);
+ value.Data.ManyValue.Should().ContainSingle(resource => resource.Id == todoItems[0].Tags.ElementAt(1).StringId);
});
});
@@ -109,8 +109,8 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
value.Should().NotBeNull();
value.Data.ManyValue.Should().HaveCount(2);
value.Data.ManyValue.Should().AllSatisfy(resource => resource.Type.Should().Be("tags"));
- value.Data.ManyValue[0].Id.Should().Be(todoItems[1].Tags.ElementAt(0).StringId);
- value.Data.ManyValue[1].Id.Should().Be(todoItems[1].Tags.ElementAt(1).StringId);
+ value.Data.ManyValue.Should().ContainSingle(resource => resource.Id == todoItems[1].Tags.ElementAt(0).StringId);
+ value.Data.ManyValue.Should().ContainSingle(resource => resource.Id == todoItems[1].Tags.ElementAt(1).StringId);
});
});
diff --git a/test/DapperTests/IntegrationTests/ReadWrite/Relationships/FetchRelationshipTests.cs b/test/DapperTests/IntegrationTests/ReadWrite/Relationships/FetchRelationshipTests.cs
index 961f4e9f9c..eeb2c3e786 100644
--- a/test/DapperTests/IntegrationTests/ReadWrite/Relationships/FetchRelationshipTests.cs
+++ b/test/DapperTests/IntegrationTests/ReadWrite/Relationships/FetchRelationshipTests.cs
@@ -141,8 +141,8 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
responseDocument.Data.ManyValue.Should().HaveCount(2);
responseDocument.Data.ManyValue.Should().AllSatisfy(resource => resource.Type.Should().Be("tags"));
- responseDocument.Data.ManyValue[0].Id.Should().Be(todoItem.Tags.ElementAt(0).StringId);
- responseDocument.Data.ManyValue[1].Id.Should().Be(todoItem.Tags.ElementAt(1).StringId);
+ responseDocument.Data.ManyValue.Should().ContainSingle(resource => resource.Id == todoItem.Tags.ElementAt(0).StringId);
+ responseDocument.Data.ManyValue.Should().ContainSingle(resource => resource.Id == todoItem.Tags.ElementAt(1).StringId);
responseDocument.Meta.Should().ContainTotal(2);
diff --git a/test/JsonApiDotNetCoreTests/UnitTests/Queries/QueryExpressionTests.cs b/test/JsonApiDotNetCoreTests/UnitTests/Queries/QueryExpressionTests.cs
index c8ed8ec3f9..5b0ae957af 100644
--- a/test/JsonApiDotNetCoreTests/UnitTests/Queries/QueryExpressionTests.cs
+++ b/test/JsonApiDotNetCoreTests/UnitTests/Queries/QueryExpressionTests.cs
@@ -2,6 +2,7 @@
using FluentAssertions;
using JetBrains.Annotations;
using JsonApiDotNetCore.Configuration;
+using JsonApiDotNetCore.Queries;
using JsonApiDotNetCore.Queries.Expressions;
using JsonApiDotNetCore.Resources;
using JsonApiDotNetCore.Resources.Annotations;
@@ -179,6 +180,104 @@ public void Expressions_can_accept_visitor(QueryExpression left, QueryExpression
right.Accept(EmptyQueryExpressionVisitor.Instance, null).Should().BeNull();
}
+ [Fact]
+ public void Can_convert_QueryLayer_to_string()
+ {
+ // Arrange
+ QueryLayer queryLayer = TestQueryLayerFactory.Instance.Default();
+
+ // Act
+ string text = queryLayer.ToString();
+
+ // Assert
+ text.Should().Be("""
+ QueryLayer
+ {
+ Include: parent.children
+ Filter: and(contains(text,'example'),not(equals(text,'example')))
+ Sort: -count(children)
+ Pagination: Page number: 2, size: 5
+ Selection
+ {
+ FieldSelectors
+ {
+ text
+ parent: QueryLayer
+ {
+ Selection
+ {
+ FieldSelectors
+ {
+ text
+ }
+ }
+ }
+ children: QueryLayer
+ {
+ Selection
+ {
+ FieldSelectors
+ {
+ text
+ }
+ }
+ }
+ }
+ }
+ }
+
+ """);
+ }
+
+ [Fact]
+ public void Can_convert_QueryLayer_to_full_string()
+ {
+ // Arrange
+ QueryLayer queryLayer = TestQueryLayerFactory.Instance.Default();
+
+ // Act
+ string text = queryLayer.ToFullString();
+
+ // Assert
+ text.Should().Be("""
+ QueryLayer
+ {
+ Include: baseTestResources:parent.baseTestResources:children
+ Filter: and(contains(baseTestResources:text,'example'),not(equals(baseTestResources:text,'example')))
+ Sort: -count(baseTestResources:children)
+ Pagination: Page number: 2, size: 5
+ Selection
+ {
+ FieldSelectors
+ {
+ derivedTestResources:text
+ derivedTestResources:parent: QueryLayer
+ {
+ Selection
+ {
+ FieldSelectors
+ {
+ derivedTestResources:text
+ }
+ }
+ }
+ derivedTestResources:children: QueryLayer
+ {
+ Selection
+ {
+ FieldSelectors
+ {
+ derivedTestResources:text
+ }
+ }
+ }
+ }
+ }
+ }
+
+ """);
+ }
+
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
private class BaseTestResource : Identifiable
{
@@ -202,6 +301,7 @@ private sealed class TestExpressionFactory
private readonly AttrAttribute _textAttribute;
private readonly RelationshipAttribute _parentRelationship;
private readonly RelationshipAttribute _childrenRelationship;
+
public static TestExpressionFactory Instance { get; } = new();
private TestExpressionFactory()
@@ -262,7 +362,7 @@ public LiteralConstantExpression LiteralConstant()
public LogicalExpression Logical()
{
- return new LogicalExpression(LogicalOperator.Or, Comparison(), MatchText());
+ return new LogicalExpression(LogicalOperator.And, MatchText(), Not());
}
public MatchTextExpression MatchText()
@@ -364,4 +464,63 @@ private EmptyQueryExpressionVisitor()
{
}
}
+
+ private sealed class TestQueryLayerFactory
+ {
+ public static TestQueryLayerFactory Instance { get; } = new();
+
+ private TestQueryLayerFactory()
+ {
+ }
+
+ public QueryLayer Default()
+ {
+ var options = new JsonApiOptions();
+
+ var builder = new ResourceGraphBuilder(options, NullLoggerFactory.Instance);
+ builder.Add();
+ builder.Add();
+ IResourceGraph resourceGraph = builder.Build();
+
+ ResourceType resourceType = resourceGraph.GetResourceType();
+ AttrAttribute textAttribute = resourceType.GetAttributeByPropertyName(nameof(DerivedTestResource.Text));
+ RelationshipAttribute parentRelationship = resourceType.GetRelationshipByPropertyName(nameof(DerivedTestResource.Parent));
+ RelationshipAttribute childrenRelationship = resourceType.GetRelationshipByPropertyName(nameof(DerivedTestResource.Children));
+
+ return new QueryLayer(resourceType)
+ {
+ Include = TestExpressionFactory.Instance.Include(),
+ Filter = TestExpressionFactory.Instance.Logical(),
+ Sort = TestExpressionFactory.Instance.Sort(),
+ Pagination = TestExpressionFactory.Instance.Pagination(),
+ Selection = new FieldSelection
+ {
+ [resourceType] = new FieldSelectors
+ {
+ [textAttribute] = null,
+ [parentRelationship] = new QueryLayer(resourceType)
+ {
+ Selection = new FieldSelection
+ {
+ [resourceType] = new FieldSelectors
+ {
+ [textAttribute] = null
+ }
+ }
+ },
+ [childrenRelationship] = new QueryLayer(resourceType)
+ {
+ Selection = new FieldSelection
+ {
+ [resourceType] = new FieldSelectors
+ {
+ [textAttribute] = null
+ }
+ }
+ }
+ }
+ }
+ };
+ }
+ }
}