• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lucaslorentz / auto-compute / 20047162014

09 Dec 2025 12:10AM UTC coverage: 82.876% (+0.1%) from 82.728%
20047162014

push

github

lucaslorentz
Move IncrementalContext to input dictionary

35 of 37 new or added lines in 5 files covered. (94.59%)

1781 of 2149 relevant lines covered (82.88%)

852.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.77
/src/LLL.AutoCompute/EntityContexts/NavigationEntityContext.cs
1
using System.Linq.Expressions;
2

3
namespace LLL.AutoCompute.EntityContexts;
4

5
public class NavigationEntityContext : EntityContext
6
{
7
    private readonly EntityContext _parent;
8
    private readonly IObservedNavigation _navigation;
9
    private bool _shouldLoadAll;
10

11
    public NavigationEntityContext(
12
        Expression expression,
13
        EntityContext parent,
14
        IObservedNavigation navigation)
15
        : base(expression, [parent])
190✔
16
    {
17
        _parent = parent;
190✔
18
        _navigation = navigation;
190✔
19
        IsTrackingChanges = parent.IsTrackingChanges;
190✔
20
    }
21

22
    public override IObservedEntityType EntityType => _navigation.TargetEntityType;
1,158✔
23
    public IObservedNavigation Navigation => _navigation;
×
24
    public override bool IsTrackingChanges { get; }
176✔
25

26
    public override async Task<IReadOnlyCollection<object>> GetParentAffectedEntities(ComputedInput input)
27
    {
28
        // Short circuit to avoid requiring inverse navigation when no tracked property is accessed
29
        if (!GetAllObservedMembers().Any())
1,544✔
30
            return [];
356✔
31

32
        input.TryGet<IncrementalContext>(out var incrementalContext);
1,188✔
33

34
        var inverseNavigation = _navigation.GetInverse();
1,188✔
35

36
        var sourceType = _navigation.SourceEntityType;
1,188✔
37

38
        var entities = await GetAffectedEntitiesAsync(input);
1,188✔
39

40
        var parentEntities = new HashSet<object>();
1,188✔
41
        foreach (var (ent, parents) in await inverseNavigation.LoadOriginalAsync(input, entities))
2,520✔
42
        {
43
            foreach (var parent in parents)
284✔
44
            {
45
                if (!sourceType.IsInstanceOfType(parent))
70✔
46
                    continue;
47

48
                parentEntities.Add(parent);
70✔
49
                incrementalContext?.AddOriginalEntity(parent, _navigation, ent);
70✔
50
            }
51
        }
52
        foreach (var (ent, parents) in await inverseNavigation.LoadCurrentAsync(input, entities))
4,328✔
53
        {
54
            foreach (var parent in parents)
3,868✔
55
            {
56
                if (!sourceType.IsInstanceOfType(parent))
958✔
57
                    continue;
58

59
                parentEntities.Add(parent);
958✔
60
                incrementalContext?.AddCurrentEntity(parent, _navigation, ent);
958✔
61
            }
62
        }
63
        return parentEntities;
1,188✔
64
    }
65

66
    public override async Task EnrichIncrementalContextFromParentAsync(ComputedInput input, IReadOnlyCollection<object> parentEntities)
67
    {
68
        var entities = new HashSet<object>();
260✔
69

70
        if (!input.TryGet<IncrementalContext>(out var incrementalContext))
260✔
NEW
71
            throw new InvalidOperationException("IncrementalContext is required to enrich from parent.");
×
72

73
        var parentEntitiesByLoadAll = parentEntities
260✔
74
            .ToLookup(e => _shouldLoadAll || incrementalContext.ShouldLoadAll(e));
512✔
75

76
        var parentEntitiesToLoadAll = parentEntitiesByLoadAll[true].ToArray();
260✔
77

78
        foreach (var (parent, ents) in await _navigation.LoadOriginalAsync(input, parentEntitiesToLoadAll))
552✔
79
        {
80
            foreach (var ent in ents)
60✔
81
            {
82
                entities.Add(ent);
14✔
83
                incrementalContext.AddOriginalEntity(parent, _navigation, ent);
14✔
84
                if (incrementalContext.ShouldLoadAll(parent))
14✔
85
                    incrementalContext.SetShouldLoadAll(ent);
12✔
86
            }
87
        }
88

89
        foreach (var (parent, ents) in await _navigation.LoadCurrentAsync(input, parentEntitiesToLoadAll))
556✔
90
        {
91
            foreach (var ent in ents)
64✔
92
            {
93
                entities.Add(ent);
14✔
94
                incrementalContext.AddCurrentEntity(parent, _navigation, ent);
14✔
95
                if (incrementalContext.ShouldLoadAll(parent))
14✔
96
                    incrementalContext.SetShouldLoadAll(ent);
10✔
97
            }
98
        }
99

100
        foreach (var parentEntity in parentEntitiesByLoadAll[false])
988✔
101
        {
102
            foreach (var entity in incrementalContext.GetEntities(parentEntity, _navigation))
936✔
103
            {
104
                entities.Add(entity);
234✔
105
            }
106
        }
107

108
        await EnrichIncrementalContextAsync(input, entities);
260✔
109
    }
110

111
    public override async Task EnrichIncrementalContextTowardsRootAsync(ComputedInput input, IReadOnlyCollection<object> entities)
112
    {
113
        if (!input.TryGet<IncrementalContext>(out var incrementalContext))
72✔
NEW
114
            throw new InvalidOperationException("IncrementalContext is required to enrich towards root.");
×
115

116
        var inverse = _navigation.GetInverse();
72✔
117

118
        var parentEntities = new HashSet<object>();
72✔
119

120
        foreach (var (ent, parents) in await inverse.LoadOriginalAsync(input, entities))
232✔
121
        {
122
            foreach (var parent in parents)
160✔
123
            {
124
                parentEntities.Add(parent);
36✔
125
                incrementalContext.AddOriginalEntity(parent, _navigation, ent);
36✔
126
            }
127
        }
128

129
        foreach (var (ent, parents) in await inverse.LoadCurrentAsync(input, entities))
240✔
130
        {
131
            foreach (var parent in parents)
168✔
132
            {
133
                parentEntities.Add(parent);
36✔
134
                incrementalContext.AddCurrentEntity(parent, _navigation, ent);
36✔
135
            }
136
        }
137

138
        await _parent.EnrichIncrementalContextTowardsRootAsync(input, parentEntities);
72✔
139
    }
140

141
    public override async Task PreLoadNavigationsFromParentAsync(ComputedInput input, IReadOnlyCollection<object> parentEntities)
142
    {
143
        var entities = new HashSet<object>();
1,284✔
144

145
        foreach (var (parent, ents) in await _navigation.LoadOriginalAsync(input, parentEntities))
3,000✔
146
        {
147
            foreach (var ent in ents)
832✔
148
                entities.Add(ent);
200✔
149
        }
150

151
        foreach (var (parent, ents) in await _navigation.LoadCurrentAsync(input, parentEntities))
4,868✔
152
        {
153
            foreach (var ent in ents)
4,652✔
154
                entities.Add(ent);
1,176✔
155
        }
156

157
        await PreLoadNavigationsAsync(input, entities);
1,284✔
158
    }
159

160
    public override void MarkNavigationToLoadAll()
161
    {
162
        _shouldLoadAll = true;
14✔
163
    }
164

165
    public override void ValidateSelf()
166
    {
167
        if (GetAllObservedMembers().Any())
190✔
168
        {
169
            _navigation.GetInverse();
142✔
170
        }
171
    }
172
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc