diff --git a/backend/Omnikeeper/GraphQL/TraitEntities/TraitEntityTypes.cs b/backend/Omnikeeper/GraphQL/TraitEntities/TraitEntityTypes.cs index ed77aba6..342e4dfd 100644 --- a/backend/Omnikeeper/GraphQL/TraitEntities/TraitEntityTypes.cs +++ b/backend/Omnikeeper/GraphQL/TraitEntities/TraitEntityTypes.cs @@ -55,6 +55,21 @@ public TraitEntityRootType(ITrait at, IEffectiveTraitModel effectiveTraitModel, var ets = await traitEntityModel.GetByCIID(AllCIIDsSelection.Instance, layerset, trans, timeThreshold); return ets.Select(kv => kv.Value); }); + Field("latestChangeAll") + .Description("Note: the implementation that calculates the latest relevant changeset is done rather defensively. That means there are circumstances " + + "where this field returns a new/later changeset even though there are no (visible) changes to the trait entities themselves. However, it will never NOT report " + + "a new changeset when there have been changes to the trait entities. This behavior makes it reasonably suitable for implementing a client-side cache that only " + + "fetches new data when anything has changed") + .ResolveAsync(async context => + { + var userContext = (context.UserContext as OmnikeeperUserContext)!; + var layerset = userContext.GetLayerSet(context.Path); + var timeThreshold = userContext.GetTimeThreshold(context.Path); + var trans = userContext.Transaction; + + // TODO: use dataloader + return await traitEntityModel.GetLatestRelevantChangesetOverallHeuristic(AllCIIDsSelection.Instance, layerset, trans, timeThreshold); + }); Field("filtered", new ListGraphType(wrapperElementGraphType)) .Arguments( diff --git a/backend/Tests/Integration/GraphQL/BasicTraitEntityTest.cs b/backend/Tests/Integration/GraphQL/BasicTraitEntityTest.cs index 09357a5d..3df17d53 100644 --- a/backend/Tests/Integration/GraphQL/BasicTraitEntityTest.cs +++ b/backend/Tests/Integration/GraphQL/BasicTraitEntityTest.cs @@ -110,6 +110,10 @@ public async Task TestBasics() assignments { relatedCIID } } } + latestChangeAll { + userID + layerID + } } } } @@ -118,7 +122,8 @@ public async Task TestBasics() { ""traitEntities"": { ""test_trait_a"": { - ""all"": [] + ""all"": [], + ""latestChangeAll"": null } } } @@ -166,7 +171,11 @@ public async Task TestBasics() }] } } - ] + ], + ""latestChangeAll"": { + ""userID"": " + userInDatabase.ID + @", + ""layerID"": ""layer_1"" + } } } } @@ -213,7 +222,11 @@ public async Task TestBasics() }] } } - ] + ], + ""latestChangeAll"": { + ""userID"": " + userInDatabase.ID + @", + ""layerID"": ""layer_1"" + } } } } @@ -284,7 +297,11 @@ public async Task TestBasics() }}] }} }} - ] + ], + ""latestChangeAll"": {{ + ""userID"": " + userInDatabase.ID + $@", + ""layerID"": ""layer_1"" + }} }} }} }} @@ -325,7 +342,11 @@ public async Task TestBasics() }}] }} }} - ] + ], + ""latestChangeAll"": {{ + ""userID"": " + userInDatabase.ID + $@", + ""layerID"": ""layer_1"" + }} }} }} }} @@ -380,7 +401,11 @@ public async Task TestBasics() }}] }} }} - ] + ], + ""latestChangeAll"": {{ + ""userID"": " + userInDatabase.ID + $@", + ""layerID"": ""layer_1"" + }} }} }} }} @@ -432,7 +457,11 @@ public async Task TestBasics() }}] }} }} - ] + ], + ""latestChangeAll"": {{ + ""userID"": " + userInDatabase.ID + $@", + ""layerID"": ""layer_1"" + }} }} }} }} @@ -462,7 +491,11 @@ public async Task TestBasics() {{ ""traitEntities"": {{ ""test_trait_a"": {{ - ""all"": [] + ""all"": [], + ""latestChangeAll"": {{ + ""userID"": " + userInDatabase.ID + $@", + ""layerID"": ""layer_1"" + }} }} }} }}