diff --git a/src/DataAccess/src/SIL.DataAccess/IUpdateBuilder.cs b/src/DataAccess/src/SIL.DataAccess/IUpdateBuilder.cs index 6eaf27e5..35db6f88 100644 --- a/src/DataAccess/src/SIL.DataAccess/IUpdateBuilder.cs +++ b/src/DataAccess/src/SIL.DataAccess/IUpdateBuilder.cs @@ -24,6 +24,7 @@ IUpdateBuilder SetAll( Expression?>> collectionField, Expression> itemField, TField value, - Expression>? predicate = null + Expression>? predicate = null, + Expression>? setIfFieldExists = null ); } diff --git a/src/DataAccess/src/SIL.DataAccess/MemoryUpdateBuilder.cs b/src/DataAccess/src/SIL.DataAccess/MemoryUpdateBuilder.cs index bbf6b5d9..a6131d63 100644 --- a/src/DataAccess/src/SIL.DataAccess/MemoryUpdateBuilder.cs +++ b/src/DataAccess/src/SIL.DataAccess/MemoryUpdateBuilder.cs @@ -170,9 +170,11 @@ public IUpdateBuilder SetAll( Expression?>> collectionField, Expression> itemField, TField value, - Expression>? predicate = null + Expression>? predicate = null, + Expression>? setIfFieldExists = null ) { + // TODO check for setIfFieldExists (IEnumerable owners, PropertyInfo? prop, object? index) = GetFieldOwners( _entity, _filter, diff --git a/src/DataAccess/src/SIL.DataAccess/MongoRepository.cs b/src/DataAccess/src/SIL.DataAccess/MongoRepository.cs index d5b09a1b..b822ba38 100644 --- a/src/DataAccess/src/SIL.DataAccess/MongoRepository.cs +++ b/src/DataAccess/src/SIL.DataAccess/MongoRepository.cs @@ -122,7 +122,11 @@ await _collection var updateBuilder = new MongoUpdateBuilder(); update(updateBuilder); updateBuilder.Inc(e => e.Revision, 1); - (UpdateDefinition updateDef, IReadOnlyList arrayFilters) = updateBuilder.Build(); + ( + FilterDefinition filterDef, + UpdateDefinition updateDef, + IReadOnlyList arrayFilters + ) = updateBuilder.Build(filter); var options = new FindOneAndUpdateOptions { IsUpsert = upsert, @@ -136,13 +140,13 @@ await _collection if (_context.Session is not null) { entity = await _collection - .FindOneAndUpdateAsync(_context.Session, filter, updateDef, options, cancellationToken) + .FindOneAndUpdateAsync(_context.Session, filterDef, updateDef, options, cancellationToken) .ConfigureAwait(false); } else { entity = await _collection - .FindOneAndUpdateAsync(filter, updateDef, options, cancellationToken) + .FindOneAndUpdateAsync(filterDef, updateDef, options, cancellationToken) .ConfigureAwait(false); } } @@ -162,7 +166,11 @@ public async Task UpdateAllAsync( var updateBuilder = new MongoUpdateBuilder(); update(updateBuilder); updateBuilder.Inc(e => e.Revision, 1); - (UpdateDefinition updateDef, IReadOnlyList arrayFilters) = updateBuilder.Build(); + ( + FilterDefinition filterDef, + UpdateDefinition updateDef, + IReadOnlyList arrayFilters + ) = updateBuilder.Build(filter); UpdateOptions? updateOptions = null; if (arrayFilters.Count > 0) updateOptions = new UpdateOptions { ArrayFilters = arrayFilters }; @@ -172,13 +180,13 @@ public async Task UpdateAllAsync( if (_context.Session is not null) { result = await _collection - .UpdateManyAsync(_context.Session, filter, updateDef, updateOptions, cancellationToken) + .UpdateManyAsync(_context.Session, filterDef, updateDef, updateOptions, cancellationToken) .ConfigureAwait(false); } else { result = await _collection - .UpdateManyAsync(filter, updateDef, updateOptions, cancellationToken) + .UpdateManyAsync(filterDef, updateDef, updateOptions, cancellationToken) .ConfigureAwait(false); } } diff --git a/src/DataAccess/src/SIL.DataAccess/MongoUpdateBuilder.cs b/src/DataAccess/src/SIL.DataAccess/MongoUpdateBuilder.cs index 662c3f92..a5fa09e5 100644 --- a/src/DataAccess/src/SIL.DataAccess/MongoUpdateBuilder.cs +++ b/src/DataAccess/src/SIL.DataAccess/MongoUpdateBuilder.cs @@ -4,12 +4,15 @@ public class MongoUpdateBuilder : IUpdateBuilder where T : IEntity { private readonly UpdateDefinitionBuilder _builder; + private readonly FilterDefinitionBuilder _filterBuilder; private readonly List> _defs; + private FilterDefinition? _existsFilter = null; private readonly Dictionary FilterDef)> _arrayFilters; public MongoUpdateBuilder() { _builder = Builders.Update; + _filterBuilder = Builders.Filter; _defs = new List>(); _arrayFilters = new Dictionary)>(); } @@ -63,13 +66,19 @@ public IUpdateBuilder SetAll( Expression?>> collectionField, Expression> itemField, TField value, - Expression>? predicate = null + Expression>? predicate = null, + Expression>? setIfFieldExists = null ) { Expression> itemExpr = ExpressionHelper.Concatenate( collectionField, (collection) => ((IReadOnlyList?)collection)![ArrayPosition.ArrayFilter] ); + FieldDefinition itemFieldDef = ToFieldDefinition(itemExpr); + if (setIfFieldExists == null) + { + _existsFilter = _filterBuilder.Exists(setIfFieldExists, true); + } Expression> fieldExpr = ExpressionHelper.Concatenate(itemExpr, itemField); if (predicate != null) { @@ -107,12 +116,20 @@ public IUpdateBuilder SetAll( return this; } - public (UpdateDefinition, IReadOnlyList) Build() + public (FilterDefinition, UpdateDefinition, IReadOnlyList) Build( + Expression> filter + ) { ArrayFilterDefinition[] arrayFilters = _arrayFilters.Values.Select(f => f.FilterDef).ToArray(); + FilterDefinition outFilter; + if (_existsFilter != null) + outFilter = _filterBuilder.And(_existsFilter, filter); + else + outFilter = filter; + if (_defs.Count == 1) - return (_defs.Single(), arrayFilters); - return (_builder.Combine(_defs), arrayFilters); + return (outFilter, _defs.Single(), arrayFilters); + return (outFilter, _builder.Combine(_defs), arrayFilters); } private static FieldDefinition ToFieldDefinition( diff --git a/src/Serval/src/Serval.Translation/Services/EngineService.cs b/src/Serval/src/Serval.Translation/Services/EngineService.cs index b0cfb5be..63e2fdd1 100644 --- a/src/Serval/src/Serval.Translation/Services/EngineService.cs +++ b/src/Serval/src/Serval.Translation/Services/EngineService.cs @@ -616,13 +616,15 @@ public Task UpdateDataFileFilenameFilesAsync( e => e.ParallelCorpora[ArrayPosition.All].SourceCorpora[ArrayPosition.All].Files, f => f.Filename, filename, - f => f.Id == dataFileId + f => f.Id == dataFileId, + f => f.ParallelCorpora ); u.SetAll( e => e.ParallelCorpora[ArrayPosition.All].TargetCorpora[ArrayPosition.All].Files, f => f.Filename, filename, - f => f.Id == dataFileId + f => f.Id == dataFileId, + f => f.ParallelCorpora ); }, cancellationToken: cancellationToken @@ -646,13 +648,15 @@ public Task UpdateCorpusFilesAsync( e => e.ParallelCorpora[ArrayPosition.All].SourceCorpora, mc => mc.Files, files, - mc => mc.Id == corpusId + f => f.Id == corpusId, + f => f.ParallelCorpora ); u.SetAll( e => e.ParallelCorpora[ArrayPosition.All].TargetCorpora, mc => mc.Files, files, - mc => mc.Id == corpusId + f => f.Id == corpusId, + f => f.ParallelCorpora ); }, cancellationToken: cancellationToken