Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query tweaks #1257

Merged
merged 14 commits into from Mar 11, 2023
Merged

Query tweaks #1257

merged 14 commits into from Mar 11, 2023

Conversation

bkoelman
Copy link
Member

@bkoelman bkoelman commented Feb 16, 2023

Minor changes in the QueryExpression model shape, to make it easier to understand and consume. And a few other small changes. See the individual commits for details.

QUALITY CHECKLIST

@codecov
Copy link

codecov bot commented Feb 16, 2023

Codecov Report

Merging #1257 (81c55d0) into master (2732109) will decrease coverage by 0.01%.
The diff coverage is 97.40%.

❗ Current head 81c55d0 differs from pull request most recent head 039ee72. Consider uploading reports for the commit 039ee72 to get more accurate results

@@            Coverage Diff             @@
##           master    #1257      +/-   ##
==========================================
- Coverage   92.69%   92.69%   -0.01%     
==========================================
  Files         243      243              
  Lines        7814     7813       -1     
==========================================
- Hits         7243     7242       -1     
  Misses        571      571              
Impacted Files Coverage Δ
...iDotNetCore/Middleware/JsonApiRoutingConvention.cs 92.75% <75.00%> (ø)
...e/Queries/Expressions/LiteralConstantExpression.cs 75.00% <91.66%> (+6.25%) ⬆️
...e/Configuration/ResourceDescriptorAssemblyCache.cs 100.00% <100.00%> (ø)
...ApiDotNetCore/Controllers/BaseJsonApiController.cs 100.00% <100.00%> (ø)
...Errors/CannotClearRequiredRelationshipException.cs 100.00% <100.00%> (ø)
...otNetCore/Queries/Internal/Parsing/FilterParser.cs 98.40% <100.00%> (+0.05%) ⬆️
...iDotNetCore/Queries/Internal/QueryLayerComposer.cs 99.63% <100.00%> (ø)
.../Internal/QueryableBuilding/SelectClauseBuilder.cs 99.13% <100.00%> (-0.01%) ⬇️
...s/Internal/QueryableBuilding/WhereClauseBuilder.cs 94.11% <100.00%> (-0.28%) ⬇️
...s/Internal/PaginationQueryStringParameterReader.cs 100.00% <100.00%> (ø)
... and 4 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@bkoelman bkoelman marked this pull request as ready for review February 16, 2023 18:55
@bkoelman bkoelman requested a review from maurei February 16, 2023 19:00
… of a string value. This effectively moves the type resolving/conversion logic from the EF query production phase to the filter parsing phase. By providing a richer QueryLayer model, it becomes easier to implement non-relational and non-EF Core-based repositories. And it enables to produce better errors earlier.

Note we still need to wrap nullable values (see WhereClauseBuilder.ResolveCommonType), due to https://bradwilson.typepad.com/blog/2008/07/creating-nullab.html.
|          Method |     Mean |     Error |    StdDev | Ratio |   Gen0 | Allocated | Alloc Ratio |
|---------------- |---------:|----------:|----------:|------:|-------:|----------:|------------:|
|    TrackChanges | 3.741 us | 0.0122 us | 0.0114 us |  1.00 | 0.0229 |   6.41 KB |        1.00 |
| NewTrackChanges | 1.359 us | 0.0070 us | 0.0066 us |  0.36 | 0.0095 |   2.62 KB |        0.41 |

using BenchmarkDotNet.Attributes;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Middleware;
using JsonApiDotNetCore.Resources;
using JsonApiDotNetCore.Resources.Annotations;
using Microsoft.Extensions.Logging.Abstractions;

namespace Benchmarks.ChangeTracking;

// ReSharper disable once ClassCanBeSealed.Global
[MarkdownExporter]
[MemoryDiagnoser]
public class ChangeTrackerBenchmarks
{
    private readonly JsonApiRequest _request;
    private readonly TargetedFields _targetedFields;

    public ChangeTrackerBenchmarks()
    {
        IJsonApiOptions options = new JsonApiOptions();
        IResourceGraph resourceGraph = new ResourceGraphBuilder(options, NullLoggerFactory.Instance).Add<ExampleResource, long>().Build();
        ResourceType resourceType = resourceGraph.GetResourceType<ExampleResource>();

        _request = new JsonApiRequest
        {
            PrimaryResourceType = resourceType,
            IsCollection = true
        };

        _targetedFields = new TargetedFields();

        foreach (AttrAttribute attribute in resourceType.Attributes)
        {
            _targetedFields.Attributes.Add(attribute);
        }
    }

    [Benchmark(Baseline = true)]
    public void TrackChanges()
    {
        var changeTracker = new ResourceChangeTracker<ExampleResource>(_request, _targetedFields);

        var resource = new ExampleResource
        {
            Id = 1,
            Attr1 = "some",
            Attr2 = "more",
            Attr3 = "other",
            Attr4 = false,
            Attr5 = 123,
            Attr6 = default,
            Attr7 = default,
            Attr8 = default,
            Attr9 = DayOfWeek.Sunday
        };

        changeTracker.SetInitiallyStoredAttributeValues(resource);

        resource = new ExampleResource
        {
            Id = 1,
            Attr1 = "new",
            Attr2 = "change",
            Attr3 = "this",
            Attr4 = true,
            Attr5 = 456,
            Attr6 = default,
            Attr7 = default,
            Attr8 = default,
            Attr9 = DayOfWeek.Saturday
        };

        changeTracker.SetFinallyStoredAttributeValues(resource);

        changeTracker.HasImplicitChanges();
    }

    [Benchmark]
    public void NewTrackChanges()
    {
        var changeTracker = new NewResourceChangeTracker<ExampleResource>(_request, _targetedFields);

        var resource = new ExampleResource
        {
            Id = 1,
            Attr1 = "some",
            Attr2 = "more",
            Attr3 = "other",
            Attr4 = false,
            Attr5 = 123,
            Attr6 = default,
            Attr7 = default,
            Attr8 = default,
            Attr9 = DayOfWeek.Sunday
        };

        changeTracker.SetInitiallyStoredAttributeValues(resource);

        resource = new ExampleResource
        {
            Id = 1,
            Attr1 = "new",
            Attr2 = "change",
            Attr3 = "this",
            Attr4 = true,
            Attr5 = 456,
            Attr6 = default,
            Attr7 = default,
            Attr8 = default,
            Attr9 = DayOfWeek.Saturday
        };

        changeTracker.SetFinallyStoredAttributeValues(resource);

        changeTracker.HasImplicitChanges();
    }

    private sealed class ExampleResource : Identifiable<long>
    {
        [Attr]
        public string? Attr1 { get; set; }

        [Attr]
        public string? Attr2 { get; set; }

        [Attr]
        public string? Attr3 { get; set; }

        [Attr]
        public bool Attr4 { get; set; }

        [Attr]
        public int Attr5 { get; set; }

        [Attr]
        public DateTime Attr6 { get; set; }

        [Attr]
        public DateTimeOffset Attr7 { get; set; }

        [Attr]
        public TimeSpan Attr8 { get; set; }

        [Attr]
        public DayOfWeek Attr9 { get; set; }
    }
}
Caused by an unintentional breaking change in .NET SDK v7.0.200, which the latest AppVeyor image uses
…n request path ended with a slash. For example: /workItems/ => /workItems//1
Before: Expected element.GetInt32() to be 25, but found 2 (difference of -23).
After: Expected responseDocument.Meta to be 25, but found 2 (difference of -23).
@maurei maurei merged commit 8a5e914 into master Mar 11, 2023
@maurei maurei deleted the query-tweaks branch March 11, 2023 10:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants