From 9b1048e31854e82f6e7007b2050345af291d0de3 Mon Sep 17 00:00:00 2001 From: alexandre-spieser Date: Sat, 23 Sep 2017 22:00:31 +0000 Subject: [PATCH 1/7] Adding TKey support --- .../BaseMongoDbRepository.cs | 446 +++++++++++++++--- MongoDbGenericRepository/IMongoDbContext.cs | 11 + MongoDbGenericRepository/Models/IDocument.cs | 12 +- .../Models/IPartitionedDocument.cs | 2 +- MongoDbGenericRepository/MongoDbContext.cs | 24 +- 5 files changed, 417 insertions(+), 78 deletions(-) diff --git a/MongoDbGenericRepository/BaseMongoDbRepository.cs b/MongoDbGenericRepository/BaseMongoDbRepository.cs index d9e90e5..1427742 100644 --- a/MongoDbGenericRepository/BaseMongoDbRepository.cs +++ b/MongoDbGenericRepository/BaseMongoDbRepository.cs @@ -27,7 +27,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously adds a document to the collection. /// - /// + /// The type representing a Document. /// The document you want to add. Task AddOneAsync(TDocument document) where TDocument : IDocument; @@ -35,7 +35,7 @@ namespace MongoDbGenericRepository /// Adds a document to the collection. /// Populates the Id and AddedAtUtc fields if necessary. /// - /// + /// The type representing a Document. /// The document you want to add. void AddOne(TDocument document) where TDocument : IDocument; @@ -43,7 +43,7 @@ namespace MongoDbGenericRepository /// Asynchronously adds a list of documents to the collection. /// Populates the Id and AddedAtUtc fields if necessary. /// - /// + /// The type representing a Document. /// The document you want to add. Task AddManyAsync(IEnumerable documents) where TDocument : IDocument; @@ -51,7 +51,7 @@ namespace MongoDbGenericRepository /// Adds a list of documents to the collection. /// Populates the Id and AddedAtUtc fields if necessary. /// - /// + /// The type representing a Document. /// The document you want to add. void AddMany(IEnumerable documents) where TDocument : IDocument; @@ -62,7 +62,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns one document given its id. /// - /// + /// The type representing a Document. /// The Id of the document you want to get. /// An optional partition key. Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument; @@ -70,7 +70,7 @@ namespace MongoDbGenericRepository /// /// Returns one document given its id. /// - /// + /// The type representing a Document. /// The Id of the document you want to get. /// An optional partition key. TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument; @@ -78,7 +78,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns one document given an expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; @@ -86,7 +86,7 @@ namespace MongoDbGenericRepository /// /// Returns one document given an expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; @@ -94,7 +94,7 @@ namespace MongoDbGenericRepository /// /// Returns a collection cursor. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument; @@ -102,7 +102,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns true if any of the document of the collection matches the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; @@ -110,7 +110,7 @@ namespace MongoDbGenericRepository /// /// Returns true if any of the document of the collection matches the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument; @@ -118,7 +118,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns a list of the documents matching the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; @@ -126,7 +126,7 @@ namespace MongoDbGenericRepository /// /// Returns a list of the documents matching the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument; @@ -134,7 +134,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously counts how many documents match the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; @@ -142,7 +142,7 @@ namespace MongoDbGenericRepository /// /// Counts how many documents match the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument; @@ -154,14 +154,14 @@ namespace MongoDbGenericRepository /// /// Asynchronously Updates a document. /// - /// + /// The type representing a Document. /// The document with the modifications you want to persist. Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument; /// /// Updates a document. /// - /// + /// The type representing a Document. /// The document with the modifications you want to persist. bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument; @@ -172,7 +172,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously deletes a document. /// - /// + /// The type representing a Document. /// The document you want to delete. /// The number of documents deleted. Task DeleteOneAsync(TDocument document) where TDocument : IDocument; @@ -180,7 +180,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously deletes a document matching the condition of the LINQ expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. /// The number of documents deleted. @@ -189,7 +189,7 @@ namespace MongoDbGenericRepository /// /// Deletes a document. /// - /// + /// The type representing a Document. /// The document you want to delete. /// The number of documents deleted. long DeleteOne(TDocument document) where TDocument : IDocument; @@ -197,7 +197,7 @@ namespace MongoDbGenericRepository /// /// Deletes a document matching the condition of the LINQ expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. /// The number of documents deleted. @@ -206,7 +206,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. /// The number of documents deleted. @@ -215,7 +215,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously deletes a list of documents. /// - /// + /// The type representing a Document. /// The list of documents to delete. /// The number of documents deleted. Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument; @@ -223,7 +223,7 @@ namespace MongoDbGenericRepository /// /// Deletes a list of documents. /// - /// + /// The type representing a Document. /// The list of documents to delete. /// The number of documents deleted. long DeleteMany(IEnumerable documents) where TDocument : IDocument; @@ -231,21 +231,33 @@ namespace MongoDbGenericRepository /// /// Deletes the documents matching the condition of the LINQ expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. /// The number of documents deleted. long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument; + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteMany(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + #endregion - #region Project + #region Project /// /// Asynchronously returns a projected document matching the filter condition. /// - /// - /// + /// The type representing a Document. + /// The type representing the model you want to project to. /// /// The projection expression. /// An optional partition key. @@ -253,11 +265,25 @@ namespace MongoDbGenericRepository where TDocument : IDocument where TProjection : class; + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + /// /// Returns a projected document matching the filter condition. /// - /// - /// + /// The type representing a Document. + /// The type representing the model you want to project to. /// /// The projection expression. /// An optional partition key. @@ -265,11 +291,25 @@ namespace MongoDbGenericRepository where TDocument : IDocument where TProjection : class; + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + /// /// Asynchronously returns a list of projected documents matching the filter condition. /// - /// - /// + /// The type representing a Document. + /// The type representing the model you want to project to. /// /// The projection expression. /// An optional partition key. @@ -280,8 +320,22 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns a list of projected documents matching the filter condition. /// - /// - /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. /// /// The projection expression. /// An optional partition key. @@ -289,8 +343,70 @@ namespace MongoDbGenericRepository where TDocument : IDocument where TProjection : class; + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + #endregion + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument; + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// + /// + /// + /// + Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument; + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// + /// + /// + Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument + where TKey : IEquatable; + } /// @@ -338,7 +454,7 @@ namespace MongoDbGenericRepository /// Asynchronously adds a document to the collection. /// Populates the Id and AddedAtUtc fields if necessary. /// - /// + /// The type representing a Document. /// The document you want to add. public async Task AddOneAsync(TDocument document) where TDocument : IDocument { @@ -350,7 +466,7 @@ namespace MongoDbGenericRepository /// Adds a document to the collection. /// Populates the Id and AddedAtUtc fields if necessary. /// - /// + /// The type representing a Document. /// The document you want to add. public void AddOne(TDocument document) where TDocument : IDocument { @@ -362,7 +478,7 @@ namespace MongoDbGenericRepository /// Asynchronously adds a list of documents to the collection. /// Populates the Id and AddedAtUtc fields if necessary. /// - /// + /// The type representing a Document. /// The documents you want to add. public async Task AddManyAsync(IEnumerable documents) where TDocument : IDocument { @@ -381,7 +497,7 @@ namespace MongoDbGenericRepository /// Adds a list of documents to the collection. /// Populates the Id and AddedAtUtc fields if necessary. /// - /// + /// The type representing a Document. /// The documents you want to add. public void AddMany(IEnumerable documents) where TDocument : IDocument { @@ -403,7 +519,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns one document given its id. /// - /// + /// The type representing a Document. /// The Id of the document you want to get. /// An optional partition key. public async Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument @@ -415,7 +531,7 @@ namespace MongoDbGenericRepository /// /// Returns one document given its id. /// - /// + /// The type representing a Document. /// The Id of the document you want to get. /// An optional partition key. public TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument @@ -427,7 +543,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns one document given an expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. public async Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument @@ -438,7 +554,7 @@ namespace MongoDbGenericRepository /// /// Returns one document given an expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. public TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument @@ -449,7 +565,7 @@ namespace MongoDbGenericRepository /// /// Returns a collection cursor. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. public IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument @@ -460,7 +576,7 @@ namespace MongoDbGenericRepository /// /// Returns true if any of the document of the collection matches the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. public async Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument @@ -472,7 +588,7 @@ namespace MongoDbGenericRepository /// /// Returns true if any of the document of the collection matches the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. public bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument @@ -484,7 +600,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns a list of the documents matching the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. public async Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument @@ -495,7 +611,7 @@ namespace MongoDbGenericRepository /// /// Returns a list of the documents matching the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. public List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument @@ -506,7 +622,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously counts how many documents match the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partitionKey public async Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument @@ -517,7 +633,7 @@ namespace MongoDbGenericRepository /// /// Counts how many documents match the filter condition. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partitionKey public long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument @@ -532,7 +648,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously Updates a document. /// - /// + /// The type representing a Document. /// The document with the modifications you want to persist. public async Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument { @@ -543,7 +659,7 @@ namespace MongoDbGenericRepository /// /// Updates a document. /// - /// + /// The type representing a Document. /// The document with the modifications you want to persist. public bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument { @@ -558,7 +674,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously deletes a document. /// - /// + /// The type representing a Document. /// The document you want to delete. /// The number of documents deleted. public async Task DeleteOneAsync(TDocument document) where TDocument : IDocument @@ -569,7 +685,7 @@ namespace MongoDbGenericRepository /// /// Deletes a document. /// - /// + /// The type representing a Document. /// The document you want to delete. /// The number of documents deleted. public long DeleteOne(TDocument document) where TDocument : IDocument @@ -580,7 +696,7 @@ namespace MongoDbGenericRepository /// /// Deletes a document matching the condition of the LINQ expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. /// The number of documents deleted. @@ -592,7 +708,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously deletes a document matching the condition of the LINQ expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. /// The number of documents deleted. @@ -604,7 +720,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. /// The number of documents deleted. @@ -616,7 +732,7 @@ namespace MongoDbGenericRepository /// /// Asynchronously deletes a list of documents. /// - /// + /// The type representing a Document. /// The list of documents to delete. /// The number of documents deleted. public async Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument @@ -632,7 +748,7 @@ namespace MongoDbGenericRepository /// /// Deletes a list of documents. /// - /// + /// The type representing a Document. /// The list of documents to delete. /// The number of documents deleted. public long DeleteMany(IEnumerable documents) where TDocument : IDocument @@ -645,10 +761,29 @@ namespace MongoDbGenericRepository return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; } + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The list of documents to delete. + /// The number of documents deleted. + public long DeleteMany(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable + { + if (!documents.Any()) + { + return 0; + } + var idsTodelete = documents.Select(e => e.Id).ToArray(); + return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; + } + /// /// Deletes the documents matching the condition of the LINQ expression filter. /// - /// + /// The type representing a Document. /// A LINQ expression filter. /// An optional partition key. /// The number of documents deleted. @@ -657,6 +792,21 @@ namespace MongoDbGenericRepository return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; } + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public long DeleteMany(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; + } + #endregion Delete #region Project @@ -664,8 +814,8 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns a projected document matching the filter condition. /// - /// - /// + /// The type representing a Document. + /// The type representing the model you want to project to. /// /// The projection expression. /// An optional partition key. @@ -678,11 +828,30 @@ namespace MongoDbGenericRepository .FirstOrDefaultAsync(); } + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefaultAsync(); + } + /// /// Returns a projected document matching the filter condition. /// - /// - /// + /// The type representing a Document. + /// The type representing the model you want to project to. /// /// The projection expression. /// An optional partition key. @@ -695,11 +864,30 @@ namespace MongoDbGenericRepository .FirstOrDefault(); } + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefault(); + } + /// /// Asynchronously returns a list of projected documents matching the filter condition. /// - /// - /// + /// The type representing a Document. + /// The type representing the model you want to project to. /// /// The projection expression. /// An optional partition key. @@ -715,8 +903,27 @@ namespace MongoDbGenericRepository /// /// Asynchronously returns a list of projected documents matching the filter condition. /// - /// - /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToListAsync(); + } + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. /// /// The projection expression. /// An optional partition key. @@ -729,27 +936,63 @@ namespace MongoDbGenericRepository .ToList(); } + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToList(); + } + #endregion /// /// Asynchronously returns a paginated list of the documents matching the filter condition. /// - /// + /// The type representing a Document. /// /// The number of documents you want to skip. Default value is 0. /// The number of documents you want to take. Default value is 50. /// An optional partition key. - public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) where TDocument : IDocument + public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument { return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); } + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); + } + #region Find And Update /// /// GetAndUpdateOne with filter /// - /// + /// The type representing a Document. /// /// /// @@ -759,6 +1002,22 @@ namespace MongoDbGenericRepository return await GetCollection().FindOneAndUpdateAsync(filter, update, options); } + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// + /// + /// + public async Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument + where TKey : IEquatable + { + return await GetCollection().FindOneAndUpdateAsync(filter, update, options); + } + #endregion Find And Update #region Private Methods @@ -782,6 +1041,17 @@ namespace MongoDbGenericRepository return GetCollection(); } + private IMongoCollection HandlePartitioned(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + if (document is IPartitionedDocument) + { + return GetCollection(((IPartitionedDocument)document).PartitionKey); + } + return GetCollection(); + } + private IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument { if (!string.IsNullOrEmpty(partitionKey)) @@ -803,6 +1073,42 @@ namespace MongoDbGenericRepository } } + + private IMongoCollection GetCollection(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable + { + return MongoDbContext.GetCollection(partitionKey); + } + + private IMongoCollection GetCollection() + where TDocument : IDocument + where TKey : IEquatable + { + return MongoDbContext.GetCollection(); + } + + private IMongoCollection HandlePartitioned(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable + { + if (!string.IsNullOrEmpty(partitionKey)) + { + return GetCollection(partitionKey); + } + return GetCollection(); + } + + private void FormatDocument(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + if (document == null) + { + throw new ArgumentNullException(nameof(document)); + } + } + #endregion } } \ No newline at end of file diff --git a/MongoDbGenericRepository/IMongoDbContext.cs b/MongoDbGenericRepository/IMongoDbContext.cs index 31fee2a..ca2b297 100644 --- a/MongoDbGenericRepository/IMongoDbContext.cs +++ b/MongoDbGenericRepository/IMongoDbContext.cs @@ -1,5 +1,6 @@ using MongoDB.Driver; using MongoDbGenericRepository.Models; +using System; namespace MongoDbGenericRepository { @@ -31,6 +32,16 @@ namespace MongoDbGenericRepository /// The value of the partition key. IMongoCollection GetCollection(string partitionKey) where TDocument : IDocument; + /// + /// Returns a collection for a document type that has a partition key. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The value of the partition key. + IMongoCollection GetCollection(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable; + /// /// Drops a collection, use very carefully. /// diff --git a/MongoDbGenericRepository/Models/IDocument.cs b/MongoDbGenericRepository/Models/IDocument.cs index bdad597..07d25c4 100644 --- a/MongoDbGenericRepository/Models/IDocument.cs +++ b/MongoDbGenericRepository/Models/IDocument.cs @@ -6,16 +6,24 @@ namespace MongoDbGenericRepository.Models /// This class represents a basic document that can be stored in MongoDb. /// Your document must implement this class in order for the MongoDbRepository to handle them. /// - public interface IDocument + public interface IDocument where TKey : IEquatable { /// /// The Guid, which must be decorated with the [BsonId] attribute /// if you want the MongoDb C# driver to consider it to be the document ID. /// - Guid Id { get; set; } + TKey Id { get; set; } /// /// A version number, to indicate the version of the schema. /// int Version { get; set; } } + + /// + /// This class represents a basic document that can be stored in MongoDb. + /// Your document must implement this class in order for the MongoDbRepository to handle them. + /// + public interface IDocument: IDocument + { + } } \ No newline at end of file diff --git a/MongoDbGenericRepository/Models/IPartitionedDocument.cs b/MongoDbGenericRepository/Models/IPartitionedDocument.cs index 9dbf5e2..21626ca 100644 --- a/MongoDbGenericRepository/Models/IPartitionedDocument.cs +++ b/MongoDbGenericRepository/Models/IPartitionedDocument.cs @@ -6,7 +6,7 @@ /// This can be useful if you are planning to build a Software as a Service (SaaS) Platform, or if you want to reduce indexing. /// You could for example insert Logs in different collections based on the week and year they where created, or their Log category/source. /// - public interface IPartitionedDocument : IDocument + public interface IPartitionedDocument { /// /// The partition key used to partition your collection. diff --git a/MongoDbGenericRepository/MongoDbContext.cs b/MongoDbGenericRepository/MongoDbContext.cs index dd21e9d..2223fe3 100644 --- a/MongoDbGenericRepository/MongoDbContext.cs +++ b/MongoDbGenericRepository/MongoDbContext.cs @@ -1,5 +1,6 @@ using MongoDB.Driver; using MongoDbGenericRepository.Models; +using System; namespace MongoDbGenericRepository { @@ -48,7 +49,7 @@ namespace MongoDbGenericRepository /// /// The private GetCollection method /// - /// + /// The type representing a Document. /// public IMongoCollection GetCollection() { @@ -58,17 +59,30 @@ namespace MongoDbGenericRepository /// /// Returns a collection for a document type that has a partition key. /// - /// + /// The type representing a Document. /// The value of the partition key. public IMongoCollection GetCollection(string partitionKey) where TDocument : IDocument { return Database.GetCollection(partitionKey +"-"+ Pluralize()); } + /// + /// Returns a collection for a document type that has a partition key. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The value of the partition key. + public IMongoCollection GetCollection(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable + { + return Database.GetCollection(partitionKey + "-" + Pluralize()); + } + /// /// Drops a collection, use very carefully. /// - /// + /// The type representing a Document. public void DropCollection() { Database.DropCollection(Pluralize()); @@ -77,7 +91,7 @@ namespace MongoDbGenericRepository /// /// Drops a collection having a partitionkey, use very carefully. /// - /// + /// The type representing a Document. public void DropCollection(string partitionKey) { Database.DropCollection(partitionKey + "-" + Pluralize()); @@ -86,7 +100,7 @@ namespace MongoDbGenericRepository /// /// Very naively pluralizes a TDocument type name. /// - /// + /// The type representing a Document. /// private string Pluralize() { From 6552a01d2898ada07d57d9a61a2afa632e36afed Mon Sep 17 00:00:00 2001 From: alexandre-spieser Date: Sat, 23 Sep 2017 22:32:44 +0000 Subject: [PATCH 2/7] TKey support, continued --- .../CoreIntegrationTests.csproj | 5 +- IntegrationTests/App.config | 8 + IntegrationTests/IntegrationTests.csproj | 20 +- IntegrationTests/packages.config | 4 +- .../BaseMongoDbRepository.cs | 2484 +++++++++-------- 5 files changed, 1397 insertions(+), 1124 deletions(-) diff --git a/CoreIntegrationTests/CoreIntegrationTests.csproj b/CoreIntegrationTests/CoreIntegrationTests.csproj index 2e4ad1b..4edac06 100644 --- a/CoreIntegrationTests/CoreIntegrationTests.csproj +++ b/CoreIntegrationTests/CoreIntegrationTests.csproj @@ -7,13 +7,16 @@ - + + + + Always diff --git a/IntegrationTests/App.config b/IntegrationTests/App.config index 139995c..6d19a67 100644 --- a/IntegrationTests/App.config +++ b/IntegrationTests/App.config @@ -7,4 +7,12 @@ + + + + + + + + \ No newline at end of file diff --git a/IntegrationTests/IntegrationTests.csproj b/IntegrationTests/IntegrationTests.csproj index 58a2d21..580fb5d 100644 --- a/IntegrationTests/IntegrationTests.csproj +++ b/IntegrationTests/IntegrationTests.csproj @@ -31,16 +31,13 @@ - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\MongoDB.Bson.dll + ..\packages\MongoDB.Bson.2.4.4\lib\net45\MongoDB.Bson.dll - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\MongoDB.Driver.dll + ..\packages\MongoDB.Driver.2.4.4\lib\net45\MongoDB.Driver.dll - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\MongoDB.Driver.Core.dll - - - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\MongoDbGenericRepository.dll + ..\packages\MongoDB.Driver.Core.2.4.4\lib\net45\MongoDB.Driver.Core.dll ..\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll @@ -49,8 +46,9 @@ - - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True @@ -78,5 +76,11 @@ + + + {efc776c4-2af3-440c-be80-3fbe335817a5} + MongoDbGenericRepository + + \ No newline at end of file diff --git a/IntegrationTests/packages.config b/IntegrationTests/packages.config index 8ef186d..383927f 100644 --- a/IntegrationTests/packages.config +++ b/IntegrationTests/packages.config @@ -3,8 +3,8 @@ - - + + \ No newline at end of file diff --git a/MongoDbGenericRepository/BaseMongoDbRepository.cs b/MongoDbGenericRepository/BaseMongoDbRepository.cs index 1427742..f7f566c 100644 --- a/MongoDbGenericRepository/BaseMongoDbRepository.cs +++ b/MongoDbGenericRepository/BaseMongoDbRepository.cs @@ -1,1114 +1,1372 @@ -using MongoDB.Driver; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using System.Linq.Expressions; -using MongoDbGenericRepository.Models; -using System.Linq; - -namespace MongoDbGenericRepository -{ - /// - /// The IBaseMongoRepository exposes the functionality of the BaseMongoRepository. - /// - public interface IBaseMongoRepository - { - /// - /// The connection string. - /// - string ConnectionString { get; set; } - /// - /// The database name. - /// - string DatabaseName { get; set; } - - #region Create - - /// - /// Asynchronously adds a document to the collection. - /// - /// The type representing a Document. - /// The document you want to add. - Task AddOneAsync(TDocument document) where TDocument : IDocument; - - /// - /// Adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - void AddOne(TDocument document) where TDocument : IDocument; - - /// - /// Asynchronously adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - Task AddManyAsync(IEnumerable documents) where TDocument : IDocument; - - /// - /// Adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - void AddMany(IEnumerable documents) where TDocument : IDocument; - - #endregion - - #region Read - - /// - /// Asynchronously returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns a collection cursor. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - #endregion - - #region Update - - /// - /// Asynchronously Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument; - - /// - /// Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument; - - #endregion - - #region Delete - - /// - /// Asynchronously deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - Task DeleteOneAsync(TDocument document) where TDocument : IDocument; - - /// - /// Asynchronously deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - long DeleteOne(TDocument document) where TDocument : IDocument; - - /// - /// Deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument; - - /// - /// Deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - long DeleteMany(IEnumerable documents) where TDocument : IDocument; - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteMany(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - #endregion - - #region Project - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - #endregion - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument; - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// - /// - /// - /// - Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) - where TDocument : IDocument; - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// - /// - /// - Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) - where TDocument : IDocument - where TKey : IEquatable; - - } - - /// - /// The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. - /// Its constructor must be given a connection string and a database name. - /// - public abstract class BaseMongoRepository : IBaseMongoRepository - { - /// - /// The connection string. - /// - public string ConnectionString { get; set; } - /// - /// The database name. - /// - public string DatabaseName { get; set; } - - /// - /// The constructor taking a connection string and a database name. - /// - /// The connection string of the MongoDb server. - /// The name of the database against which you want to perform operations. - protected BaseMongoRepository(string connectionString, string databaseName) - { - MongoDbContext = new MongoDbContext(connectionString, databaseName); - } - - /// - /// The contructor taking a . - /// - /// A mongodb context implementing - protected BaseMongoRepository(IMongoDbContext mongoDbContext) - { - MongoDbContext = mongoDbContext; - } - - /// - /// The MongoDbContext - /// - protected IMongoDbContext MongoDbContext = null; - - #region Create - - /// - /// Asynchronously adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - public async Task AddOneAsync(TDocument document) where TDocument : IDocument - { - FormatDocument(document); - await HandlePartitioned(document).InsertOneAsync(document); - } - - /// - /// Adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - public void AddOne(TDocument document) where TDocument : IDocument - { - FormatDocument(document); - HandlePartitioned(document).InsertOne(document); - } - - /// - /// Asynchronously adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The documents you want to add. - public async Task AddManyAsync(IEnumerable documents) where TDocument : IDocument - { - if (!documents.Any()) - { - return; - } - foreach (var doc in documents) - { - FormatDocument(doc); - } - await HandlePartitioned(documents.FirstOrDefault()).InsertManyAsync(documents); - } - - /// - /// Adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The documents you want to add. - public void AddMany(IEnumerable documents) where TDocument : IDocument - { - if (!documents.Any()) - { - return; - } - foreach (var document in documents) - { - FormatDocument(document); - } - HandlePartitioned(documents.FirstOrDefault()).InsertMany(documents.ToList()); - } - - #endregion Create - - #region Read - - /// - /// Asynchronously returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - public async Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument - { - var filter = Builders.Filter.Eq("Id", id); - return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); - } - - /// - /// Returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - public TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument - { - var filter = Builders.Filter.Eq("Id", id); - return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); - } - - /// - /// Asynchronously returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); - } - - /// - /// Returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); - } - - /// - /// Returns a collection cursor. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter); - } - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - var count = await HandlePartitioned(partitionKey).CountAsync(filter); - return (count > 0); - } - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - var count = HandlePartitioned(partitionKey).Count(filter); - return (count > 0); - } - - /// - /// Asynchronously returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); - } - - /// - /// Returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter).ToList(); - } - - /// - /// Asynchronously counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partitionKey - public async Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).CountAsync(filter); - } - - /// - /// Counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partitionKey - public long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter).Count(); - } - - #endregion - - #region Update - - /// - /// Asynchronously Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - public async Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument - { - var updateRes = await HandlePartitioned(modifiedDocument).ReplaceOneAsync(x => x.Id == modifiedDocument.Id, modifiedDocument); - return updateRes.ModifiedCount == 1; - } - - /// - /// Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - public bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument - { - var updateRes = HandlePartitioned(modifiedDocument).ReplaceOne(x => x.Id == modifiedDocument.Id, modifiedDocument); - return updateRes.ModifiedCount == 1; - } - - #endregion Update - - #region Delete - - /// - /// Asynchronously deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - public async Task DeleteOneAsync(TDocument document) where TDocument : IDocument - { - return (await HandlePartitioned(document).DeleteOneAsync(x => x.Id == document.Id)).DeletedCount; - } - - /// - /// Deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - public long DeleteOne(TDocument document) where TDocument : IDocument - { - return HandlePartitioned(document).DeleteOne(x => x.Id == document.Id).DeletedCount; - } - - /// - /// Deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).DeleteOne(filter).DeletedCount; - } - - /// - /// Asynchronously deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public async Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return (await HandlePartitioned(partitionKey).DeleteOneAsync(filter)).DeletedCount; - } - - /// - /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public async Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return (await HandlePartitioned(partitionKey).DeleteManyAsync(filter)).DeletedCount; - } - - /// - /// Asynchronously deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - public async Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument - { - if (!documents.Any()) - { - return 0; - } - var idsTodelete = documents.Select(e => e.Id).ToArray(); - return (await HandlePartitioned(documents.FirstOrDefault()).DeleteManyAsync(x => idsTodelete.Contains(x.Id))).DeletedCount; - } - - /// - /// Deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - public long DeleteMany(IEnumerable documents) where TDocument : IDocument - { - if (!documents.Any()) - { - return 0; - } - var idsTodelete = documents.Select(e => e.Id).ToArray(); - return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; - } - - /// - /// Deletes a list of documents. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The list of documents to delete. - /// The number of documents deleted. - public long DeleteMany(IEnumerable documents) - where TDocument : IDocument - where TKey : IEquatable - { - if (!documents.Any()) - { - return 0; - } - var idsTodelete = documents.Select(e => e.Id).ToArray(); - return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; - } - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; - } - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public long DeleteMany(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; - } - - #endregion Delete - - #region Project - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class - { - return await HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .FirstOrDefaultAsync(); - } - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class - { - return await HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .FirstOrDefaultAsync(); - } - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class - { - return HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .FirstOrDefault(); - } - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class - { - return HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .FirstOrDefault(); - } - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class - { - return await HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .ToListAsync(); - } - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class - { - return await HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .ToListAsync(); - } - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class - { - return HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .ToList(); - } - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class - { - return HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .ToList(); - } - - #endregion - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); - } - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); - } - - #region Find And Update - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// - /// - /// - /// - public async Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) where TDocument : IDocument - { - return await GetCollection().FindOneAndUpdateAsync(filter, update, options); - } - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// - /// - /// - public async Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) - where TDocument : IDocument - where TKey : IEquatable - { - return await GetCollection().FindOneAndUpdateAsync(filter, update, options); - } - - #endregion Find And Update - - #region Private Methods - - private IMongoCollection GetCollection(string partitionKey) where TDocument : IDocument - { - return MongoDbContext.GetCollection(partitionKey); - } - - private IMongoCollection GetCollection() where TDocument : IDocument - { - return MongoDbContext.GetCollection(); - } - - private IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument - { - if (document is IPartitionedDocument) - { - return GetCollection(((IPartitionedDocument)document).PartitionKey); - } - return GetCollection(); - } - - private IMongoCollection HandlePartitioned(TDocument document) - where TDocument : IDocument - where TKey : IEquatable - { - if (document is IPartitionedDocument) - { - return GetCollection(((IPartitionedDocument)document).PartitionKey); - } - return GetCollection(); - } - - private IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument - { - if (!string.IsNullOrEmpty(partitionKey)) - { - return GetCollection(partitionKey); - } - return GetCollection(); - } - - private void FormatDocument(TDocument document) where TDocument : IDocument - { - if (document == null) - { - throw new ArgumentNullException(nameof(document)); - } - if (document.Id == default(Guid)) - { - document.Id = Guid.NewGuid(); - } - } - - - private IMongoCollection GetCollection(string partitionKey) - where TDocument : IDocument - where TKey : IEquatable - { - return MongoDbContext.GetCollection(partitionKey); - } - - private IMongoCollection GetCollection() - where TDocument : IDocument - where TKey : IEquatable - { - return MongoDbContext.GetCollection(); - } - - private IMongoCollection HandlePartitioned(string partitionKey) - where TDocument : IDocument - where TKey : IEquatable - { - if (!string.IsNullOrEmpty(partitionKey)) - { - return GetCollection(partitionKey); - } - return GetCollection(); - } - - private void FormatDocument(TDocument document) - where TDocument : IDocument - where TKey : IEquatable - { - if (document == null) - { - throw new ArgumentNullException(nameof(document)); - } - } - - #endregion - } +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq.Expressions; +using MongoDbGenericRepository.Models; +using System.Linq; + +namespace MongoDbGenericRepository +{ + /// + /// The IBaseMongoRepository exposes the functionality of the BaseMongoRepository. + /// + public interface IBaseMongoRepository + { + /// + /// The connection string. + /// + string ConnectionString { get; set; } + /// + /// The database name. + /// + string DatabaseName { get; set; } + + #region Create + + /// + /// Asynchronously adds a document to the collection. + /// + /// The type representing a Document. + /// The document you want to add. + Task AddOneAsync(TDocument document) where TDocument : IDocument; + + /// + /// Asynchronously adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + Task AddOneAsync(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + void AddOne(TDocument document) where TDocument : IDocument; + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + void AddOne(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + Task AddManyAsync(IEnumerable documents) where TDocument : IDocument; + + /// + /// Adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + void AddMany(IEnumerable documents) where TDocument : IDocument; + + #endregion + + #region Read + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + #endregion + + #region Update + + /// + /// Asynchronously Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument; + + /// + /// Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument; + + #endregion + + #region Delete + + /// + /// Asynchronously deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + Task DeleteOneAsync(TDocument document) where TDocument : IDocument; + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + long DeleteOne(TDocument document) where TDocument : IDocument; + + /// + /// Deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument; + + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + long DeleteMany(IEnumerable documents) where TDocument : IDocument; + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteMany(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + #endregion + + #region Project + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + #endregion + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument; + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// + /// + /// + /// + Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument; + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// + /// + /// + Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument + where TKey : IEquatable; + + } + + /// + /// The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. + /// Its constructor must be given a connection string and a database name. + /// + public abstract class BaseMongoRepository : IBaseMongoRepository + { + /// + /// The connection string. + /// + public string ConnectionString { get; set; } + + /// + /// The database name. + /// + public string DatabaseName { get; set; } + + /// + /// The constructor taking a connection string and a database name. + /// + /// The connection string of the MongoDb server. + /// The name of the database against which you want to perform operations. + protected BaseMongoRepository(string connectionString, string databaseName) + { + MongoDbContext = new MongoDbContext(connectionString, databaseName); + } + + /// + /// The contructor taking a . + /// + /// A mongodb context implementing + protected BaseMongoRepository(IMongoDbContext mongoDbContext) + { + MongoDbContext = mongoDbContext; + } + + /// + /// The MongoDbContext + /// + protected IMongoDbContext MongoDbContext = null; + + #region Create + + /// + /// Asynchronously adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + public async Task AddOneAsync(TDocument document) where TDocument : IDocument + { + FormatDocument(document); + await HandlePartitioned(document).InsertOneAsync(document); + } + + /// + /// Asynchronously adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + public async Task AddOneAsync(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + FormatDocument(document); + await HandlePartitioned(document).InsertOneAsync(document); + } + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + public void AddOne(TDocument document) where TDocument : IDocument + { + FormatDocument(document); + HandlePartitioned(document).InsertOne(document); + } + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + public void AddOne(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + FormatDocument(document); + HandlePartitioned(document).InsertOne(document); + } + + /// + /// Asynchronously adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The documents you want to add. + public async Task AddManyAsync(IEnumerable documents) where TDocument : IDocument + { + if (!documents.Any()) + { + return; + } + foreach (var doc in documents) + { + FormatDocument(doc); + } + await HandlePartitioned(documents.FirstOrDefault()).InsertManyAsync(documents); + } + + /// + /// Asynchronously adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The documents you want to add. + public async Task AddManyAsync(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable + { + if (!documents.Any()) + { + return; + } + foreach (var doc in documents) + { + FormatDocument(doc); + } + await HandlePartitioned(documents.FirstOrDefault()).InsertManyAsync(documents); + } + + /// + /// Adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The documents you want to add. + public void AddMany(IEnumerable documents) where TDocument : IDocument + { + if (!documents.Any()) + { + return; + } + foreach (var document in documents) + { + FormatDocument(document); + } + HandlePartitioned(documents.FirstOrDefault()).InsertMany(documents.ToList()); + } + + #endregion Create + + #region Read + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public async Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", id); + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", id); + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + var count = await HandlePartitioned(partitionKey).CountAsync(filter); + return (count > 0); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + var count = HandlePartitioned(partitionKey).Count(filter); + return (count > 0); + } + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); + } + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter).ToList(); + } + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public async Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).CountAsync(filter); + } + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter).Count(); + } + + #endregion + + #region Read TKey + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public async Task GetByIdAsync(Guid id, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", id); + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public TDocument GetById(Guid id, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", id); + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task GetOneAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public TDocument GetOne(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public IFindFluent GetCursor(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task AnyAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + var count = await HandlePartitioned(partitionKey).CountAsync(filter); + return (count > 0); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public bool Any(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + var count = HandlePartitioned(partitionKey).Count(filter); + return (count > 0); + } + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task> GetAllAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); + } + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public List GetAll(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter).ToList(); + } + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public async Task CountAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).CountAsync(filter); + } + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public long Count(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter).Count(); + } + + #endregion + + #region Update + + /// + /// Asynchronously Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + public async Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument + { + var updateRes = await HandlePartitioned(modifiedDocument).ReplaceOneAsync(x => x.Id == modifiedDocument.Id, modifiedDocument); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + public bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument + { + var updateRes = HandlePartitioned(modifiedDocument).ReplaceOne(x => x.Id == modifiedDocument.Id, modifiedDocument); + return updateRes.ModifiedCount == 1; + } + + #endregion Update + + #region Update TKey + + /// + /// Asynchronously Updates a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document with the modifications you want to persist. + public async Task UpdateOneAsync(TDocument modifiedDocument) + where TDocument : IDocument where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", modifiedDocument.Id); + var updateRes = await HandlePartitioned(modifiedDocument).ReplaceOneAsync(filter, modifiedDocument); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document with the modifications you want to persist. + public bool UpdateOne(TDocument modifiedDocument) + where TDocument : IDocument where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", modifiedDocument.Id); + var updateRes = HandlePartitioned(modifiedDocument).ReplaceOne(filter, modifiedDocument); + return updateRes.ModifiedCount == 1; + } + + #endregion Update + + #region Delete + + /// + /// Asynchronously deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + public async Task DeleteOneAsync(TDocument document) where TDocument : IDocument + { + return (await HandlePartitioned(document).DeleteOneAsync(x => x.Id == document.Id)).DeletedCount; + } + + /// + /// Deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + public long DeleteOne(TDocument document) where TDocument : IDocument + { + return HandlePartitioned(document).DeleteOne(x => x.Id == document.Id).DeletedCount; + } + + /// + /// Deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).DeleteOne(filter).DeletedCount; + } + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public async Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return (await HandlePartitioned(partitionKey).DeleteOneAsync(filter)).DeletedCount; + } + + /// + /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public async Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return (await HandlePartitioned(partitionKey).DeleteManyAsync(filter)).DeletedCount; + } + + /// + /// Asynchronously deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + public async Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument + { + if (!documents.Any()) + { + return 0; + } + var idsTodelete = documents.Select(e => e.Id).ToArray(); + return (await HandlePartitioned(documents.FirstOrDefault()).DeleteManyAsync(x => idsTodelete.Contains(x.Id))).DeletedCount; + } + + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + public long DeleteMany(IEnumerable documents) where TDocument : IDocument + { + if (!documents.Any()) + { + return 0; + } + var idsTodelete = documents.Select(e => e.Id).ToArray(); + return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; + } + + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The list of documents to delete. + /// The number of documents deleted. + public long DeleteMany(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable + { + if (!documents.Any()) + { + return 0; + } + var idsTodelete = documents.Select(e => e.Id).ToArray(); + return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; + } + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; + } + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public long DeleteMany(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; + } + + #endregion Delete + + #region Project + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefaultAsync(); + } + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefaultAsync(); + } + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefault(); + } + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefault(); + } + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToListAsync(); + } + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToListAsync(); + } + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToList(); + } + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToList(); + } + + #endregion + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); + } + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); + } + + #region Find And Update + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// + /// + /// + /// + public async Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) where TDocument : IDocument + { + return await GetCollection().FindOneAndUpdateAsync(filter, update, options); + } + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// + /// + /// + public async Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument + where TKey : IEquatable + { + return await GetCollection().FindOneAndUpdateAsync(filter, update, options); + } + + #endregion Find And Update + + #region Private Methods + + private IMongoCollection GetCollection(string partitionKey) where TDocument : IDocument + { + return MongoDbContext.GetCollection(partitionKey); + } + + private IMongoCollection GetCollection() where TDocument : IDocument + { + return MongoDbContext.GetCollection(); + } + + private IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument + { + if (document is IPartitionedDocument) + { + return GetCollection(((IPartitionedDocument)document).PartitionKey); + } + return GetCollection(); + } + + private IMongoCollection HandlePartitioned(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + if (document is IPartitionedDocument) + { + return GetCollection(((IPartitionedDocument)document).PartitionKey); + } + return GetCollection(); + } + + private IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument + { + if (!string.IsNullOrEmpty(partitionKey)) + { + return GetCollection(partitionKey); + } + return GetCollection(); + } + + private void FormatDocument(TDocument document) where TDocument : IDocument + { + if (document == null) + { + throw new ArgumentNullException(nameof(document)); + } + if (document.Id == default(Guid)) + { + document.Id = Guid.NewGuid(); + } + } + + + private IMongoCollection GetCollection(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable + { + return MongoDbContext.GetCollection(partitionKey); + } + + private IMongoCollection GetCollection() + where TDocument : IDocument + where TKey : IEquatable + { + return MongoDbContext.GetCollection(); + } + + private IMongoCollection HandlePartitioned(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable + { + if (!string.IsNullOrEmpty(partitionKey)) + { + return GetCollection(partitionKey); + } + return GetCollection(); + } + + private void FormatDocument(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + if (document == null) + { + throw new ArgumentNullException(nameof(document)); + } + } + + #endregion + } } \ No newline at end of file From 1d985e0274ab1ac8af15303171fd1fe5396d21f9 Mon Sep 17 00:00:00 2001 From: alexandre-spieser Date: Sun, 24 Sep 2017 21:34:29 +0000 Subject: [PATCH 3/7] Added tests --- .../CreateTKeyPartitionedTests.cs | 77 +++ IntegrationTests/CreateTKeyTests.cs | 75 +++ .../DeletePartitionedTKeyTests.cs | 137 +++++ IntegrationTests/DeleteTKeyTests.cs | 135 +++++ .../BaseMongoDbRepositoryTests.cs | 2 +- IntegrationTests/IntegrationTests.csproj | 5 + IntegrationTests/ProjectTKeyTests.cs | 152 +++++ .../BaseMongoDbRepository.cs | 553 +++++++++++++++--- MongoDbGenericRepository/Models/IDocument.cs | 6 +- 9 files changed, 1063 insertions(+), 79 deletions(-) create mode 100644 IntegrationTests/CreateTKeyPartitionedTests.cs create mode 100644 IntegrationTests/CreateTKeyTests.cs create mode 100644 IntegrationTests/DeletePartitionedTKeyTests.cs create mode 100644 IntegrationTests/DeleteTKeyTests.cs create mode 100644 IntegrationTests/ProjectTKeyTests.cs diff --git a/IntegrationTests/CreateTKeyPartitionedTests.cs b/IntegrationTests/CreateTKeyPartitionedTests.cs new file mode 100644 index 0000000..4cc8fa2 --- /dev/null +++ b/IntegrationTests/CreateTKeyPartitionedTests.cs @@ -0,0 +1,77 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + + public class CreateTestsPartitionedTKeyDocument : IDocument, IPartitionedDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public CreateTestsPartitionedTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + PartitionKey = "TestPartitionKey"; + } + public string PartitionKey { get; set; } + public string SomeContent { get; set; } + } + + public class CreatePartitionedTKeyTests : BaseMongoDbRepositoryTests + { + [Test] + public void PartitionedAddOne() + { + // Arrange + var document = new CreateTestsPartitionedTKeyDocument(); + // Act + SUT.AddOne(document); + // Assert + long count = SUT.Count(e => e.Id == document.Id, PartitionKey); + Assert.AreEqual(1, count); + } + + [Test] + public async Task PartitionedAddOneAsync() + { + // Arrange + var document = new CreateTestsPartitionedTKeyDocument(); + // Act + await SUT.AddOneAsync(document); + // Assert + long count = SUT.Count(e => e.Id == document.Id, PartitionKey); + Assert.AreEqual(1, count); + } + + [Test] + public void PartitionedAddMany() + { + // Arrange + var documents = new List { new CreateTestsPartitionedTKeyDocument(), new CreateTestsPartitionedTKeyDocument() }; + // Act + SUT.AddMany(documents); + // Assert + long count = SUT.Count(e => e.Id == documents[0].Id || e.Id == documents[1].Id, PartitionKey); + Assert.AreEqual(2, count); + } + + [Test] + public async Task PartitionedAddManyAsync() + { + // Arrange + var documents = new List { new CreateTestsPartitionedTKeyDocument(), new CreateTestsPartitionedTKeyDocument() }; + // Act + await SUT.AddManyAsync(documents); + // Assert + long count = SUT.Count(e => e.Id == documents[0].Id || e.Id == documents[1].Id, PartitionKey); + Assert.AreEqual(2, count); + } + } +} diff --git a/IntegrationTests/CreateTKeyTests.cs b/IntegrationTests/CreateTKeyTests.cs new file mode 100644 index 0000000..f709ba7 --- /dev/null +++ b/IntegrationTests/CreateTKeyTests.cs @@ -0,0 +1,75 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + public class CreateTestsTKeyDocument : IDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public CreateTestsTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + } + public string SomeContent { get; set; } + } + + [TestFixture] + public class CreateTKeyTests : BaseMongoDbRepositoryTests + { + [Test] + public void TKeyAddOne() + { + // Arrange + var document = new CreateTestsTKeyDocument(); + // Act + SUT.AddOne(document); + // Assert + long count = SUT.Count(e => e.Id == document.Id); + Assert.AreEqual(1, count); + } + + [Test] + public async Task TKeyAddOneAsync() + { + // Arrange + var document = new CreateTestsTKeyDocument(); + // Act + await SUT.AddOneAsync(document); + // Assert + long count = SUT.Count(e => e.Id == document.Id); + Assert.AreEqual(1, count); + } + + [Test] + public void TKeyAddMany() + { + // Arrange + var documents = new List { new CreateTestsTKeyDocument(), new CreateTestsTKeyDocument() }; + // Act + SUT.AddMany(documents); + // Assert + long count = SUT.Count(e => e.Id == documents[0].Id || e.Id == documents[1].Id); + Assert.AreEqual(2, count); + } + + [Test] + public async Task TKeyAddManyAsync() + { + // Arrange + var documents = new List { new CreateTestsTKeyDocument(), new CreateTestsTKeyDocument() }; + // Act + await SUT.AddManyAsync(documents); + // Assert + long count = SUT.Count(e => e.Id == documents[0].Id || e.Id == documents[1].Id); + Assert.AreEqual(2, count); + } + } +} diff --git a/IntegrationTests/DeletePartitionedTKeyTests.cs b/IntegrationTests/DeletePartitionedTKeyTests.cs new file mode 100644 index 0000000..b213cb4 --- /dev/null +++ b/IntegrationTests/DeletePartitionedTKeyTests.cs @@ -0,0 +1,137 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + public class DeleteTestsPartitionedTKeyDocument : IPartitionedDocument, IDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public DeleteTestsPartitionedTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + PartitionKey = "TestPartitionKey"; + } + public string PartitionKey { get; set; } + public string SomeContent { get; set; } + } + + public class DeletePartitionedTKeyTests : BaseMongoDbRepositoryTests + { + [Test] + public void PartitionedDeleteOne() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.DeleteOne(document); + // Assert + Assert.AreEqual(1, result); + Assert.IsFalse(SUT.Any(e => e.Id == document.Id, PartitionKey)); + } + + [Test] + public void PartitionedDeleteOneLinq() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.DeleteOne(e => e.Id == document.Id, PartitionKey); + // Assert + Assert.AreEqual(1, result); + Assert.IsFalse(SUT.Any(e => e.Id == document.Id, PartitionKey)); + } + + [Test] + public async Task PartitionedDeleteOneAsync() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.DeleteOneAsync(document); + // Assert + Assert.AreEqual(1, result); + Assert.IsFalse(SUT.Any(e => e.Id == document.Id, PartitionKey)); + } + + [Test] + public async Task PartitionedDeleteOneAsyncLinq() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.DeleteOneAsync(e => e.Id == document.Id, PartitionKey); + // Assert + Assert.AreEqual(1, result); + Assert.IsFalse(SUT.Any(e => e.Id == document.Id, PartitionKey)); + } + + [Test] + public async Task PartitionedDeleteManyAsyncLinq() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "DeleteManyAsyncLinqContent"); + SUT.AddMany(documents); + // Act + var result = await SUT.DeleteManyAsync(e => e.SomeContent == "DeleteManyAsyncLinqContent", PartitionKey); + // Assert + Assert.AreEqual(5, result); + Assert.IsFalse(SUT.Any(e => e.SomeContent == "DeleteManyAsyncLinqContent", PartitionKey)); + } + + [Test] + public async Task PartitionedDeleteManyAsync() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "DeleteManyAsyncLinqContent"); + SUT.AddMany(documents); + // Act + var result = await SUT.DeleteManyAsync(documents); + // Assert + Assert.AreEqual(5, result); + Assert.IsFalse(SUT.Any(e => e.SomeContent == "DeleteManyAsyncLinqContent", PartitionKey)); + } + + [Test] + public void PartitionedDeleteManyLinq() + { + // Arrange + var content = "DeleteManyLinqContent"; + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = content); + SUT.AddMany(documents); + // Act + var result = SUT.DeleteMany(e => e.SomeContent == content, PartitionKey); + // Assert + Assert.AreEqual(5, result); + Assert.IsFalse(SUT.Any(e => e.SomeContent == content, PartitionKey)); + } + + [Test] + public void PartitionedDeleteMany() + { + // Arrange + var content = "DeleteManyContent"; + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = content); + SUT.AddMany(documents); + // Act + var result = SUT.DeleteMany(documents); + // Assert + Assert.AreEqual(5, result); + Assert.IsFalse(SUT.Any(e => e.SomeContent == content, PartitionKey)); + } + } +} diff --git a/IntegrationTests/DeleteTKeyTests.cs b/IntegrationTests/DeleteTKeyTests.cs new file mode 100644 index 0000000..dd90c09 --- /dev/null +++ b/IntegrationTests/DeleteTKeyTests.cs @@ -0,0 +1,135 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + public class DeleteTestsTKeyDocument : IDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public DeleteTestsTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + } + public string SomeContent { get; set; } + } + + public class DeleteTKeyTests : BaseMongoDbRepositoryTests + { + [Test] + public void DeleteOne() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.DeleteOne(document); + // Assert + Assert.AreEqual(1, result); + Assert.IsFalse(SUT.Any(e => e.Id == document.Id)); + } + + [Test] + public void DeleteOneLinq() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.DeleteOne(e => e.Id == document.Id); + // Assert + Assert.AreEqual(1, result); + Assert.IsFalse(SUT.Any(e => e.Id == document.Id)); + } + + [Test] + public async Task DeleteOneAsync() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.DeleteOneAsync(document); + // Assert + Assert.AreEqual(1, result); + Assert.IsFalse(SUT.Any(e => e.Id == document.Id)); + } + + [Test] + public async Task DeleteOneAsyncLinq() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.DeleteOneAsync(e => e.Id == document.Id); + // Assert + Assert.AreEqual(1, result); + Assert.IsFalse(SUT.Any(e => e.Id == document.Id)); + } + + [Test] + public async Task DeleteManyAsyncLinq() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "DeleteManyAsyncLinqContent"); + SUT.AddMany(documents); + // Act + var result = await SUT.DeleteManyAsync(e => e.SomeContent == "DeleteManyAsyncLinqContent"); + // Assert + Assert.AreEqual(5, result); + Assert.IsFalse(SUT.Any(e => e.SomeContent == "DeleteManyAsyncLinqContent")); + } + + [Test] + public async Task DeleteManyAsync() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "DeleteManyAsyncLinqContent"); + SUT.AddMany(documents); + // Act + var result = await SUT.DeleteManyAsync(documents); + // Assert + Assert.AreEqual(5, result); + Assert.IsFalse(SUT.Any(e => e.SomeContent == "DeleteManyAsyncLinqContent")); + } + + [Test] + public void DeleteManyLinq() + { + // Arrange + var content = "DeleteManyLinqContent"; + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = content); + SUT.AddMany(documents); + // Act + var result = SUT.DeleteMany(e => e.SomeContent == content); + // Assert + Assert.AreEqual(5, result); + Assert.IsFalse(SUT.Any(e => e.SomeContent == content)); + } + + [Test] + public void DeleteMany() + { + // Arrange + var content = "DeleteManyContent"; + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = content); + SUT.AddMany(documents); + // Act + var result = SUT.DeleteMany(documents); + // Assert + Assert.AreEqual(5, result); + Assert.IsFalse(SUT.Any(e => e.SomeContent == content)); + } + } +} diff --git a/IntegrationTests/Infrastructure/BaseMongoDbRepositoryTests.cs b/IntegrationTests/Infrastructure/BaseMongoDbRepositoryTests.cs index 74d358e..1c7b43f 100644 --- a/IntegrationTests/Infrastructure/BaseMongoDbRepositoryTests.cs +++ b/IntegrationTests/Infrastructure/BaseMongoDbRepositoryTests.cs @@ -5,7 +5,7 @@ using System.Configuration; namespace IntegrationTests.Infrastructure { - public class BaseMongoDbRepositoryTests where T : Document, new() + public class BaseMongoDbRepositoryTests where T : class, new() { public T CreateTestDocument() { diff --git a/IntegrationTests/IntegrationTests.csproj b/IntegrationTests/IntegrationTests.csproj index 580fb5d..b2bef91 100644 --- a/IntegrationTests/IntegrationTests.csproj +++ b/IntegrationTests/IntegrationTests.csproj @@ -52,7 +52,11 @@ + + + + @@ -60,6 +64,7 @@ + diff --git a/IntegrationTests/ProjectTKeyTests.cs b/IntegrationTests/ProjectTKeyTests.cs new file mode 100644 index 0000000..614892a --- /dev/null +++ b/IntegrationTests/ProjectTKeyTests.cs @@ -0,0 +1,152 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + public class NestedTKey + { + public DateTime SomeDate { get; set; } + } + + public class MyProjectionTKey + { + public DateTime SomeDate { get; set; } + public string SomeContent { get; set; } + } + + public class ProjectTestsTKeyDocument : IDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public ProjectTestsTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + Nested = new NestedTKey + { + SomeDate = DateTime.UtcNow + }; + } + public string SomeContent { get; set; } + public NestedTKey Nested { get; set; } + } + + public class ProjectTKeyTests : BaseMongoDbRepositoryTests + { + + + [Test] + public async Task ProjectOneAsync() + { + // Arrange + const string someContent = "ProjectOneAsyncContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocument(); + document.SomeContent = someContent; + document.Nested.SomeDate = someDate; + SUT.AddOne(document); + // Act + var result = await SUT.ProjectOneAsync( + x => x.Id == document.Id, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }); + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(someContent, result.SomeContent); + Assert.AreEqual(someDate.Minute, result.SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.SomeDate.Second); + } + + [Test] + public void ProjectOne() + { + // Arrange + const string someContent = "ProjectOneContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocument(); + document.SomeContent = someContent; + document.Nested.SomeDate = someDate; + SUT.AddOne(document); + // Act + var result = SUT.ProjectOne( + x => x.Id == document.Id, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }); + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(someContent, result.SomeContent); + Assert.AreEqual(someDate.Minute, result.SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.SomeDate.Second); + } + + [Test] + public async Task ProjectManyAsync() + { + // Arrange + const string someContent = "ProjectManyAsyncContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocuments(5); + document.ForEach(e => + { + e.SomeContent = someContent; + e.Nested.SomeDate = someDate; + }); + + SUT.AddMany(document); + // Act + var result = await SUT.ProjectManyAsync( + x => x.SomeContent == someContent, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }); + // Assert + Assert.AreEqual(5, result.Count); + Assert.AreEqual(someContent, result.First().SomeContent); + Assert.AreEqual(someDate.Minute, result.First().SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.First().SomeDate.Second); + } + + [Test] + public void ProjectMany() + { + // Arrange + const string someContent = "ProjectManyContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocuments(5); + document.ForEach(e => + { + e.SomeContent = someContent; + e.Nested.SomeDate = someDate; + }); + + SUT.AddMany(document); + // Act + var result = SUT.ProjectMany( + x => x.SomeContent == someContent, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }); + // Assert + Assert.AreEqual(5, result.Count); + Assert.AreEqual(someContent, result.First().SomeContent); + Assert.AreEqual(someDate.Minute, result.First().SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.First().SomeDate.Second); + } + } +} diff --git a/MongoDbGenericRepository/BaseMongoDbRepository.cs b/MongoDbGenericRepository/BaseMongoDbRepository.cs index f7f566c..630a535 100644 --- a/MongoDbGenericRepository/BaseMongoDbRepository.cs +++ b/MongoDbGenericRepository/BaseMongoDbRepository.cs @@ -31,6 +31,34 @@ namespace MongoDbGenericRepository /// The document you want to add. Task AddOneAsync(TDocument document) where TDocument : IDocument; + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + void AddOne(TDocument document) where TDocument : IDocument; + + /// + /// Asynchronously adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + Task AddManyAsync(IEnumerable documents) where TDocument : IDocument; + + /// + /// Adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + void AddMany(IEnumerable documents) where TDocument : IDocument; + + #endregion + + #region Create TKey + /// /// Asynchronously adds a document to the collection. /// Populates the Id and AddedAtUtc fields if necessary. @@ -42,14 +70,6 @@ namespace MongoDbGenericRepository where TDocument : IDocument where TKey : IEquatable; - /// - /// Adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - void AddOne(TDocument document) where TDocument : IDocument; - /// /// Adds a document to the collection. /// Populates the Id and AddedAtUtc fields if necessary. @@ -66,16 +86,22 @@ namespace MongoDbGenericRepository /// Populates the Id and AddedAtUtc fields if necessary. /// /// The type representing a Document. - /// The document you want to add. - Task AddManyAsync(IEnumerable documents) where TDocument : IDocument; + /// The type of the primary key for a Document. + /// The documents you want to add. + Task AddManyAsync(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable; /// /// Adds a list of documents to the collection. /// Populates the Id and AddedAtUtc fields if necessary. /// /// The type representing a Document. - /// The document you want to add. - void AddMany(IEnumerable documents) where TDocument : IDocument; + /// The type of the primary key for a Document. + /// The documents you want to add. + void AddMany(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable; #endregion @@ -171,6 +197,134 @@ namespace MongoDbGenericRepository #endregion + #region Read TKey + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + Task GetByIdAsync(Guid id, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + TDocument GetById(Guid id, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task GetOneAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + TDocument GetOne(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + IFindFluent GetCursor(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task AnyAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + bool Any(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task> GetAllAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + List GetAll(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + Task CountAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + long Count(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + #endregion + + #region Update /// @@ -189,6 +343,30 @@ namespace MongoDbGenericRepository #endregion + #region Update TKey + + /// + /// Asynchronously Updates a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document with the modifications you want to persist. + Task UpdateOneAsync(TDocument modifiedDocument) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document with the modifications you want to persist. + bool UpdateOne(TDocument modifiedDocument) + where TDocument : IDocument + where TKey : IEquatable; + + #endregion + #region Delete /// @@ -259,6 +437,90 @@ namespace MongoDbGenericRepository /// The number of documents deleted. long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument; + #endregion + + #region Delete TKey + + /// + /// Deletes a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to delete. + /// The number of documents deleted. + long DeleteOne(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to delete. + /// The number of documents deleted. + Task DeleteOneAsync(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteOne(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteOneAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteManyAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously deletes a list of documents. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The list of documents to delete. + /// The number of documents deleted. + Task DeleteManyAsync(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The list of documents to delete. + /// The number of documents deleted. + long DeleteMany(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable; + /// /// Deletes the documents matching the condition of the LINQ expression filter. /// @@ -273,7 +535,8 @@ namespace MongoDbGenericRepository #endregion - #region Project + + #region Project /// /// Asynchronously returns a projected document matching the filter condition. @@ -413,7 +676,7 @@ namespace MongoDbGenericRepository /// /// /// - Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) where TDocument : IDocument; /// @@ -485,21 +748,6 @@ namespace MongoDbGenericRepository await HandlePartitioned(document).InsertOneAsync(document); } - /// - /// Asynchronously adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document you want to add. - public async Task AddOneAsync(TDocument document) - where TDocument : IDocument - where TKey : IEquatable - { - FormatDocument(document); - await HandlePartitioned(document).InsertOneAsync(document); - } - /// /// Adds a document to the collection. /// Populates the Id and AddedAtUtc fields if necessary. @@ -512,21 +760,6 @@ namespace MongoDbGenericRepository HandlePartitioned(document).InsertOne(document); } - /// - /// Adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document you want to add. - public void AddOne(TDocument document) - where TDocument : IDocument - where TKey : IEquatable - { - FormatDocument(document); - HandlePartitioned(document).InsertOne(document); - } - /// /// Asynchronously adds a list of documents to the collection. /// Populates the Id and AddedAtUtc fields if necessary. @@ -546,6 +779,59 @@ namespace MongoDbGenericRepository await HandlePartitioned(documents.FirstOrDefault()).InsertManyAsync(documents); } + /// + /// Adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The documents you want to add. + public void AddMany(IEnumerable documents) where TDocument : IDocument + { + if (!documents.Any()) + { + return; + } + foreach (var document in documents) + { + FormatDocument(document); + } + HandlePartitioned(documents.FirstOrDefault()).InsertMany(documents.ToList()); + } + + #endregion Create + + #region Create TKey + + /// + /// Asynchronously adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + public async Task AddOneAsync(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + FormatDocument(document); + await HandlePartitioned(document).InsertOneAsync(document); + } + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + public void AddOne(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + FormatDocument(document); + HandlePartitioned(document).InsertOne(document); + } + /// /// Asynchronously adds a list of documents to the collection. /// Populates the Id and AddedAtUtc fields if necessary. @@ -573,8 +859,11 @@ namespace MongoDbGenericRepository /// Populates the Id and AddedAtUtc fields if necessary. /// /// The type representing a Document. + /// The type of the primary key for a Document. /// The documents you want to add. - public void AddMany(IEnumerable documents) where TDocument : IDocument + public void AddMany(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable { if (!documents.Any()) { @@ -582,12 +871,13 @@ namespace MongoDbGenericRepository } foreach (var document in documents) { - FormatDocument(document); + FormatDocument(document); } - HandlePartitioned(documents.FirstOrDefault()).InsertMany(documents.ToList()); + HandlePartitioned(documents.FirstOrDefault()).InsertMany(documents.ToList()); } - #endregion Create + + #endregion #region Read @@ -728,7 +1018,8 @@ namespace MongoDbGenericRepository /// The Id of the document you want to get. /// An optional partition key. public async Task GetByIdAsync(Guid id, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { var filter = Builders.Filter.Eq("Id", id); return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); @@ -742,7 +1033,8 @@ namespace MongoDbGenericRepository /// The Id of the document you want to get. /// An optional partition key. public TDocument GetById(Guid id, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { var filter = Builders.Filter.Eq("Id", id); return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); @@ -756,7 +1048,8 @@ namespace MongoDbGenericRepository /// A LINQ expression filter. /// An optional partition key. public async Task GetOneAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); } @@ -769,7 +1062,8 @@ namespace MongoDbGenericRepository /// A LINQ expression filter. /// An optional partition key. public TDocument GetOne(Expression> filter, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); } @@ -782,7 +1076,8 @@ namespace MongoDbGenericRepository /// A LINQ expression filter. /// An optional partition key. public IFindFluent GetCursor(Expression> filter, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(filter); } @@ -795,7 +1090,8 @@ namespace MongoDbGenericRepository /// A LINQ expression filter. /// An optional partition key. public async Task AnyAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { var count = await HandlePartitioned(partitionKey).CountAsync(filter); return (count > 0); @@ -809,7 +1105,8 @@ namespace MongoDbGenericRepository /// A LINQ expression filter. /// An optional partition key. public bool Any(Expression> filter, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { var count = HandlePartitioned(partitionKey).Count(filter); return (count > 0); @@ -823,7 +1120,8 @@ namespace MongoDbGenericRepository /// A LINQ expression filter. /// An optional partition key. public async Task> GetAllAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); } @@ -836,7 +1134,8 @@ namespace MongoDbGenericRepository /// A LINQ expression filter. /// An optional partition key. public List GetAll(Expression> filter, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(filter).ToList(); } @@ -849,7 +1148,8 @@ namespace MongoDbGenericRepository /// A LINQ expression filter. /// An optional partitionKey public async Task CountAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { return await HandlePartitioned(partitionKey).CountAsync(filter); } @@ -862,7 +1162,8 @@ namespace MongoDbGenericRepository /// A LINQ expression filter. /// An optional partitionKey public long Count(Expression> filter, string partitionKey = null) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(filter).Count(); } @@ -904,7 +1205,8 @@ namespace MongoDbGenericRepository /// The type of the primary key for a Document. /// The document with the modifications you want to persist. public async Task UpdateOneAsync(TDocument modifiedDocument) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { var filter = Builders.Filter.Eq("Id", modifiedDocument.Id); var updateRes = await HandlePartitioned(modifiedDocument).ReplaceOneAsync(filter, modifiedDocument); @@ -918,7 +1220,8 @@ namespace MongoDbGenericRepository /// The type of the primary key for a Document. /// The document with the modifications you want to persist. public bool UpdateOne(TDocument modifiedDocument) - where TDocument : IDocument where TKey : IEquatable + where TDocument : IDocument + where TKey : IEquatable { var filter = Builders.Filter.Eq("Id", modifiedDocument.Id); var updateRes = HandlePartitioned(modifiedDocument).ReplaceOne(filter, modifiedDocument); @@ -1019,6 +1322,116 @@ namespace MongoDbGenericRepository return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; } + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; + } + + #endregion Delete + + #region Delete TKey + + /// + /// Deletes a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to delete. + /// The number of documents deleted. + public long DeleteOne(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", document.Id); + return HandlePartitioned(document).DeleteOne(filter).DeletedCount; + } + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to delete. + /// The number of documents deleted. + public async Task DeleteOneAsync(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", document.Id); + return (await HandlePartitioned(document).DeleteOneAsync(filter)).DeletedCount; + } + + /// + /// Deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public long DeleteOne(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return HandlePartitioned(partitionKey).DeleteOne(filter).DeletedCount; + } + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public async Task DeleteOneAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return (await HandlePartitioned(partitionKey).DeleteOneAsync(filter)).DeletedCount; + } + + /// + /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public async Task DeleteManyAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return (await HandlePartitioned(partitionKey).DeleteManyAsync(filter)).DeletedCount; + } + + /// + /// Asynchronously deletes a list of documents. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The list of documents to delete. + /// The number of documents deleted. + public async Task DeleteManyAsync(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable + { + if (!documents.Any()) + { + return 0; + } + var idsTodelete = documents.Select(e => e.Id).ToArray(); + return (await HandlePartitioned(documents.FirstOrDefault()).DeleteManyAsync(x => idsTodelete.Contains(x.Id))).DeletedCount; + } + /// /// Deletes a list of documents. /// @@ -1038,18 +1451,6 @@ namespace MongoDbGenericRepository return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; } - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; - } - /// /// Deletes the documents matching the condition of the LINQ expression filter. /// @@ -1065,7 +1466,7 @@ namespace MongoDbGenericRepository return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; } - #endregion Delete + #endregion #region Project @@ -1223,7 +1624,7 @@ namespace MongoDbGenericRepository /// The number of documents you want to skip. Default value is 0. /// The number of documents you want to take. Default value is 50. /// An optional partition key. - public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) where TDocument : IDocument { return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); @@ -1299,7 +1700,7 @@ namespace MongoDbGenericRepository return GetCollection(); } - private IMongoCollection HandlePartitioned(TDocument document) + private IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument where TKey : IEquatable { diff --git a/MongoDbGenericRepository/Models/IDocument.cs b/MongoDbGenericRepository/Models/IDocument.cs index 07d25c4..3142dfb 100644 --- a/MongoDbGenericRepository/Models/IDocument.cs +++ b/MongoDbGenericRepository/Models/IDocument.cs @@ -1,4 +1,5 @@ -using System; +using MongoDB.Bson.Serialization.Attributes; +using System; namespace MongoDbGenericRepository.Models { @@ -9,9 +10,10 @@ namespace MongoDbGenericRepository.Models public interface IDocument where TKey : IEquatable { /// - /// The Guid, which must be decorated with the [BsonId] attribute + /// The Primary Key, which must be decorated with the [BsonId] attribute /// if you want the MongoDb C# driver to consider it to be the document ID. /// + [BsonId] TKey Id { get; set; } /// /// A version number, to indicate the version of the schema. From a13800637f0f576cb1f9053f043dab6f87c6cd6c Mon Sep 17 00:00:00 2001 From: alexandre-spieser Date: Mon, 25 Sep 2017 21:44:10 +0000 Subject: [PATCH 4/7] added more tests for the documents implementing the IDocument interface --- .../CreateTKeyPartitionedTests.cs | 1 - IntegrationTests/IntegrationTests.csproj | 5 + .../ProjectPartitionedTKeyTests.cs | 143 +++++++++++++ IntegrationTests/ProjectTKeyTests.cs | 2 - IntegrationTests/ReadPartitionedTKeyTests.cs | 189 ++++++++++++++++++ IntegrationTests/ReadTKeyTests.cs | 187 +++++++++++++++++ .../UpdatePartitionedTKeyTests.cs | 61 ++++++ IntegrationTests/UpdateTKeyTests.cs | 59 ++++++ 8 files changed, 644 insertions(+), 3 deletions(-) create mode 100644 IntegrationTests/ProjectPartitionedTKeyTests.cs create mode 100644 IntegrationTests/ReadPartitionedTKeyTests.cs create mode 100644 IntegrationTests/ReadTKeyTests.cs create mode 100644 IntegrationTests/UpdatePartitionedTKeyTests.cs create mode 100644 IntegrationTests/UpdateTKeyTests.cs diff --git a/IntegrationTests/CreateTKeyPartitionedTests.cs b/IntegrationTests/CreateTKeyPartitionedTests.cs index 4cc8fa2..4d00dd5 100644 --- a/IntegrationTests/CreateTKeyPartitionedTests.cs +++ b/IntegrationTests/CreateTKeyPartitionedTests.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; namespace IntegrationTests { - public class CreateTestsPartitionedTKeyDocument : IDocument, IPartitionedDocument { [BsonId] diff --git a/IntegrationTests/IntegrationTests.csproj b/IntegrationTests/IntegrationTests.csproj index b2bef91..f608e8b 100644 --- a/IntegrationTests/IntegrationTests.csproj +++ b/IntegrationTests/IntegrationTests.csproj @@ -63,13 +63,18 @@ + + + + + diff --git a/IntegrationTests/ProjectPartitionedTKeyTests.cs b/IntegrationTests/ProjectPartitionedTKeyTests.cs new file mode 100644 index 0000000..9d80dde --- /dev/null +++ b/IntegrationTests/ProjectPartitionedTKeyTests.cs @@ -0,0 +1,143 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + + public class ProjectTestsPartitionedTKeyDocument : IDocument, IPartitionedDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public ProjectTestsPartitionedTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + PartitionKey = "TestPartitionKey"; + Nested = new NestedTKey(); + } + public string PartitionKey { get; set; } + public NestedTKey Nested { get; set; } + public string SomeContent { get; set; } + } + + public class ProjectPartitionedTKeyTests : BaseMongoDbRepositoryTests + { + [Test] + public async Task PartitionedProjectOneAsync() + { + // Arrange + const string someContent = "ProjectOneAsyncContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocument(); + document.SomeContent = someContent; + document.Nested.SomeDate = someDate; + SUT.AddOne(document); + // Act + var result = await SUT.ProjectOneAsync( + x => x.Id == document.Id, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }, + PartitionKey); + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(someContent, result.SomeContent); + Assert.AreEqual(someDate.Minute, result.SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.SomeDate.Second); + } + + [Test] + public void PartitionedProjectOne() + { + // Arrange + const string someContent = "ProjectOneContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocument(); + document.SomeContent = someContent; + document.Nested.SomeDate = someDate; + SUT.AddOne(document); + // Act + var result = SUT.ProjectOne( + x => x.Id == document.Id, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }, + PartitionKey); + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(someContent, result.SomeContent); + Assert.AreEqual(someDate.Minute, result.SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.SomeDate.Second); + } + + [Test] + public async Task PartitionedProjectManyAsync() + { + // Arrange + const string someContent = "ProjectManyAsyncContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocuments(5); + document.ForEach(e => + { + e.SomeContent = someContent; + e.Nested.SomeDate = someDate; + }); + + SUT.AddMany(document); + // Act + var result = await SUT.ProjectManyAsync( + x => x.SomeContent == someContent, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }, + PartitionKey); + // Assert + Assert.AreEqual(5, result.Count); + Assert.AreEqual(someContent, result.First().SomeContent); + Assert.AreEqual(someDate.Minute, result.First().SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.First().SomeDate.Second); + } + + [Test] + public void PartitionedProjectMany() + { + // Arrange + const string someContent = "ProjectManyContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocuments(5); + document.ForEach(e => + { + e.SomeContent = someContent; + e.Nested.SomeDate = someDate; + }); + + SUT.AddMany(document); + // Act + var result = SUT.ProjectMany( + x => x.SomeContent == someContent, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }, + PartitionKey); + // Assert + Assert.AreEqual(5, result.Count); + Assert.AreEqual(someContent, result.First().SomeContent); + Assert.AreEqual(someDate.Minute, result.First().SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.First().SomeDate.Second); + } + } +} diff --git a/IntegrationTests/ProjectTKeyTests.cs b/IntegrationTests/ProjectTKeyTests.cs index 614892a..cec8606 100644 --- a/IntegrationTests/ProjectTKeyTests.cs +++ b/IntegrationTests/ProjectTKeyTests.cs @@ -39,8 +39,6 @@ namespace IntegrationTests public class ProjectTKeyTests : BaseMongoDbRepositoryTests { - - [Test] public async Task ProjectOneAsync() { diff --git a/IntegrationTests/ReadPartitionedTKeyTests.cs b/IntegrationTests/ReadPartitionedTKeyTests.cs new file mode 100644 index 0000000..ceab08e --- /dev/null +++ b/IntegrationTests/ReadPartitionedTKeyTests.cs @@ -0,0 +1,189 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + public class ReadTestsPartitionedTKeyDocument : IDocument, IPartitionedDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public ReadTestsPartitionedTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + PartitionKey = "TestPartitionKey"; + } + public string PartitionKey { get; set; } + public string SomeContent { get; set; } + } + + [TestFixture] + public class ReadPartitionedTKeyTests : BaseMongoDbRepositoryTests + { + [Test] + public async Task PartitionedGetByIdAsync() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.GetByIdAsync(document.Id, PartitionKey); + // Assert + Assert.IsNotNull(result); + } + + [Test] + public void PartitionedGetById() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.GetById(document.Id, PartitionKey); + // Assert + Assert.IsNotNull(result); + } + + [Test] + public async Task PartitionedGetOneAsync() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.GetOneAsync(x => x.Id == document.Id, PartitionKey); + // Assert + Assert.IsNotNull(result); + } + + [Test] + public void PartitionedGetOne() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.GetOne(x => x.Id == document.Id, PartitionKey); + // Assert + Assert.IsNotNull(result); + } + + [Test] + public void PartitionedGetCursor() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var cursor = SUT.GetCursor(x => x.Id == document.Id, PartitionKey); + var count = cursor.Count(); + // Assert + Assert.AreEqual(1, count); + } + + [Test] + public async Task PartitionedAnyAsyncReturnsTrue() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.AnyAsync(x => x.Id == document.Id, PartitionKey); + // Assert + Assert.AreEqual(true, result); + } + + [Test] + public async Task PartitionedAnyAsyncReturnsFalse() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.AnyAsync(x => x.Id == Guid.NewGuid(), PartitionKey); + // Assert + Assert.AreEqual(false, result); + } + + [Test] + public void PartitionedAnyReturnsTrue() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.Any(x => x.Id == document.Id, PartitionKey); + // Assert + Assert.AreEqual(true, result); + } + + [Test] + public void PartitionedAnyReturnsFalse() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.Any(x => x.Id == Guid.NewGuid(), PartitionKey); + // Assert + Assert.AreEqual(false, result); + } + + [Test] + public async Task PartitionedGetAllAsync() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "GetAllAsyncContent"); + SUT.AddMany(documents); + // Act + var result = await SUT.GetAllAsync(x => x.SomeContent == "GetAllAsyncContent", PartitionKey); + // Assert + Assert.AreEqual(5, result.Count); + } + + [Test] + public void PartitionedGetAll() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "GetAllContent"); + SUT.AddMany(documents); + // Act + var result = SUT.GetAll(x => x.SomeContent == "GetAllContent", PartitionKey); + // Assert + Assert.AreEqual(5, result.Count); + } + + [Test] + public async Task PartitionedCountAsync() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "CountAsyncContent"); + SUT.AddMany(documents); + // Act + var result = await SUT.CountAsync(x => x.SomeContent == "CountAsyncContent", PartitionKey); + // Assert + Assert.AreEqual(5, result); + } + + [Test] + public void PartitionedCount() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "CountContent"); + SUT.AddMany(documents); + // Act + var result = SUT.Count(x => x.SomeContent == "CountContent", PartitionKey); + // Assert + Assert.AreEqual(5, result); + } + } +} diff --git a/IntegrationTests/ReadTKeyTests.cs b/IntegrationTests/ReadTKeyTests.cs new file mode 100644 index 0000000..e2e6330 --- /dev/null +++ b/IntegrationTests/ReadTKeyTests.cs @@ -0,0 +1,187 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + public class ReadTestsTKeyDocument : IDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public ReadTestsTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + } + public string SomeContent { get; set; } + } + + [TestFixture] + public class ReadTKeyTests : BaseMongoDbRepositoryTests + { + [Test] + public async Task GetByIdAsync() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.GetByIdAsync(document.Id); + // Assert + Assert.IsNotNull(result); + } + + [Test] + public void GetById() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.GetById(document.Id); + // Assert + Assert.IsNotNull(result); + } + + [Test] + public async Task GetOneAsync() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.GetOneAsync(x => x.Id == document.Id); + // Assert + Assert.IsNotNull(result); + } + + [Test] + public void GetOne() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.GetOne(x => x.Id == document.Id); + // Assert + Assert.IsNotNull(result); + } + + [Test] + public void GetCursor() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var cursor = SUT.GetCursor(x => x.Id == document.Id); + var count = cursor.Count(); + // Assert + Assert.AreEqual(1, count); + } + + [Test] + public async Task AnyAsyncReturnsTrue() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.AnyAsync(x => x.Id == document.Id); + // Assert + Assert.AreEqual(true, result); + } + + [Test] + public async Task AnyAsyncReturnsFalse() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = await SUT.AnyAsync(x => x.Id == Guid.NewGuid()); + // Assert + Assert.AreEqual(false, result); + } + + [Test] + public void AnyReturnsTrue() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.Any(x => x.Id == document.Id); + // Assert + Assert.AreEqual(true, result); + } + + [Test] + public void AnyReturnsFalse() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + // Act + var result = SUT.Any(x => x.Id == Guid.NewGuid()); + // Assert + Assert.AreEqual(false, result); + } + + [Test] + public async Task GetAllAsync() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "GetAllAsyncContent"); + SUT.AddMany(documents); + // Act + var result = await SUT.GetAllAsync(x => x.SomeContent == "GetAllAsyncContent"); + // Assert + Assert.AreEqual(5, result.Count); + } + + [Test] + public void GetAll() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "GetAllContent"); + SUT.AddMany(documents); + // Act + var result = SUT.GetAll(x => x.SomeContent == "GetAllContent"); + // Assert + Assert.AreEqual(5, result.Count); + } + + [Test] + public async Task CountAsync() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "CountAsyncContent"); + SUT.AddMany(documents); + // Act + var result = await SUT.CountAsync(x => x.SomeContent == "CountAsyncContent"); + // Assert + Assert.AreEqual(5, result); + } + + [Test] + public void Count() + { + // Arrange + var documents = CreateTestDocuments(5); + documents.ForEach(e => e.SomeContent = "CountContent"); + SUT.AddMany(documents); + // Act + var result = SUT.Count(x => x.SomeContent == "CountContent"); + // Assert + Assert.AreEqual(5, result); + } + } +} diff --git a/IntegrationTests/UpdatePartitionedTKeyTests.cs b/IntegrationTests/UpdatePartitionedTKeyTests.cs new file mode 100644 index 0000000..8cfb58a --- /dev/null +++ b/IntegrationTests/UpdatePartitionedTKeyTests.cs @@ -0,0 +1,61 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + + public class UpdateTestsPartitionedTKeyDocument : IDocument, IPartitionedDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public UpdateTestsPartitionedTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + PartitionKey = "TestPartitionKey"; + } + public string PartitionKey { get; set; } + public string SomeContent { get; set; } + } + + [TestFixture] + public class UpdatePartitionedTKeyTests : BaseMongoDbRepositoryTests + { + [Test] + public void PartitionedUpdateOne() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + document.SomeContent = "UpdateOneContent"; + // Act + var result = SUT.UpdateOne(document); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual("UpdateOneContent", updatedDocument.SomeContent); + } + + [Test] + public async Task PartitionedUpdateOneAsync() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + document.SomeContent = "UpdateOneAsyncContent"; + // Act + var result = await SUT.UpdateOneAsync(document); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual("UpdateOneAsyncContent", updatedDocument.SomeContent); + } + } +} diff --git a/IntegrationTests/UpdateTKeyTests.cs b/IntegrationTests/UpdateTKeyTests.cs new file mode 100644 index 0000000..bcb77aa --- /dev/null +++ b/IntegrationTests/UpdateTKeyTests.cs @@ -0,0 +1,59 @@ +using IntegrationTests.Infrastructure; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + + public class UpdateTestsTKeyDocument : IDocument + { + [BsonId] + public Guid Id { get; set; } + public int Version { get; set; } + public UpdateTestsTKeyDocument() + { + Id = Guid.NewGuid(); + Version = 2; + } + public string SomeContent { get; set; } + } + + [TestFixture] + public class UpdateTKeyTests : BaseMongoDbRepositoryTests + { + [Test] + public void UpdateOne() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + document.SomeContent = "UpdateOneContent"; + // Act + var result = SUT.UpdateOne(document); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual("UpdateOneContent", updatedDocument.SomeContent); + } + + [Test] + public async Task UpdateOneAsync() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + document.SomeContent = "UpdateOneAsyncContent"; + // Act + var result = await SUT.UpdateOneAsync(document); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual("UpdateOneAsyncContent", updatedDocument.SomeContent); + } + } +} From 76862b2caa3220264025db5560ebdeff83f209fc Mon Sep 17 00:00:00 2001 From: alexandre-spieser Date: Mon, 25 Sep 2017 22:40:00 +0000 Subject: [PATCH 5/7] new nuget package --- .../MongoDbGenericRepository.nuspec | 4 +- .../lib/net45/MongoDbGenericRepository.dll | Bin 38912 -> 57856 bytes .../lib/net45/MongoDbGenericRepository.xml | 782 ++++++++++++++++-- .../MongoDbGenericRepository.dll | Bin 38912 -> 57856 bytes .../MongoDbGenericRepository.xml | 782 ++++++++++++++++-- .../MongoDbGenericRepository.dll | Bin 38912 -> 57856 bytes .../MongoDbGenericRepository.xml | 782 ++++++++++++++++-- 7 files changed, 2117 insertions(+), 233 deletions(-) diff --git a/MongoDbGenericRepository/MongoDbGenericRepository.nuspec b/MongoDbGenericRepository/MongoDbGenericRepository.nuspec index 6aba088..92ed6a0 100644 --- a/MongoDbGenericRepository/MongoDbGenericRepository.nuspec +++ b/MongoDbGenericRepository/MongoDbGenericRepository.nuspec @@ -2,7 +2,7 @@ MongoDbGenericRepository - 1.2.1 + 1.2.2 MongoDb Generic Repository Alexandre Spieser Alexandre Spieser @@ -10,7 +10,7 @@ https://github.com/alexandre-spieser/mongodb-generic-repository false A generic repository implementation using the MongoDB C# Sharp 2.0 driver. - Exposed core MongoDb driver objects and removed the AddedAtUtc property constraint from the IDocument interface. + Added support for Documents that have an Id of type TKey, and implement the IDocument{TKey} interface. Copyright 2017 (c) Alexandre Spieser. All rights reserved. MongoDb Repository Generic NoSql diff --git a/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.dll b/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.dll index c5464da115e06e7f04f407f878b2dc422558973e..7ffaca9176ae34306411eade9b1f9d2a94f3b3c1 100644 GIT binary patch literal 57856 zcmdSC34B!5**|{ny|ZK{`z#4NVUq#Ez9@>ws-U1K!4-v&3=j<&%p?jXqd{=1XkA+u z+M=QrtF>0GT5+q08*Q=DR$H{F6l>L5Thv-D{=VPmoSAzkfTi!}?f?D!qxad*bI$Xe z=bU@)ok^H|`ZdZ?O8Ibo^_5bO0`q5*z^?}#P?z-nX^DC$^z%NCTC;xMr)FtGx@viI zYDshLvZ}h;rlwR&)uLoob8AyoLsQkX6XsSeOVuZb6&Hv58`pEDD>ch`YM5z;m zveY&vq4Q6brHUY%1iQmJ>%NY!$_-tt3c%0s*bi$-u4n;2>o)+^3?n1Uh4sxW5B!A>&n&m^U$xSXa2Ft7OG*lgujUFwxe zTx+r{n*R*+vfI$PZ*X7R$p`@fr%41toMb0rN`-C5mtKc(GN?Y^;KQ>*%_6gn?Gz-s0}O_r=m?+c4U8d_ z+fD*#2oU-n;>03qZ@da!1yVi4I@>q2(sxft*>^9&x^MV`ES^C-^i59pjS^zt6y*Bu zj=oPu-_Vsi2|p}`T7#WbU)Y3)lmt@!*xC-tpaQA>;D-MB&2XSP5J(LGvjYRgtPjzn zO$0&4BDNlKK`H?Y1ZbhgZ4`R9!77Zda`{7V62l;vF$S0d>llUz9nVw)2inN#7_j6R z0|mJlI^{0}6ATMoeNFx_Xz6>X^y6fP3D$iN7doE7Do5Ysbl-)#ZwhjKA8h_OsISYP zjP^gs-%R8Y*_Iea%6Og3D8atWXu*jwK$)>Z$1~%A18wAVELe-oBLxZU9i|Q)g|^(* z$`j)uY(}*%PaF=)Nfo0(*!Cq#7)UHp%J!C?=wJd9JY=xUE60UcWn2@{kn?(!U|(jE zU_CCZAF0tPz=1Y$dR*o7tJ*2Z8yD(auMa%}CzgnarCA+%1QX5pj288j8x!&?W11%Y zI+^K$eVL;LCyoKiV4smOAqI?zoE}qDkBNfBaRAz{Pxa|Ero=2LJu7xL*ow3F+TL-X zhGZPaL&w~lAlR3gBRFv)Q063|mdCRzx(zlaYEZCP>B3O@W zsnGFE18|^?oE{hUdX9^Nym5Kvha)&}?RvD{`NCS0F`X^_I+=3>`!bD!b?q(_I-Y3) z4z!WeW9p{IM8Sb-S9(2|+QllDaipX#C$n6zFLSP7UAxUf$1`c*KpQzd4&3XQ8ww6o zyPoKCcfCaC+Qt4LV`!0noJ^}=U*YIlEQ$g5p! zOe$i=uu}SQG8YKe^Ux-AJkt&wXd|clMh&oU3Ow@=P`lv|`%8H`15G&KWG)1@18qcd zQ{6UDsqTr3z&2yQU!LdyRT$icJyuH-t035RF@eZdgKEJFvl44S1-2cMGrWX0^s8l; zf=XOQ_8@&#Y`dIIt^m*-d;?VFRsGP{fQsPliCzd%58OQhBzi-bx{8Kp@3m0W+4Bqb zGMUG#q2l`greK}JYlMzxt_2RXk<&S>(mABSlS9A4p5FPMbscOy$A`L;@!be5$M-G4y1u?GbUbqtaG;Hx9v==(oMQ?+^%YRR z$M~>smZxuqhI4!iFy@%(e`St`c=3C;v~@BY1#5rz2p!M-065S_PWwAV z`=h|)FQonsf8AIY_d*jkr*Eg??7;!&!uuc^FtqZJ3x5b=Z{U8w^p7a(peBL39+F4^ zWF7?TJ%sOfzld!c#0I&g+vTe1vT6g{hUb?Ky=mE{?1tOJ?E@+gdb_zj@i1C++7sM* z!TSFX>g5r*^3;o?CL&)2$d~7A`ft{`yUM-AmtEuC&0Ic;j#zt-3D$G@Q=#LT$AJTF z7-+cuHq*S?iATSW`rO}2?_H7NI1`#-Mz{nbmS z+PBq-$bXf||2Fi?dVNK(FY_zG{>-a_6Wf6@zZN>4`3-QOjhvp3QOE`Amx9D=09cZ8 zPp1Dq#{cV()Bo=T`!cwHf%j*22-g1J5IUZD6FAUDPWvCN{Zrua?N` z*vA7k#*=-D8w*a~OFZ_NlI)rJK=wL6xc^Fh?v$}PnYRS{GH(m^XWkK<*aejNqtNlp zZs0&0IX(VE_4p}B{0YFDAB;)-zXv(<^Jl@n%=?1;+opH1|aGT9b&N#lfk0_U(>5+Q_5Vd2U}zMd6G4nvXT>vD>G^PEDHJ zJ6b9RAC-ywSqMJ{7`!O9H*hD2bexKG1z<;j`5Ja1QL57P=~t@}H-FN1!F)h7w)y4F z0{~JRg&)+3A5MOztDj5$ZI{Qkm#0750{>?KkT3Z+7_$ z$ggwxyUBaTvzh!JS8qGudjOdJ@kq72d7R5nB0tCF=Xc^e$lv4Ye?tBPm;aQ!CmzXH zUmyCrNAlMnWb+u8pG3aK<GeO7{7hGWN+*4?6MsJWTV4A*$&U)={7(Ss_5VyK{uS~cy7r%uuPn&5 z?*r1?{!sD@T>TRAl7F4=?~#Ae)xS#qEr80@_hmvpqTn-+;42CWL#{!GjdM=n=d@!ABl}6NaE1AR9{`3I+mH znBay}Fy14WPQeKt!5I|Pc?2oYskQ37 z$0a{<$uC^eUz7{J+$H;E$-%eV=`PrpGeO?LG+7{IS4u-9ixqtk9 z*uCxUSK-iuS8dJ1;SNvbPDQF4TJea}9r*SEU7AOWrmIt#>LHSDvf1CB=m}1im``gG zy&yFZ?4YsS^l!IG8xa*6gP?Fl z!Riq~C(#eCs|N<X5VKgR=MHF#WN11H`|{eUx-!)Dguv(fKcN>V@tpBcoYf1V_!%!=w5Xwsvuzmq3fpbNfeHiF^MiKV z2=;yq<|#|h0IkKbh@+ovL#dIlN{s?2ir9(Kz(Xh46$8Q<`m+l%V~E6=}nKD+l`?M0fG`x1vy5zQAT#zQz*K8wdUW7L}K zRM!OjjnjQPiNi%LvEung;k^xFJpw|+IsvFKF#fy9f!%f_n8dLd-%$S>FXtqwi4YeJ zDJe)D1)?|@l7tjwzcEk}s2Cn9s16k9Zw(+(;^sKGN$6~mk45}CTjl=LB=C~1s4wEv z`I;#C;+X7mUuH6K`xL+kHqBW~*hzL9rN~G-u_t3}1UDvQ0j5U$Nc-}DCu6SIWDH5_ z!87|P)om6MCqE_XrPp%#;}G)l=hn(psF1&DK&DovgG|iEV37i$j|Z*EgQykyL#-T5 z)P4*gYvlxnj#{AtnYE%FCdD;yJR}Ss3$ydVXe)E3i&%82({9bI01zI0>&IrcH4=7DVzX?6r*(Jf=QeNCKOBH z`D}>0a1u3OQ}dvgg>y29p?cx41194X;`UPknT&Zbf3wDJqm;=Y-W!LsyKFUVgk+o! zRD``oR*pCl2gt@5(7YMrf^x+LiTRKY=J$TM*W7ehZmqCaCvhgV=mGcC$6+x-;y(*Q zgt-6+@t=$!7lM=^?Y3HwvBb%Y)MvH`pBrg$#7Rh?dPk)vJCs>O)LsV|aqPq?jB~Et zMrpC#PUH!bP2eOOrl0YM8);we_k`(+O_;eo^`fhCak5uWocjJTQsS(K3UMZZOq`2B znmCt`TnZ3#<4iSxPn`|GIL`q#cMf_&oQ*{7%K#bYsf_a!yNy!BNwhb9Ms_;c1Wr;w z{ALQLRALoZ;sdcRhgMIiD=tW!3#ohmSbc3SR`%>9P^#WJ#d~JdbQ(g$+5%)^Z3Ss! zJrCqQb9x$vpIQM8V_gYsVx=d;8z5uF%SM?~N)ap3-uPMBSlI+lGC;XF#f`K_ zoEJi)<8;LZiHjh0b; zzZ8&hV)`UbN)acKXHMC~%xNx8aU<;!=jAZaak}Dy#1)Y4H%|8IB)%bPS)=YAbtQy| zb1e|!+;@+<3X0qwbv2m8d<^|R*rV71_o#0Yw_gLuJ?c!xk3EV~?oq^^#mh#W_b72B z4)XRWSA5_-ioJT)u6K{R7AnMl9gvyl>p@D8cH0dg_o?UHZro{)q9@GrjYRF=0^~fS zbY-3?#XJ*v!ekT7bKV{$ZlrzQ9_5O^W{+a8o;baG)VHBRoHqfPIBy1N;=G0A!PYZ9 zAZY>N3rJv>`~u=3bB3{$i(_R zkS5mkAorQm1MN}tgjjDQYQG(ju`V=oN-1I`^6XJ;(s_>(H_|?Dk8;Idvq!Pl1ME?E zK!rFr0GT-N1Zm>Di{!!1DLo<1?-RA(4ahiaO`Mb>P9o2ovPtJXO58~MygkYlf6X4n zUdwdhD@Cz#NDIi8@GA z_oG`m`uzxmIr=dd+*ThTZvQbLw^h798S>_tb{nPKR*Cn<&(7XI*$CU}gFw0ONAU&| zil_3R=fL2K&0?I4XD9yf!D$xe0J|5zL&MLU`0UA{n04u$N56UxHuy9cXNZSj zf_Z!x2z7gb=Un^~i0t-90QXjK@=}k2OeGN&kI0lK_`HA#C+&S;c#MYoOB6d}qJB!; z{x~2Lg%>}PC`y?qVo##jXn%>4!?Ji3Pq-1eCo5N+-L;Sqb6&ph@!Z*pBiK)V0xE+% z;)8MIXA?}2pC^D&=cTOkCqc8$p90Q24S+f)`d_N^ru;gm=WQbU@6@@cz_G%Hq<)6} zq`;pAVG5i{;Jj@nZhsDt^M;}r^5$uF8>O5#;=S?Z*#c)H%-a?q`JPd(xW$`zL2+Y8 zF{dY2oZXp}^49lcZhupR*0Nd?a!3cgy^5OJ#3q zo~7Q1;qP~;Ggn;dJBi!h0_0L(#<|B*r<6;b*faTTwBMyJ-o#7ZQg_8>^1bUEHLA|T z<++b>82i-0+YolV1MszV;HWpTKE_KO?1C}s;EzC9AL)JWb-SV1-@T4ekQu}dE*Yeh86@^(kc~QLP;PMIO}yX+cR8%|qoym)E}z`}?e-t# z?r-e;0DHxIP$3t81~Pla`ykDE^#hWa2Mj6uI>?Q;)4oVY*egCHYX1w{V6R9qTI`FI zVy__b1j{D--7CbGILX^9TyZwo{p^eE`T((h1QlZaE0BrxV~{4+zme<|>w)$~Izp^} zCu-jV$XId1lUON5tVEtz*<`=5iZ5}J7pp7&npoNOKI`EV2s=In*w1?4(G5rV+`f3Y ztcTAaMPB{^l-(CU2aSF4pFsQWi}qe|OThHMDC?jmaW1lvXa>ma1&e)A zT;<*_A821pv)L8cz2zI9*)LFswq^47Mf%jTPWz%iXSa$E2aI={$W~{4$}epE&-X>< zimUo7;&yysA*;HDbB}$IQm$%Z&*ZaF=T$A|d+{b-^7chnd~o|Bhp|r`SP*vD0AE`N zj@p8HI6~^cfidd92ZZ%ei%Ii?H0Oo@Nd1hC&w(k%t;+kF_&l(w0w}mIgn-Q}MLNY= z2@|y!0&=aK&wSxEF{M~5M0?}7Y3sM)Yyv06K)F|K;zrtInUp}I_di!$kSK)|#hu*~ zzHw7-|6{jKqD<@gKHQDD974n#0WvX1K_*sUfOZ?cQIExvs))IK8)=`H2Uq+xd0?-e zJor7I{Y`=jd6*1@Je(ZlYdGw3Q^4D8Qw2@~bmu$O!TFwN=KExKzUc{Z9!=DK4BH@1 z+;L^TDMg$_p7-i(f;dn2&bPRc_K5S0+vmnl6 z!Qs(t0b>4Ih|l(A{=hHNTy3|Jby9Pnk*_gn-fp8hbt0sLhoyVsD@GkVX`g*)KFdkr zTf*VW)Lg(+4Z%Fxsws1ionk3GfZ+$<;8Ev|88%|r=nMp*f>WGQFVrfv84df*o2%C1v4^kS`W-WG<}~1S;MevAKcz9Xh{pJ_ zaqB*%_w9wDUSR%djpi?NvUj-Q`9!^is}}^ba2)~~qg43FO5K7Bdp!Rhg7ncHcoME} z;)1FCxs+kRL%?9_R2hY8eX$^D&n~Ph3#cyzHWZQmdw5P+RISE<18RKXyF~#tr|9~U zfO@)+aIDaO5IQ697J)rP9u&H^xCg!ue82rie?UE9Zz&F_muyPb2DcQ4)hqV%py&9v z6qn#zEH-C5&w`+6L4B zr>-oldX_w2UZOsLhk%NT{W~FAZWH_WOX%UG!a0zf3i}cjh_bIrfwKfI4YTd_4lS>Q z=ZHEg_6Pia#+Wj~6N~?VkzW_uQe2^42tNrAJtLo&hSfaYFlhKm3Q)>4+t)rU4>XVP^hgcn+vo>GdUH zRV3Pxq76e5P;WvTRyB~6s9`dy&x+Z0Vli9&3bB`{Yap*s4JDtHl&IMf@2)bA=bwN9 z)m!{rF7tI`0dqU8lx^RXdE5YbM9qva4-b_P4lgB~5&lCtE9wP2XRzWdbsO-`*z&j>uP^`h{@Iq+LR76ArHgp&O=tB^(|K!HvOpaM%M5+TadX zzY*>hhukE52ba2-^l&u(xDmO_gqx*y2=|t7C*ds)b)%5$8`Y_5r*J!w#bxR&^|o*q zOMeU0JHm0bFH`mEkHSq6FG>780D4J??rilZ;r=M?&cSCQ)J+oIa`nD&IEtaabJYjJ zVUq-RzWR%BFG%kh^;hNeDN}a}ccJ=NboYb1QFW+2!u>;Zm#9z0@)qggQuUeWPM48g zuKp?9gTh^G*f};CEGQUBEg}YYT{Xi87ceC{OV^t#DJ)(OI`zCu>Cb2)QBEtPhyu6@d!flWY zZc`P)4H7TERbBA6y~@-aY|qOud);I#Z^>A8svef5J`esF@EJfK*21nxA2p`nPk?_2 zei#|4))xE?^yu<0056FUey_|IwbXsVAEMQ@!9vj83$Db9m{ss&E1(_-Uy0T8Ktl3f|-CezHG5dptH5AHc@z=l@S*z5ui7W`J4J66S$9oPs;S!Pu}W zTtCc`mSp{O$NgYmoBd^*mf0COP_}8aDg1h1oZ9Ta6?Y&@tqJ6}%CAPR{nddA{7z|S z`+Y}yFk?6vn@!=}L5{P%tODn&XM+EJoZ9~7V1??)v+q@~Z++ss10@9ooT+ZOH)qFl z@Rm<~tlDHesD%BF2mTfTwSOX@7c0kOQ?(| zZu!~b?;YqJ#a3>(TSEh**t`w*yTGt0wrj&(7dt!}$Z@>`)1$#0cWY>Nv>?a*E>IKY znVdgc{MW@6M#Gu`rvm3h3v=AG;EHH*j%x_4ik9ZMUxmIMmE#p8Tl{5Z8>1#zaIXZO ziQ=I{ezy3pj{PQDnd5E=yc_MB<8COnVtg*(&ldkr1C_C!ngREIv^v&1$Em=Pu|7F& zTJYFdzZ};Pm>V0A<9-!thz-nfWo2!#K{@V~!1b{qIqvG%-LauL?v}t~vEe!HhT>Oa zBXitO1MkH~=eYNydt+mB+!2A&I6mK%pDq3eL*3%|RMT)r1p36~u?#$Q)p5MpH@ag3 zqvL#j;?EZUv51{dOZ?g5e^c?p@ zXhHm#9CvJBaePLOdm^+qHZ#W^i)itQfc$LnzY7lEP|tDa#!tv`x5PT)b3EMM*oisr zw7`||xgPGmIKIFvKU@6IhkhA9&BJ{dpP%DC3lvr?@Ngq57Uj4*W2aOkJ={uutSmoU z{KbJ=E6(w7k5r^`+b$hw`k>R**zo82HYoA=V zYt=}@aot|6rWuaw_8PU$a9p?7sjY_Ny1ha5mu0rw;=28onqxSw+ndzghU2=uMQt}6 z*X=r0%@+fRi0k&ds?l&wu;>r*X={9KR=SgsJU(* zRxO6(y8VgTY&fpeN7TKtsqD6%2vx@(RXYsFHT_dHrdoU9y4|GK=D6wcC)Ezaaos+p zcF1P5+qxxI9eY|8@#P45=eqrwI@NGox6i7(bGp5;&FZzB?!DL+H9|JA-4@sF3+nP5 zcW(S8^_tvp^PM~?e2{#%v6 z%Uq6=>-Kl*@*Fp^;tlmD!*Sj2R9$2X-EG|&TUqgrnqfGu+uiC%Iqs2)KdUbI5+i+b z-Tpt6Yp zT4=cS(Sgx_sQV4Kxnx%5=jw?ZcWUK7)l0c{v%tNbYd1Uk1qX?rEya_gZ-u_p47fAG zb(J~Jzqw>!9@jmOn^pO*Y&-v*B@LB(JzNvG&!oTIA@=Z<`pR(Z;VXsXAbzgxGPA4& zT&ZxEVqaPTZg`F>tyI>@!tJ&=7TY>I$8`sHMUI?#oG~7erDy+2OzFoAjvWvCea6bUo)%v;Njtp}J`M zIL>dWr=ja^l^E{((Dkq?gk$C{)zcay-0sl0;14T%S`!R+Wbi?7)3s$mm*8WSy{y@W z8yI{F+{woB55+6Py{)qh_kOWo^|qA!Y$+ZW>}plzxFdtxLoUa5eR4XsbGg%ErQyCg z-Py4+)z?}gJ#f@zs-Jb9>5rEEtqToD%l_8o!o6h`#Vj?zs-LXz^Op5#=umJihNJEf zYr_;*cZl_n;iwyET{G3y4Ybx9j=F@kZJMh~SUU|z-5_h*bXPaX+G#lI23wCF?dk?w zFBp!xA=ZXtT-^}sA;VEuZLOW*>Z+}EhNEt%#cw!d;~Q$NF&uTntd?V4-7ss7;iwyK z&6gvS&dYGC(Qwp_ux8A1+l{bJH5_##tr2p#((OiClMF}QD67lyZo5&|A;Rf88*Pm+ zI$DmlcAnr`j<)_HoVFZe{ln;JImVJdre)@Dj8$?X+iAJGJjD4h0knDrCk^d54U^|L(POTw*Ih3eaZ z!>k>`>5+}M?mpS|Io|q-aN6hL)|0|%pNCs7<>`JU+-kf7{dVARYnO1^=MmP6SU7qf3;a009>NmlO z)*j*XSdOxuKEv(rDC-x(X`hp<-w3CDPO{$4)BRbv)#@AYIm!A`IPG(?wR67fbF%eU z!!d>_*7h@9-4tt=;i#Kxy>OPRn`*sgIO?WZn-;jbY1UT5Q8(S%ywKH6x3(LOx}&YF zwXW`HYlq>eJH~owk*hn#+H5%LW?1X$T-^-o9^sgm(#o0E^O{qa$F@`+XT2|+&eAOF zvz#T~M_OMAw^|*iUasV)R(M}o z3$CuXy5Z`Mt0%7BxccDghpRuXfw%_a8iK1D*Kk~;aE-<_2G>|z<8U2{>o8p7afKA0 z3(Eoh@K3rAU|5X=EQ1B%WPvjUo+$7%fwck~1fDDKEkFyOVoxm_iDw6%ibl$l*i4J^ zjRId6oB8q?~pm~e6gA@pT7d)v)Iqo$9VJixjM7>d-xRo_0S{u-Vi@UYs6{i z*MR(_77&(?Sy#tCQ7!6_vY^$j9*uUjo-Gz3q>!vkS)Cmi<{|p1n!DZIaJ!H;K1R;s+3ZXnBjhS!_0o z&1SLLDm`w7dOS@d4tEX8*hc4g=_(Denod^f94Vt@6~<{yw;U2ORW*{|StkUzF=4^{h5vwjhs?Vl#SPm^Az zN$-H@eU`;~D3V_4)$O56{54`(WAPK&8W}$zEa%HO=ZpMfyj^|OUu*4z=X&)-=p%o< zw5pfb>m~MjX$y$9jiPN7ZKG%#MGFXRi)dRcuAml?147;|J+86%Y4I9sv;S&9K7p=< z{QH5&tmh*40nUnT4YXVQH2N`Xe)*e$LH4c1?*~4{+u&C*wp(H!`EL;aH^|6u5dVPi zzfR=qWK`>9RO>_w2<-;ZZV>GT(QXheAhh?2_FftDy&?yM{2>|hCX1gOZ^D>g2IN!a zW*PHC80YTbR%yFcJa4u5`SDiqzun^c-3o8LAfdPI7I&NN7T50%X|+RI?T}VGq}2|w z2ZX(4KM`3}uuCj=iRCV_+$EMDi2q%%e+o9V|3LhIApZAAt3A?ckF?q&t@emLAnd;s zn=i%YON*ZsiN1K*_uq+bGB3P~n z71{hOxya^c$wjbv-U5V8Ol)Fe6BC=5*u=yJ5H?rXrSa!N*V?=<+^nt${xUR6@lD^& zcCzGmp>r+13En8$2J4dWyO3-y`8afieRo8K&&8YCVE7sPbbM~r12*3e^at!0?r&dK z)YYm6jW<97ufXqCObx$oPr#>NSJ=~wX8_(EnJsWG;Qf))01L`W!(;4O=)GFt6}A;m zLjFlC8J=Koj;;((v!5uw6gKnA*M_f^+PK16Q*a$@rWb!NOj?0nQ*dYaHfv1m2jN)~ z<1ER;EL+y5-5S`APvCZxz7-yCtqk_EX4(8!5G-*I`dlpvegJuYe4prZ^`{c2@N+dx zXuf}(FW%;hxA`{LUA@iwRHM!NRE=E_Jgg9Mc!MRpwTOL-*tbaUEuw`S+IG>li?&_7 z0irGB(5?~f8quz`c@Mh5=AN_0=Kj3S=ACGbRE1^V71&a^!QN5&Ug5nqBU%GLUlhUv zD&ZlU5#4L|#|R&?8PP-bu;}*CLpCGYB)x2sUN(uhO;UTC!~?YOuvu(2i_K=S*(^3& zF`mELHTF*f4Mp3f_Z`yvX0-iA5n5sY-zxdsA-!*vd~QWPw}-YW_P$Fz?-I|u#Pcrk zTy8%Xc&_LJ@wrEQ?t;%fMX={ek%;z)&o3pSFD0TcB_f|A>&TIHzu5E_oBpubQv@v{trnYVv8fiDYO$#nKhPqUF=8`DY$iCe z;vC*9CkXu58WJcfndPuHY8=+a7_^;If>szqjl-&#FCONLhkA!KHecFS%iXQU9ul~w zWWKb5C0aF#eWTd7NRN#US5}L_kF8?^e=cd49@j{ZjcD7w6s<7YHPYi+@vv4rtd+Rd zN?bMev4NV>wPFt&*xw+QH;Cm8VtIqHd>58Ch$U=bxlTs1&e@D_R&9`08>H2}BH!R} zwXSpcjjMGI-|;>K`S%0&I=lmZj88BBTml=66K&ybleF3dZ&wF4i?_|n9#Qp=3?~?KF zaQIEE9S+~&?ve3-fbs7RLW_~375scD_Fux!%R!${)`Cygf=||hPu7Buch4dpt0LxO zRrq}TCKl{*5AEUOjuG>*HhTEDWAyNG&Gztd&Gr|c{l#a0@!4N|_7|W1#Sd)Yr&=tl z#j;u~tHrWfEXPRi6QuWQwAxS(d)#5CN$(S+_i57mH0gbs^gc^`&Jv%q#OEyWIZJ%b z5JuR$rrdXcP~P z;-OJIG>V5tY1Jt9u!Mb!*tdv%3oKWJT70}OxA=HpuCdny7DifN|3x7zu}idzeY@DV zi+#J;w~KwdSi%ODSKv-}f8+}5gyKg4*A#4u+-xn6{4DZ0?uIW!Le6DHysJK0S{jbv zIq$Vd1kZVdlLgKcc%s151l9^{5O}V@l>+h25VX2N;I#s87I>S$jRGGK_?WL641YRZZMuFcEc&EVo z1U@YA34zZE{G-4R1%4vX?{HLcfjtEd5I9!gWP!5sG*8 zp;rmKP2fh6KP&V*0v((7{RB=GSSN6`z&iv!EASnGjwAL0rwXhSxLV*H0-qK5jzIi{ zYx);BRbZXK)dKGj_^iNp1Ui1P7dTa5oxs%s?-2N`z;^^X0kIc2RbZXK)dKGj_^iNp z1Uf;n7g#57VF4u_0@n+CT3}VEO(nZ71iZKFdcZwhcLE;Ktt#B6R(D$n_;ReO&J`LEX z*G|B5dZ`jv_UZt%dOr<#T<@KLH}+PgZE9!lg@8k`yaJ|5t_(mNpE2XW#NdgxN?9i|a zwd)1$>~cMQb|qXWaJ|5t0;{@-T;O_vI|WvC7rDUo0(T0m>Opyjz?}jo^`vCIz@3`z zC2f0)T;NVkSBboj$OY~cSk+hL0@n-NDX^*^r8s{Qyci0?j!@Lw4J7325+N&)e5S#>M^Ri#oZLWExWr08!TxjeiB&`a-)yba0B z;JbiBf*$~WRQxxQe43-1V)RC+$6(o7VSzd=+ioE>kyvE>qtEU9N5dU9N5c z9l=|ZK7ii^9aZZ=N7e11V|ZWE2kThO0sJB8O7$bqmFmZ!yWmYp zAHbi0?y4RI-BtY*bT_pLbT{=R=?hp2ym9)e%a?1#6~UxKby zdqEFZ1$H06u-y-Dsbio=sS41eRTt2sRX5OMR1eT&R4>qDRTb#5sxRnqsz2y)>JZR} zss!jm)nL$vscO)NsbQeUs}Z2bt5Kliss~0q82?J)bTv!O#lM7Ai+j!e_&qdbm0M?6 ztF7-_4_o*nFm|P#v0t)ZvEQ>3&Tyy2X>+c39(I0@0w3%23g;E33-2tvxA39DCkx*${ClCVXk^hDMT?3uMXQUREPA8p zPeoSonBrrLlf@myw-i5C{BiL=ioYrzSu(z4Maim?-<7;w5-yFD&MIA5dVT4$r7xGh zTKY+8m$GqXHD%3ZcbEORY*X3mW&bEEERU4;E1y`ty8Np0o5~+3-(LQCxfLmh92z+_ za$UsN!OwiWKm093pGWY^$ZLMG`Ldq){Dz+#`8@K^@!3abyDj*Xsk7ZDCHu+-iN6x% zV0G}fzZ|Rv2dltA^*g9~2lMEl${kdWtM$29=gA-D$OO5hrVYcQ@MxTS4>7pf;GqT& z17`ojOh3boe1wsYF!GUxA8Gheh9714(S{#w_%VhbWB9R#A8Yt=h9776Lk)kZ;SU4P z{EavA@kV~Qkso2?M;Q48BR|r}k2La$hM#EoqYQtP;U}4PlZ||`kxw!5sYX84$fp_k zbR(Z`;cqkiZHB)CJjZjV!QVG{ zqrpEg_&$U0H~0aAA2j%3gC8;YF<_4CG1JfEhJW1fPZ<6Q!#`#Crwsp$;h!=5vxa}x z@Xs0kIm171_~#A(qTydO{L6-a+3-I%{Lc;lOYqFYD+a%6^sgHIuMPie!~fRUy>9UD z4SvJmKN$R$!S5LSM}yx5W`5o^{@yeEdxn4C@b4S`L&JY)_>T<#k>Ni!{Ktm>yW#(C z_)iS~iQzvJ-iP0!*X#as!+&n-^>btQg^_<@?EYo=e;K=f8N08H{3~N;S&Ywz->=vE zhGpqGcZ}SDocZ<}-f!&u#x4js^&!y{>-L34UToyWMqX;<?!n&XE1_>w zi|v%U*1in%jcTX8QO$7f1O2%AhLciHI=#>?rFJro$9+$t@Kq|ef?eG z<3@Fk|9sWqe_TD_KNS4qsv_{XItL^@GaD6ja2j5An z!{31GersUC{Z>uEQ`W@=Z7OB;vaT%nrL`5;zY6Yy|BWgU+NkD+Qur$=DfL(=0e^?! zD#2BTs~ddvz%>}xH1PfGdytdo!x3D|?9ake)$`%mxR%*73#+WN3S+pI*-2dOg?HM_ z$Mg6M^ZD>b`}c(p+C@c|fqu|FtmqBHQ@q>0#@f-FP z#h=@EK>oAhO3N-e(|JDphCQp~PW#G|H|)DhR)a5f29%aMOK`0!t+RHNJ|(hu!1paH zbtd6DtE>(_lh&0b4Y*33=gOY4?DCEFS%qDFL&|$u$Ch{Xoml=6d`|T}Q9jkTv;1?r zFWyv7j+9}{SNb^4RgoStu5}R$r*vCR>eX0X)p*7a;J+|V;Dd1j=eq~Kc?jSfj=%K+ zTntRu$RfUVsu6=Rw ziMu~62Y@~V^gz%F^fw6o4F*3%yaez(5ysiK0?!lO@H`Q~^F)|WxqQ0C^924X5cqNM zaVY4+K#vD~IOrolPXK)+=!u|@LYqlwGa398@Kd3i26{T^qd^}7dIsp3ppON89Ozk~ zXX82^*9o}h;5reylc1Xmx(4(-&?kdF1=p##PQ!INt}}4WN1tb+&$B=;0KE`&E$Bs{ z>p<6oPJ&(xdI{*Ipc_D+4f-6=jiC8AX`0YS3jA{L=Ynqrp9bFoz7_m=;Lk^!m7p&G z-G+>3kY)a*g^R#v3G0a6N(RNnB6idK%X=xPFE<&!Wv{ z;OBt106!1>0`QB#F9E*{ycPK8z`p?gCGa-jSAc&7{3`Hv;9mp(2KcwYufg~0xPAxz z_uzK`zXALvWPiZ56W3d~-p2I~u3fnPh-)|O-i6(tfZqfDGw}Ps9{_&{{1@Plfd2~o zG4S7j{|>wd_!Hny;o~33=Rc9pFF^kb^jDyjg|%yy;2UH3_v%3hL5DzxK^Iy9d}9pn z3_+KGE(Ki%x*S&oR}``sWO2|HxGKSS0pAt48*q2v9>6_;djVI$rVr@8pbr5(5Oe}G zekM#DzhJ@G5er7B3Dc5|$(H2o+NPD0(<__mCN9b<#AIZ?iD*Se?I?O-UUr203yhog9;F@d`(YaNhFz+LokO zK1Spcbhg>#ruv-SMEE;Y6zIgAF7`5-y-dzdAS9#4P@=Pz*Tq;fp2>}kxj~K^N8!{| zYg3CWJL~`sM2>)_tejb&vmQC#way#a7*W7{PVJJ0CdBKu8AsL8txa`6GsV-?*5-7o zd2Xt;xh@Ie@vV)GwTl`_&Ya%Vx-8k8{Qc|RGvuZbXsz8LsNsXI=Z2;CE1)Ol0nh`>}1Q*RQ;6JhQ|72GyHe9bv3k} ze12^MTzQ7wk|JlU(o{@K)ghp!7SgjC(!{fBFIWl0V#&+x=n)G?iFDr-9xAHNr9Ku5 zj7|2DV`))7r#W>tlH)ClaU)G1Ug79bMz~KAiXvB+xhfblnho|Xy0K#@@4Pa`iqKQD zqeWsymsdsOM6(~qyd|2iZps_e6$Gnw~dHG7TsZNw?7k6<7q6-NJ$+7 zH6$DBJvBs0lWYjNb-bMQmPV7AR2|*e$|``X{msg#g`;zdyb#BYqh{iGHDPwDzO^wq z5!JJ7QGKmimaa=RH#RKd(A36YZOVQ%H8haHn_N;Ws(b7xPHk;$(u<(VsWQWBeM zU2daN`SY&wXGL`igTAvhrDiszlg%#MIW=HdB(FK$asn4+ZEK_6o0K~ZswTyy zqnl+nKMp;YDl<5j?_6AFNUp(>WXl40z&6z~ucc0<^I2+V){7JfBjrM6k7`D3Q+;D{ zPHl6G>?cV`xeLr|O4lw%>ZYcaE$2dRZQ(*NNvWSTLow?i~Cr zP^l+1VP^flvT57_YtzZ&YnLSttld{LHPzIlw?_TvM)$QiIoZs8bYI2P#s(DYzVcky z$0b+pqvb5C)+TJ6EX`#7DXHdqbv}V9EY3koZBt!RcEFmY&B@yOxyV|}O4N2zxjR30 zP2A{HX>R;X`n;w(-m-+9nf7ugLENw`DcRFAql`%J|oM>nUIxgy;t zU&clr$w^p*s+oWj%sCOlJ4sSDc>>)3b5p3GN!DP{X60L2soR@C)iU0RvpL|9bF`k?q-vE@k(!DsXi2IWE0-@#^4Ng= zY~+FkGG5hCpRPe=a6PFh=~NTWAuagJxryCY*pG6Ig4J{rm7mL)LI*-+- za*q;fP9uWiLj_7~SyG6(*brMAYnv&YR-0am8yP5blhgYKEEIB9w{&__J!zvfgBWJg zNDX`LycNm{-A7p0X~V>ANAH|!ZtJ47{K;lDGd-KV>b}J{4}x6EIu6y)w7j)tX8O3M z)cH*{sVPY#UM^9p={V0e$}(?kM7#ic*(@@*YwVP%bOTP2D~HuX$+6GGo!x|o7T7&; zR%Wf#q|Qk;iG>MPg38i*nX(7>yo|NGY*Dh=Bfx%+oZ|@Vks&QueN8PM(Y&VG=9M0P z3J&;r0^U7&bHng)Hpi_)MyP7cT^OTP%k^25WOlBSi_OtpO>0gqcMmV>nC4V#9-nOS zXeT!>krOqa8m6zPOG?pm$8(wNUdByBp&SumlRmO>u^|sUUqukxHWzLr&&1_&yIE*#BA< zELfzUKv046mM=%M+(aqQbBENCegu&^&<`tWu{_^&+Ru4}N}Uf+#~_#T^p$(mLbXw9 zZolND#HVwi){-4or=cJ-dD9wdmo%l)Ee&<)Y^t(rFS|3(O*Ws`P?t>OF2?;B$>421 ztxitW)h?3d4Q2rz3$yq3w3@tpdE-jnVbgMpP3MB(L=J<)2JRG6T*GoZPu9xZdQb>0 z=*vjmy2;5WOdPXdLCeyH+`w}?$}lDuW73N?>vunElYum*aSuYJH#DX9^HiI=89*u3 z=nllIYLX?8!um7!4w$=73m&OSJIisHyAs_Hk}Fz8omI1Oi^U$E5y0c9F1BK^|by6~oCk%74 zG7PHUP$&{ZWw${cg`9`8GpU&c&H8bP5BKh4zN*PS@Z$(n->|qLS)UWk%pIRSLLG3< zCYuo5Z7Vh$cxRL{7eb-<#IGyS$HaOqz-gwrg{65O9>KWm@#LiUD6FRQlEr{XW%&g%TRIwQIJNfJi+qpLlU*Jv=tuS zxOcK}JdbSIc^0u-TJBD<@_@HVHFFA%qO!u=dnXG;?zA|9NYOMUdEX^BGtJw^3C+`& zEeD7D6Lwb+`0>xg8-C@iz`y-dkN5X=cvrs+@B5qZ-d;IF@n^*Q1E*n^#wQ{C_f%@t z3e^s65^wig@JUDmFf^h5YNW_i$5jb&gu=y#0quD4-+&JT+R?C4oHv193<`H~P<4>k z!4YNbz8xPh;A<85kF8VC;GrMVX5e~g+NIkD$Xel#+)Cg^XcvKNg0v1?5(8`10}FCs z4N6_ap*Mo!R|4B%ouxQB2BAIIqDQvWBf}Ro3|A{-s+DnMEp%ks`h4-;Y^+;gmy~hQ z^B^V&{V#%cG5+H?n8FmIV1LX}3Nq$`*-3)JS4@DHp$+?Frj~+d9+$y3jgMGbF>1EW zW{EU?;!7Z~#8+M5H3`We$k2Zw^N@lBlNnFoqn~={8t~B%GqsEslBrruWm@tJQE%n*C5c@5jW@&bWcdx>Aa+6e$wzO9)~AP9+@5X(=2&uKrWeudRR3`>m(rj z7VCEC3)sgXW+#RJ*nbjpO`HPOUC;y%@4(trMJ07K>b!dka_+;Aa6*&IP0kTjYl_ z8G1Qzx&FIp&GjWqVzEr?Sttum!6JV2SvW;|BrFP8=sk}MYEMK2yz%*Dd7$S9C0E>>m36w^w|mD{K4xRUO8m-xTEqcr4J5yMm+tN$-=DcKozHzuwjg^g0*RJa-Htxs=s z*_!57$XRCfc{fUKlKGb0F1b3~4Nh-t@HFt>ZEa?BQrY-N0kJZ;2LF={OR5Un0nAZIN63sa)7;y! z%ax`vmpmZp{Yw>d1hmw%vslK#jB&?d&X!A_Ni`!Qwa_<9P1T}L#Nkh2$5p`=jFgrw z$dyq3Wyq{@a20aq^o>##yEG$X-`Psi<6;bqnAwmhPz^k~^2nk>%pLn@{k5{@g1nQR zgQz%*cxeYct4Bv{vKvidq>E)#jFZP^M$Pr4^FnSZyz)?t7?2@-6W2N8D9@L6^vi=O zk2tI}9%FfLR#*l4*oZNfrzN)>FJ+995pvalb`rP-L3S3tzcT{g-@#sh9fF6$v#{SR z!2X`VH=$sGm3s!h$21h*GddIBlcL<^&w#(7$U6^QmK-M*z|$ymDAc<7$Pe}2cCxxf4ef}=xR4L0>WmyG&fbuxWl0ZC?!1wWh zrfUSw)|^eVNNa$w<7P3$7g1;^C}Bmlp`e6SK3nVf4;RPF53_oy@=QPzP9Rd`1fuxP z8e~qOJYxq6f+H-;D(j^R!j?AjRjJ64{-9OfvC0=l>tH<6aV>CRm19L!q~moc#Px)% zYZ5_pIvIL#LqSQ* zlu_zDQ97>4I@a?Ica#*0S1rP@*##MscUnZtm@!=j+@`lRNyi|-P#cE+EE6t0QCd=rn-nFvf zO0!~QG&EZ38tHIgsbylRNpaWcT83eySuxV2MBkE)p7TUT!X+VVa|MV<$5kwqc!Ugm z;@4Cot>vrA3pm?XMOyK1721(iT_daFkyiYwYGhT<@>PAH7kUuIs|L_^)zBWsU}X8K zvH1og@msHU`Rwx91#m77N|i6NYP__LqwRn)nZFY`o>lRl=s1Mci_*l9P?7#f$9=hK z&lMwWkHpxqU4$hi?QTk#Va-ZPG?`s>_^Tn<)vRchPyDhjv8#zMSt}iDFb_5@aUvNo?1a=H^z+Txl#3v$|ml(txx zXF*O|kkSKP56T@VISzOOEiva@`!cBd*FLS{8zC|TCDw!62J zo#wTjrnTLVI@xJn+i6RSP|Pu;tx@%^f2<_3>a-HMqs#po?3n@Ol;9_b^;M#GFy8xDC9OygF3%@`i=h({R_Lk*NYBL4 z?@xZ>5(obVCXS3w0YFKCUs)wROYlbq;89=?e~|7$L*xtE_>)QSbS~RtuO!p)j5tHR zDxN@*fdUy(q~k^SF2TA-8$!qNBesrLN`n4^NKtvmcQD#W$8ETq9EP^oM)lF{THvB8 zCvs%=bcpz2>4OGk z>_dz6(J$+fw%GC~>2(+uRBU?FLTIPui8a?v`sYE5b%A-_2$TzQ1{hArhrs&o!TpjF zp5kJ%G0wy~%s+H75Dc8hK%Q{5PnI-&%i<=XS9?_9U$rwTo;Kk%7(hn$9m_1}ytd>c zVyoNp(4wbi4m9YW0Y$5DT%2j;9kftGknkL|(bDH2;1V;6Fwb*Q)k7S!*vvpQnd_nk z@=Cd9&qVO~=Pq=ng*XLEC%Ua{8XLu0E3${UsOdV}8-44*Fc^+8*Xya!cm_%q(>h<9p>FKlPz!nn3ovciYnNkGGHx6$^bJJM zN(VzvgwF1K%4J@Ml`;L%3NUdO$i5l z6R;eHNVtLC01j5ndw!tnOgkFLU7x!HZm2~0J!CC;%F^>=mSonijzu4ZuxzdDqR_$L zZ6>X}<6fciwOYouKiZF0%Q)eWidGIRnykvrpq+>4nr)T_ zW*g(N8M_@HN3jg(?*&og{K0KfUSD9Nl(P@*vfHCM4B`A_W-3Zgx~)F-NS18LcGQk} zt+vuNUWs@%F+B{~VLU_GCPQ)eD>+Y@ElMA9vW$EBiCPt=FYOJZ(r)w-NB7*Nv&nWd zB-Y<+r~$0rRjn3p#iwx$xUtDSgsrtE8&Gyr{D19Tzi%8x6rNqq&M8=nVZur*Pz zWCWbn&IP1Mi7-A)oG4D@i%g_kgY8o=GWN;8aFCGVD&k+DqJlOO1#&@2K|x^&iH0Ht zB@#42RD|z)Z)f+`cNf_6HXyHcyR)-z-oAM=H}_`!eX~-E?)zD6PT9cDso7Nj80u~4 z$rqYoxr_o5?P#ncb7MDXNXKRgs{Tb(#}21j&C)n!_ddc6UxEV!7YJ~6KgEyu!0v9b z_{}G^`JwXT&kzV<$rU^$LllH3P5p&lL_yr`$=8Z;4HFW|^hzRNjId9U@3{MwyYKlx zYTz>F>Np}IdtOd;f^nQ#nmiWzk(94eJatmY(qx}RUigv5cQPpAL=vas+$1RWgA;PO zIp?&Dq|?ROS>9Tvb9F4HB|v>O=YlAStFRrCdUCm zW0Hd<>zSi6$5jRg#MB}KRh)WKAWHV4Gz6RykyU-MECjUJxzLvoi9uZK^dvdr1?R%& z{y}0GIy#phM)}THN2B|T?>gEr8rkq{DXk0IpranG%d;fTMngwSTNaDK+0d6^rQNmR zkWVJrD>>wFUzhzd+HScykvAi(2w%#{2-?4e2KMmm%73z%C4 zcqpyYJMIxz>{AU#EzG_Gq=SJ6Kj7aELC+W`eX`#x6rsH^#)8;A*vIuEPBCZlFgoG| z;zbUXn12JkaN8ezZ~gto?AmG!lm+r}?c)s(a=ysTc;>~@>^rw()cb1@p7`>1xpWaK zf|K#3h>J-E!~o0K_=<(>Al|Vtxl-Q&TV}m(tBqyAg7NR3KF=Hj6unOR02VNoAD%!3um5jORnQN2wo)VpK!9l0(GC4TJ z(_U@i$C2rYH?5hsGpmW|Ok|7-H#7%xNWsg)9MbK&&;u}LiWMo0(=Mt7J&un??+6ta z@6R(=GJ3g*wO9|UMA5G-lcA+Wek;T2IOnP`enxr3I!#gIk z`AKa`jbOqdH@T>i#RPJxpKzM<(L@q+PSumaH6Krr^W2415x1v#3=nd8PO8X=HrKI! zZMI$&S(WNmLMqQo7x~zDy^(o0n_c)dN;9uHFv!9Pc`1`60=jTMENh|tOGJ{rcePW+ z6$IRNcf>w1-i=!fHi^04d4kVR?y4U9)2C*xTB%N7`D*aO!-q3p{`vaW*Drjr#n^W0 zQf;ZeU5i?Q*nb^(T}}(3uC})DVJ(V1YpeCm^2Ls#rN+{N8Tuo!}-LN}&9>X1eoH1v11DvX+gMZ=3C0 zz&5|Ah$LQqi@av30!WWvluh{PXyd(XTRE^Y1U z_k7RyJZE&T+unQawbs7Ax3Ki08G(s)!f+8k;+yzC9Be19aXIzRdwgCtZGlSBx@p(;Ao?I`9h_Z zSRS?ey53jwt-YyEstQ??mHIR!0WH0KFK`vo0VJi$gtoQa6gUL(vy_6IKaW~>HH-3p z7aNu${OY0iToMPAI>aCx`Fm5TFl0ABsMO3O^ZpWFRWMyj1;8&ZDqoXLZq0({d7h7jAPpwRX(v<+7|$6}rYVmyALHO`Yd31x!gqfV-twQau`<)kn(f)juBM$nny zIH@sUUWcLR_3_%;gdb!@+}0)sQVEoRgBHfPje$ONoC=~T@c~`Q9u*(Pq8NQZQDARw zyx_zHpxi{ED|0o#P7gWl3#J}@p&&6CK*!Oera>_R{3{?!(EDiTpCX?j;%Fvr+ua4r3EG zk<&JnYMUrXECA4Yy=oNn%9t}YCF+n_G~yP59dy}YyVwqdQS4ZRJjUiM!QLF^C}RUt zgSoSXuFRbS?DUY+c3>DVHWVb50%*M+_19t(Lp@zq$0BHKz}hG_EEnv}ohLZ40w}jq z=*nCJu+u|M+Yr|_P>{g5|66THT~H{i=RU@d#Nk578Hd$^bw6ArbY<>hV5f(iZo6E! zO+isVIO=uu14dvhvj#aq$CJAR*min|WMUn{$}%i*DcCf|W@ln8sF42<;$Vw3u?~Vm zmt*878bM{z8CIeRlyeAcldhR)W*Mr~vKCN@B-y{NX3(MaEbZ#v0Cw=sDl{`@kpFJ3 znd7y&?&MFP=t-c+YV|K~bMM z>LtVtvnZBHA%}761V-G5{=0F*0$m(8syrmJe{|dmt0mX&@u@T#8VA41Cwq=PKiv%> zgQ7*{_1wT*m-u4;miTrF_U14+!0R|~5xO$B71-$^r{fI&7-tHK;;i+S8NJ<7*OR+K zus7EuSnKT-x-ypoc6!KZy+gEK3I^!KI;AkT#ojBWt|xbuV6CrD=*nC_u+u|M>l>=| zQBb6>MEwT(Fu!A&Par2~b~DeQ%f>mLE4M*3X5!$JuiOseuyZwF<{HZSn8WRGd}262 z?mDo=o7yqwUd5pkS)ni?PS}a16LY~i1RcfWhT62OFmCQ1Gx%?rx_2k8N8KYPnLAjp z-xmhU-!N8oLf3$?g0)g%J(Ade8kwAnpAqcM-5}VP+a);hS)knKgs#l(26lSL>An~V zJ1}M_NZbUFAG_7iFMEqmc3iWgc@tGqKELaY0;l&~+Jj|8?710wXwNNzy}2(4_T|1P zIB_db?lz$-bGHLKJ>;}KCuw^qNZbkV@$7-s#vUxv3M-h{a~Jf`p1TEmbN2}L<@N}U zdUN**p*O!T30;}H57_A;rwtpe4Wl5x`EgC8-&o(Ioi9sOPwsxf-rNI%eYpn(>vP9m zp(}IyfSn$4TKyQUo&tUDm|^#LaIEvBPNq*&HJ3Vt%tM|XXmVIr2wgN`u&uc)xfG_g zlSr_Tofu1WsVDIebWRLlP87>&`vTaGMJuKiObn%=qBHXq6u+X>Iy{JNq%Ma-E?JnD zmXlbIyb1AAEAcQ0Qv%D4GY%(lFVEV*KEZ<%`%z@vm4&l6#kQSTiPEV@kd>42U&!ZY zzM7Yz&|m>RGGAjx=Ielc4r5Yt zB~j`drcIyP2H*J0;5^`rNne)_hX|5pG; z-yg__?E+r`GCjiOPbR;@<(tT-UH%I4x4Qh7$rsu4Ecp-IeA@$lIDly%TY6`DhRe?- zzue{59KrXIf56Ruocwz({|E9#{z$w|@}j+FiQj0D>FF*%mwbcEUrPRuF7NSy9|B0<d{-*$g zQ|qKd-lyP?MS?$55Grv?oCrESrbsY_f-{N)XHl@SNU)ZI)*?X{1-T-@wG`|s5`2+@ z`-%i#rQo?D!H+3;zewN-LJ$MU`!b4xQve1T=O$4wt4Oerf^&-m7gNw&BuIfy;S7Sg zzs)7T=#uxk93&UVRqmt5tN zjV{^ll3QHzDwn+0B|q)_JLa2(U0m72b}pC0V|o(Q;dJO3l=>&s!jU8K zE#SMyoRFR-IYT^yQwKycR2KWY6HkMaDdyEViGPNGSANb>TD`~BYU5Mzu?xDw?)Uzm+`ZmD0Wp)okgZpX^qD1PTkugRC zWU}YBAS$?Kh}otRj}1=HJHbZ#c8}B%QOFeV3m5iJnC$l?{spQhoZ^>_Pz*Psihw8a z9p;4`Be6Z>9Q21rL4CeGS9zg5vAfV73*_6&H|B90^XvAH-Po9k_Q@WcKzMeVi8hDA zNAEFE}C}w+7h@azfNpcU_=>_PxD|=wRTn6Ew=RNG;tmb5%N98en%t^dJJ<2g4vNlzX>AKoH6cgn%HN7YKp-wkc}yB(5|X zBKdqF6z_dvhACXL#q6GcMO#6;=LbL`XTlo4-SaYApMbMso}LI=i!0(DeGOBR`XNfC z{ue+vZYN#=o>*%S8WYS>pB>0yvIlKGKM2NgGOdAzH_o$rC=J`aM29O+#`L!ur{a@0ev?Zff6;7p(dfDMZO~L)6t6gQg4BmaFu)GULCJF5--|h$Go{;5cj?f7{{VH zg#lY(_fU$6^b!|EjFq6qM9g7mM32;uIYkk3#U^415<1>iQ`OKVyp6g1qo@Bjf2rU1 z`Ec?>km97>^PeCq5~tBqujzKL>uDtJNr9Uey+58D2>>? zL`8103Y6sC^wA$tBlTmxA~#*JakDT_uG(4fldTr{sn>)m@$)dU;OC!#jGuVullRji zX#-Taex^L&Q(gf2i3yiq4X6ozI*{1Cen9#;i+)~U_fQHyi4Iquk?&4cfsztPc^95t zD!z&;(E(qB$kkoyiUWxdr0$xqZCAlpw(LoSCA-k4qr}$;gzz;AWPB|JY5KGbiSvKr)<@e7%JJa_HpcxPf;WF;pa&xp#5~kfkZW=$Mln}dJ?0VjeWENBSz+`qpq}+suq98 zAQS$c41~2FU9U2yfR2>dJ$M=!%#8)`m-GZaYM{^cVaeTtSzpHJ7$S-5*SS5Q{&O1ET$7cn8lP4;9@$FxVHw7i|Lu{ zs7ve~O1YR4AFf=OACatt#dH!-;VA~Y%+KXUG>WE}zi0}&;`|g;^M+&K;l~YTK4QNd z31?e%ir%AXjG2%5{>x(+f@_5g%8!9aFX1btQugtcZB z_Q}~G%~~^uB-fgv?c+?a5&|x%5&^wUQW2J#xkSD5SO-fDCfoQoF0^|n#Zp65p&V`5xS#%T?E;&e5E4z zdKOXdVnF(eMM-?66uuG_`N}HC^i_0;k^#QD;=kZ4n?9m{Ycll^_MHt-SZ`0~y>70V za<3c9FXB?7?!Z{VxgKZjb5Iy@SptN4i|MN}OF>8Mo@GG##2pxPS@_2nBMXz6(ksse zkn1!yb=X-Bm^qKKKIZU2y?I=<0xX7=s4ASgkG+H+@1a%6p=GdHKS*xIGJS|TwX87P zaa-bV+5rYWwaTy6MROeM>#^rJ!^An>K-{|ukaK(yyB%|!QqFPWqJC$kW6p8WCRzr} zaaWx0_u@I;j1Jh0R5ZtF$5CV8db&z`RM$TRjG`wD%}R*TNqzM|{HtB?h+`hXCJ^Zk6{i909#;O(AI z2;2tf`kBHKq_2e8;YHVn)C51TChEP0bUs|ZTFD%q&|rpxvi&pyNB7S>mVIhlX(dD zqWXCEt+04p>PdYHd4p5e1EzKm>||Lrf92WOsIVa6hdWy8^652`Yo<+}Hf0tiKGg=e z8~3NGuLOa+EfwXUS7y_#9UC$%Q88DkXHl_w)k^iFCHmdc>a$kWWA{+M1pja)^5(bk z@tXW>Oz{gw-W@6#0ro>{8Xruv^>s+t%Ty22SCF1SLY9J+ss=cTggLKDka!zm7*Z9| z8YI?tkcJ|)A))Kk#YlKjG{ijSUR1I&>Ztbwt`3s^d0=j|TxFun9b58B&{1=P+ro}| zxP)+w&@T$zF7Q(V!y^Ah%zACoy}rjoLAA|(0(8dncqppA-eXc>i8cHvs^D&cMvu3YsC_nvSksBOXx#bn%tyNy>1hjSRX(dt^^ zu%&_+z3`@&6D*9-SFN?xL7sGY*uqUAKaz|GcQmAqQKqD>Ar4^eV9G?AMmCFiKm z3ReQ1m*D-5-NNCL45jMSjlyAr0(Z9hyl}fj%W`##@{B4|4@$lB)E6Z0F)6uH-6q`q zQu0D|hm`!8lw7Uulsr7jht7-DJ;JRPu1Vc1+~ugZOSP)|gu_7>+-7yZ@}Q6A`f2A@ z^`Pi{3H2^fSEzl6{JXwkmZkOsdhr6v*TSRJXy==NFZ%vDJVo_7{{p(Y^blZI8R2K5 zuZAskn{O~`_50og9dZ^zPpvb|a@1Xcg%}riMdkt8rPBfLh|NUqC92s!F!$4CJ58A* zb8DdIO6bpPSRbc_m#Er+tAS;-e&#yrXOVY~Dl^MIcA0-E(sT21%1kP8+j{LdWvJ&e zc;}X6i&{e4X!CEOM@tw7w_B`_!OTJ!I@>r2~)Kw9VpDZ9X z7x#kO<3Edxa2$1A;AFrH%O*K`Y>ZN;#(#nFSsxo_(d%D@2SLaC*wy(v82MfBT9nkk zgApfGhTJ^2(toXkX)V8lkrsa$-%!$=uhjcNSQbt22YuK3KMH#bdEfPVBEABbiEQv?SS!)*^e92s2T9`GKF3@LE0#a@f>tij(w-+1qP5j@?J z-$CC!{y#=|jN$K~?{x3s2%cQXkKDmXRe{^*FNvO1#Jv`&E^x1)@47hslxajx-_k@2*l;Dj7c zl)~?Ai#r2)np0H+ZKCzzUnj_d%8}2$8hZFMe28kV^1$uUJ2sc z7JK?^wZ?Gl=_P81;n>s5)LVvQPcK(xqqSx1=@n|D;n>p+YPaFo)90(V49A|nKs_(r z^tQ#GzEBP4aTWftZ&$023fyavi_`?^LY6!jS);Zajy-*;dcDAvMc1hb(!Fn6?CD0u z_aUj1J>8@(G#q=nMLlUa_VfnzOT)3JFH?(oO9=JY)9q@jaM!5+^88b@Q@v@p+x-6) z&8pclWct;k;SZx*)HwytDc!0rG~8TY4BYkt_hGbK-DPZr+XI(WSk*8ph|1;j!TUU0Qg%ggSHT|1%tQ=G1=*x9fyi z(MjMu6Ik^cjL2!=stepB(JR&2!o6*=^*(iJf%`Dpr}_-X*8A0$3*1<6|0Z0&+7&## z^b_h2!s+%tp-OSxgOAAq-!D58dBcUuQlC&S3wMp06{$nXC#Ny* z8nxdk!x`&)hC4s>Nc0-@6T>ZvJQDq+`oM6zg6EWeO0`Va_4a_zq&1YUg@XR z@Kc%BuMRjn!Z)Z%!rcU`FD>1rW*cq~xX-C`40mm?rSwL%)o@<~cayr;a1#S9rJq;- zX1Iruce8riaGyusE$TPIG1eANT;UmP{q2&IeXXTmP!)!o=<5J?qHxy)0={hN7u6WU z4fb6DuEvynG4x00RyD(LuZ4W-Rw~5rV1znv(+oK3bUD_$y^zOxE>{=7*14mQw<=zS z)8Co8by!`7)88`F9!uV(&Nm!O-lf(F_fzYmn5FJkwRobe)K9Iq{lma5F&y*mQN1(W zynECR!!d7-aJ-w3BmKA`?EfWyH>bh6$9>ejh# zy$93-!s&Vssz*&8OFpP>nCF&!P~B-b=IvFz^WD6?>QlmLE&J4Gh0}9vpSpcO-j{^i zrcPGh^6pbl3a9(%A=Ovs>U>CjS~#uqE9xfUw9c=ny9eYwAlx>5>Gmz}SJYF&X`K(N zI~Te-A65?=jy~*HyBE26`_&%9G4By|>sfBzBWkbVnDggws|(p?*>*Y2hx&JHlKCnyeEPyhoB4ZzyZg?*_ZIsxGj>0SNh7z zY_(plP>boGMO^v+Y5Fp;N<(d7af?SwigSy7DVF~Xhdmpo=dv=qQ77L0eUjoB4hvCd zm!Hv-PY6sr|6hsfUyfvP^!`srRkw8&#+V1!A!TLW0ey5`fM29vD5F&OowodFT1)Wi zHhQGEceGr?O)?U;gxJ>iWJaVMmS2c|wAI-%_KNA0!;!xNwJfFSb?A4jrMUlRL!#ww z?$IUxAUccTTB)UB@rXJetu5ENe~|I^-+@nx*IGj{eYDQshuxTHPtOW@@U^cGcQ;CK zS2ctbRuhmCxQlcn?j7BzN|DNtVn}hMa->S66Oe`?4MQ4%Gz#e?q-vzmNF|CVg&3d@ z&$vjB0t~7tfMsfyzYWgH<;6+m1?Z)(PL$Ao@Y^hm%y({ znXuf`2+MtdSJe%HT6n{IDS)`I@~Zl2Y%$={&}w`E_ME>HSM|I}Sw(Yy9_Wy6BlMcU`7qybrT* z?<+9Inhu>cgwR((04wnpyB ztPyQ%L=PbJu;hPPEmEdM%CtzCHfga1C1=@yDA^`0wn>Xww6)x>P_M;W>|UwcD|LIN z?slo$i@G->mvy&G-R)Ah#C|`v&)y-mc1W!qQfs%=+JRcHA(ypwORe2f>sGY&fxSm+ z?U8#pd&D+Cl-w)*wO8cNsT%)e&nWxx$V|X@V)Hyx?4kZ8pabQr028rB&uZK6zYKJP zbGc`idNckB&{u{&1^Be*3!Zna&-x$poM-)0?1!GGq{XLX3_K;a0iwlcrNw7O{w}W9 z!rs-^A(XFB`~0VPpO;$Ci+9h9ch5^*K-7I%a$lC*mnHXQ$pu92>yrDrjH1^?4hZ>M z(&Bq^FX%noQF+|^o}4>Afc!=8e(SNa9|G3KKk&XK_nP)wOG+KzDEsgxC@-j788N7DL7a@Xi1vB7I`jD3U_8+?Fh(Q9#pdo7N!KUw?AHu}OAM|jxc{k^co zJ5FJXJFD$!==`6i}#dzwOs&i!4g+qcZwWv>dabXqN5<=rLnMyo5Z4w6U1 zmpT3R&1K!7Zw&W2U$f7~-G~X8<1c!r1Aft&Zfyy^plW5-*9q*mHwCqi71(dT7ymirZvrl{9*zCcX|VQ%y#6}$LePJm zwAgQDoiaalp6Dmtjq+Ki+JB2RIzHCFM!Z`i5m;mK-eZfE^q%MMR?kN+@lUZ@egCS~ zSiEzKl2}__RV#cOA+Ny6@KyDr@Kyd-)d-<^rO_tZ+C*EM#T6-QasBDFxc;2OkS7P+axA!h{-EXn_^7f63uUk=C?%i zTcWwde#~o?yeB$85S?#9=cE#p$H@FhJo-R%ek2}!Bp!Vv9(iq$Kb#Qp}c zzXf$~4K_%5ltKA5QgV%yTq7mdn3AucbW_xUo$y>$WJvPVW9-E_LkIhlBS9ISENrB^urm4R4|D2)~5A*TWVo>pd_07RuKKP!hAIA1loEaKCkCXa``{ z*%jVpttcc&~0JMvjul(`|XFYYQ=GS+82(iu>z+EoF#Cczu6$xJ%$I0`C|2n82q6z98^bfj)~ZMg&$0JW=2nffEIuDsZ;Ig#wofTqUqwV3)w0 zz?}kb5qPh_{Q|!U7*O99_?-0!+I<1EjaS;90GufBRDtyZ&jTE#GHQQm4Nk3ur!s<*xf*eGPVG1w%bZWDN?z-I(1Uym9Vn+wjQisb^!4A zu`1lbofTgPn2X;D_-y=5z+icmzehEc_W|Bsekb5B%MSoftEdX}s4FYh0X|o8Ctzje z0l=opxk1{tPN2dwn*F6!0_O@`C$LZ8odORCR8iKd5;#}jI)Qxx@6@oAWex~bWuF5* zS74vO0|He{Qssos^|&EC&=t9>{7-t;+6z4L_gW9MCGh<}p*8vhIaHGyjbZv-wb*;Wz? z_6Oe%o*w!_$i_9M2mg6-wdKQKeR6PxRD!!Xc&`H^xD?kXe48a0+KC5O8~udE^!(T^ zNVWz(4_Hk9rtCIIX8G<09OkpyrYCs#; zJSCvV0NQwSAq2P-HsYEYR@!PMuIX$%S1bqY#Fe0h=i`;2)A;KQ7G}&~&{vTcV(2stj~o#X-k$imirqgFu(76F^tu%sL8i1n3iRS{(&=GU%ad9O$8H z0_b6?2J|pB8T1HsI_MENUsl7GMW9Ei#h_18XM;Wof2FS)ky-}28gJNFBVH>&k5&z! zC*qxrYt-ZFAS@bTt+bL>ul1%i!JcN<+t=7T?eE(^wEx`>cuw|A^t|Koc^7yay;pf} z^X~B;^q%Tl>U+rdr0)aYAm@7LbI$$Fe&;vNe>$`M_5NG^_xK<1zvKUnA6NB(>cI5C z!a!%>mcX5XuLlkUJ`9{tQe9G8(q3|B$$cdcmHedSosvXwQgBu9lHiTOZv|fodP2ca zEHpK=EVMC{3iaVlnQw;4QKC=dGGgZ}1w7asJl2mR_ne|m7W?Ll99@J^Tq zW6guU^kAHM(2xB486I4{^KX24(0?9`Esv@~8ijNcQZ>?Oq%j!hC!0U07*gwSKZkGB zXk2P=%;0i^D-9lO@DPKC8a&M4;Rc^*@CbuP8eC=YD1%QjxZ2>+29GiLWP?vJIAQQu zgU1;>-rxxaPc*p3;7JBgHh7A`Qw^SG@N|PuHF$=>rx`rc;8_NrZtxif*BU$n#@-vNmu943(@_9x+-|+JdzrgSd3}0vXI>Rpl&wgBN@OcKWG4T_QwDD~IAd^^!CMUOHn_*&oWWNa+;8wUV8(Hq z@$+iKUv2nn4S%iSuQU90hQA&><SR;LjO+qrsmy_%?&@F!(Nm?=ko*2Jbic zs|G)2@DsqNs^$38o6UI7t680jdx8sqmm-~uv{ucqHmF;y-Jn~MHmUDgYt;wV7SLC# zx%Mq;k9`~H2i4E)t5vDzCH0`^2g3ix^K-#xdmmIAk*@KUTEF(jtXr%~q#;(b8gH%f zO|m}e+oX2+&a__i-KJji-J(A7tyQPv>0vXTH8$fdwPw7V){M0pZKKXjs?Pseq{pm` ze*y4Pp`Z4@3Z1(_w<7)68XkDZS`yd-`W1}Rp4Xx zhb5bU7ucP_1@=Qo2ZN>7(9nG%8x@*lT^RbY)fjrlzBW{C9|--#{vb5bo{s0Zb^a0$ zb!YHSSOV*60;^R5y`R7?oxqtPft4$Pl`DbWIf1i7{+=!G*Cw!LCa`8Eux2Jy3<-bK z0c&OgYi0s#W&&$w0&8XhYi0s#W&&$w0&8XhYi0s#W&&$w0&8XhYi0s#W&&$wLRBM; zMjC^3GSVqX{BJDMIHd7N6Od|ulrn{q=C3J=qnLeTH2y$ely43K?x}1uavjx?0?*qVzP$K$`=kQ>NuTohH{UZ^G%tef9m?*@Fzsmw1}>(-k=IZ78hIOQ}7k9K_OOvo2?butF5iEsf}d)!j7)?WZG~IjhRglF5KFgPG&N#sScJ{kZNm7HfIgD zG}W;oH9(}TtxK+N?PxWn7PYozlj#8>v4i@TCbJt;E%Uot+gg%o=s&Woo5Rxcwluav zRgtCH6gg8W!;B@ZnJn;<#w)skYL}-|m%-lRNKKouZfYT8KtE2Ki5!U)P;0WSrO0SX zI%KF722dv*%%Dm=vlg{=B|EZIJ!h7xU7Bj?YD><69qmmmjjBDbtIR-_x%Dj~1%joVMr=_nZtQ4jOD=CrXJs@dA>|la)sbmjkI*ehwRdvm zY*C^jV^d=$xva50dHmd? za~7mJI`qWSpRXKU;{0Tqv+(GQ1#PVuc}L3&Zl9CvJ}Q^Jthzcd?Km`(Ef=KHEouva z8CVK^kZtT}PRd+r*qBZ>wyZ?dvfUWlN#!mTs-F8nD#K-iL0{F;%wZvrmL5?j#vD0|eL| z3SFp>lWc&|X71&qgUQ2zR=k_IQ?6*XnTf_=>N#c>;gwnFUE0{Zu@#C|CbI*0#NEw2 zzYz-y-E!BBbW+L6TQ|R^F5P;0GL5wavQ>rNR0|qAvt2Bv*H?_k0e-7`UEesW+PRMB zV?dJ&wC>uZ>XJQEEx;(qCe`BZ&W%Z)4zQk0S-V#3RjncCEx#g|x3 zUEn#fTHBIoS?5r%D61~n)U{y)M~hp0UM7=lZ))pqXw423<8V_PDYr&LV;ViY2>-A_ z5`%b?o1xVw(~Da%kvm-Z!mZh42j`P3%D0M5C}}3!(V6uf>r?6WMlSu0ZO1Kz*}T4W zLsweL9j&A;nQ2b9%KqVI>KI9l70I^7twLqo{JeQsEL*yovqxtvNOg9nTQ_VxW>$MA zPltsLG4qaXqMfGJw$^M>E+>nOJ9RlnpDLU^)$%qt#ZxGTSbI{4l~@qF+8Wao)-`4} zVj}}(HaWd+poBuqnl~=&Xd!JfjS)2_jLc!nM=pgjLyr()27L6 z*H|f2nO2-Zx@%gHN!#nOvm5tN1FI(vR~#!1sZGfaDPf!yr}DI(rfk7IZDH=VHzm_W z0<7nVISxQYGK2-QuOnL|TGi2*?k?iz;~YOgz}=IZ8_dVa4qJyJ3~TY{%H-HY zGT&Fp_2%HG>e8uB_wb_5N~gL8@X2gZ?!5E{oGCl9JZ3K3+MJX@&lS&Q@@p9v4Ta$d z4?Fbvi<1p;;2F`742h5{H??-^rqNA#BbT&xY*q_4Hm2Fd_33m{1}2&OAU&$b3mF+R zj8(RAQ*v1s8&VlGV#s;CusZ6g+_dLPx2hQ>%<4eSnp5ppUw0 zy_}AZSkHNcN^OCrvk*%;t{2Yc7;TiA?U$Sk@r9hIjbv+@H56nzudcOmLq{r;ZEeov zLzSO<`IUKPGJSb#b25WnjO#Ii!EHXH&QCQrHp%n`vliD8`Mo`(=5=ACO20KmFiqukK=V~b8A*DX>A8& zYv!UsU$fI=u`BB6G;P^KlXhn``grm0}Sr>n4Al8EKkDKvKuN`;II`D)~ zc_u2$Ga5L9av9tsR6}@oZ7aS$&Z0~Pa4hbwNlwXVHAQ5qZ)ZXjVbJ37VJ{vJw&KxY zFDkZ)@($4JL1706)eLzv6j8?Jd+~U!74#0n%c5<*rB;bv8hq)$d}Nb z>HICCJ#9*7Q7$QVQS(@a4(&G~cRl{29SmU#Ua&pJCa5=~JL>sYD~ zXhEq~shtFb-iRI%%~~^t^u?&(i}=$ET0*bg_E}EhV?K`Rt-3`s*gM2K-4j>n9EtK3 zT64AT@hhOa3EFjU>2bndxq@wsWpq;bkL@SXi^M6xS&18?w!UBuy+iCy)nl3c#__`O z#1X<-kVXXDC?wHx8X6j@L9AxH@yDJp!Z_+VjfpvmIKDd2wx0fsL5bE_#IT%Z2E#i0q5q|tajpA(#BaVcR) zSRy~QC`+Ot8c)p~;JT!CFKSStwKG87a6u2}eAnt>t|vo&SnB}igT+CPfBQ>1LJwdG zfR6)+a!#Nk`DqM>o(`O@f2~^!ZON2aFWq`6h6THz3D)xY2`AjKr-+^yuoShY!aH^a zmm1xn945$<$>>U0rX6Kcu)0uRrbAw$MjmgX8I6MnP8UAclgVPV=*goZoGi3OtU#nV zS-JSI4`3Ijh8}=iXph`cOf4C%Ts~Fb^;E}Q;{WcB(ps2BbW`< zhu6@<+zhxF>ZMOFbonvOrI5YM(O0}sa*-TZlFKD$hr7V(g$h`;E?FwV?GKlm7%X{?!-mVN@-sG&0!y?)+)!GP*Mj-%(t178 z+aF>O;<~XF37uZT?U%7rp*#g?Xal6&mMPx=$g-eIxZLZ~c?zZdTmhL&EZa*74?o<- z6)4sQ72T^@pDsVzTJij5p6I*tS$jdy$W?N+TkT$WP0dYDAmx z!JLGfpXpc>F%Tus)y;wy*d2Ckjn)6A=h1^DH<)IipAVPW* z*D<4&TcjTKa$VpNha-*0SnkaVvp^pkVPh;Kv8BC~(Mx*BSp(XGC+QyiIf4-1oScle z`mh#Yh2Y`vQmi*?vA**?0hGYZy%Qd;qaZ zl2MZJq(j(uBmTr?Wo)`NLdDu0O?aGm*yEJrJq*Y^PORN_0{+RCWtELkfuN-ed8<@> zw%2dPHhY7p?5~XX?F0^1d8~33@B3kFvnZaKS4_h1RL18aTa-``_IoPhT_Di<=3tqH zKh=){Bb1awV^#PvwF?!%vlQCIJ8@OY4x#7>NiM?d z1f`hxGZ$J5{*VbHLQ7HjJhW_!^^{f}OT8{OLfL2oe?q@9R%eviaGtb}nr%lyp>Zl*Y?SJrfi4Py)T|{TQBT?o2j<7i7%1J9{Us2@Hj9Nz zjItmqkroSs+QOiCOKBh9L@2`ya$KuHV^7@Cw`cK45!twqwl=Y8d!Tzzs<4F-tjP*}J?V{6Q0A3G6^m0)V21JN@h%Pe2K@BYGwD0CUi&Wdfu6bMRS z)}c0I%D|8o_eh9)E!1t?BRv$uA>Oy|XtfAd72HJ*d)9<*BWmPzlNQ}1q~*4vT+)(D zLUOkj<&u_M5@J^`h`e2-IZyh4OVAA*z_I!OD2Ooet1wG2LUdqa^}Z_G8h*lHObwa* z2pE?DojbykDS}Ce72!lmndfy*6p5*UiH6r~TEVD{jA+Cj{;>a=&Op>{p$1pD6aU(E~Je=glMl>XiezMT040~x<%iO7A z6-^b>q%OjB*TUaShYdRzgu>kN8wm%L&MTEtH<(h4c&v{c7i4z1#QSOx7)bHH>$rR= zU7Mx6_$O4NThW71Y*n5BKs4Y}R`f)CSZzb0z~PwU zsOIyt4M>pT_1n<^#z}uWwP1#j>HDUrtfGsk0>1)cR=n@qXaV~m>kxW8KDgHRLd5S2 z#KW<^Td<7v-G=_2j;aVWwgzb12^^~O#Allw4k18MuLBUAY}?!)%SND&YzTB!y~o~G z>Gwme-pk;vt9~XlBIMi@fwv>0SZ_$2 zNtAGlDwip<5F=*5j>3*c!`$IYu-R&j939k*QK1PL_b@HUvBn&3qNwV3;1#(6hRj7) zaZ&OyDXObuZPu}^Lk1eBFYziY#|y3EZ3F`W0&PN&Qx1&;qs9bG57r(gYB^$z6`IU9 zuo&V&vdk`o+XMC$w4`O|QBkdHVjpEYnkmddxN6$f8QjhCKA{i|%Qv|M8AV2t9qtbx zOjs3`gOSo$+hzUJVQ7FDVPGx>sM!TTS7R5Tm49g`K=(?4KwdA_P}+k!WyWMy$KIE> z1CFn8?bugj$2x5Xb4SR*ftruGTbNe&OO8s`9Y$i1ad0T6O0K!v1?m(73RuT!kK~1f@pwhmg9`+12&_Z zODKjs&ozCw>5Tz-7S?kh5Tb@#13W3W%+#^+Q%7$Z>Jb$5m`Xl~u`_z}6~b%&91@ z&v5RLuyD&LSED9dUYf)GRaT*R-_;N!Xxuht_Y%lnd2A4kAVQ>*r=5?^c5IiOu6gLeLvQOaj$BlxE?+YyQ zG{MaT-{!SSd^V1(z_2qUtUe6{Dbi$E_A5FPtB(f22vJ#(y1Ta>jY)Q~WU!RWpWO5N zydAAD^)a$tVHt!21Vc3RGb2V z=*Y>ucFGS#MiB#1&~-djNw-7Bi_$3EWIkzhJDL^}7ZN~by#m5Wv;87O&0k4JOk3YGBYf}71@b4}+*n=)eH+C*dbrfE0!Mh5n zEg1{tY$=C-I%8c-sg|dV2S8V3B zCAZ@J)^xIJWoIj1t%Dl-_wV=9c zC0-@yteRRgxvE9KqNt6Vg1_I6|L`5DrF_ERALO&t3A*OdFK;M(>Zs-&FSq6x&y>gW zmEHWi&3waOJ_%4~S!({rR#SKZS@iG~{=Y*H-d8yKwf?`uE$A8G7GL;R3oJF~W4d+Z z*B*bLDfySd85#Lpg8w$q+>d99yaFLFR*4pV1feiR>OP*9fiJ#`CVn9CcW4^;&b(;i z*AxE`P4WQ>zSUI=Kc08mrU3&{K0^5isgg1M@vSni3Kow?`K&^nW2r?S&q1SVpojbr z1D`ajvp$|KOp$?KOt25-yQRM)Tu@g0dbgQw}|dv@@Tp zaoIpttyo#N(yp$pS~33eMK>+(TGRKLLzi$TS#bKAmgMDYjJJG2Mvv;e(vFpC28q>0v1|8Gh^k zrsFvnVxS(vSD6;R+~gCb{1ZDo2f~w`DtS`Hr*hQV44zL-`7#pUtI#hZbwjG3O406o zeb>S&Jb_|qKGUi~9X_$E!uOxFo=;Tk@ZD$?TCWCNiCjjZ6ZBL(W10-yB5ms@**Ih2 zSBEcR^Y-%Hj}ELR%YfN7fAb`QTP26J+1^U%)Xxv)86lon@o!t?V^oJSd?rROI|szJ z*v=+=&C2JQ`Dm;Fb!05q{$w0-UESwPc}5`LUsJ?0ddH+-3;&)5dt5(()bG-`9(`OJ zY7jHNF2~;&@Wrl$FK+QU3*v#7@?k|M;zdt4Ali6Fcnle%KUqz|Uy|oH#Laj@SM@hU zwZ@cc19tUigkyXeH}+!-{N}Go{65!|?cKPC9cEDKq zxVmZgWPHJG;j86hok#Yv+s6vuPIElWLj?4*WWFfIS#$h4dR(xr|M`8)2;7OwCRDjo R{=W9dtouL3|DTV*{|}*HUCaOg diff --git a/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.xml b/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.xml index 9afe743..618ae3f 100644 --- a/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.xml +++ b/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.xml @@ -23,7 +23,7 @@ Asynchronously adds a document to the collection. - + The type representing a Document. The document you want to add. @@ -31,7 +31,7 @@ Adds a document to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -39,7 +39,7 @@ Asynchronously adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -47,14 +47,50 @@ Adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. + + + Asynchronously adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Asynchronously adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The documents you want to add. + + + + Adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The documents you want to add. + Asynchronously returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -62,7 +98,7 @@ Returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -70,7 +106,7 @@ Asynchronously returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -78,7 +114,7 @@ Returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -86,7 +122,7 @@ Returns a collection cursor. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -94,7 +130,7 @@ Asynchronously returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -102,7 +138,7 @@ Returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -110,7 +146,7 @@ Asynchronously returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -118,7 +154,7 @@ Returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -126,7 +162,7 @@ Asynchronously counts how many documents match the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -134,29 +170,144 @@ Counts how many documents match the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. + + + Asynchronously returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Asynchronously returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a collection cursor. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partitionKey + + + + Counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partitionKey + Asynchronously Updates a document. - + The type representing a Document. The document with the modifications you want to persist. Updates a document. - + The type representing a Document. + The document with the modifications you want to persist. + + + + Asynchronously Updates a document. + + The type representing a Document. + The type of the primary key for a Document. + The document with the modifications you want to persist. + + + + Updates a document. + + The type representing a Document. + The type of the primary key for a Document. The document with the modifications you want to persist. Asynchronously deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -164,7 +315,7 @@ Asynchronously deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -173,7 +324,7 @@ Deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -181,7 +332,7 @@ Deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -190,7 +341,7 @@ Asynchronously deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -199,7 +350,7 @@ Asynchronously deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -207,7 +358,7 @@ Deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -215,7 +366,83 @@ Deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Deletes a document. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -224,8 +451,19 @@ Asynchronously returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -234,8 +472,19 @@ Returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -244,8 +493,19 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -254,12 +514,65 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a paginated list of the documents matching the filter condition. + + The type representing a Document. + + The number of documents you want to skip. Default value is 0. + The number of documents you want to take. Default value is 50. + An optional partition key. + + + + Asynchronously returns a paginated list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + + The number of documents you want to skip. Default value is 0. + The number of documents you want to take. Default value is 50. + An optional partition key. + + + + GetAndUpdateOne with filter + + The type representing a Document. + + + + + + + + GetAndUpdateOne with filter + + The type representing a Document. + The type of the primary key for a Document. + + + + + The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. @@ -299,7 +612,7 @@ Asynchronously adds a document to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -307,7 +620,7 @@ Adds a document to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -315,7 +628,7 @@ Asynchronously adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The documents you want to add. @@ -323,14 +636,50 @@ Adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. + The documents you want to add. + + + + Asynchronously adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Asynchronously adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The documents you want to add. + + + + Adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. The documents you want to add. Asynchronously returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -338,7 +687,7 @@ Returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -346,7 +695,7 @@ Asynchronously returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -354,7 +703,7 @@ Returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -362,7 +711,7 @@ Returns a collection cursor. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -370,7 +719,7 @@ Returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -378,7 +727,7 @@ Returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -386,7 +735,7 @@ Asynchronously returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -394,7 +743,7 @@ Returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -402,7 +751,7 @@ Asynchronously counts how many documents match the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partitionKey @@ -410,7 +759,106 @@ Counts how many documents match the filter condition. - + The type representing a Document. + A LINQ expression filter. + An optional partitionKey + + + + Asynchronously returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Asynchronously returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a collection cursor. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partitionKey + + + + Counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. A LINQ expression filter. An optional partitionKey @@ -418,21 +866,37 @@ Asynchronously Updates a document. - + The type representing a Document. The document with the modifications you want to persist. Updates a document. - + The type representing a Document. + The document with the modifications you want to persist. + + + + Asynchronously Updates a document. + + The type representing a Document. + The type of the primary key for a Document. + The document with the modifications you want to persist. + + + + Updates a document. + + The type representing a Document. + The type of the primary key for a Document. The document with the modifications you want to persist. Asynchronously deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -440,7 +904,7 @@ Deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -448,7 +912,7 @@ Deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -457,7 +921,7 @@ Asynchronously deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -466,7 +930,7 @@ Asynchronously deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -475,7 +939,7 @@ Asynchronously deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -483,7 +947,7 @@ Deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -491,7 +955,83 @@ Deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Deletes a document. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -500,8 +1040,19 @@ Asynchronously returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -510,8 +1061,19 @@ Returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -520,8 +1082,19 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -530,8 +1103,19 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -540,7 +1124,18 @@ Asynchronously returns a paginated list of the documents matching the filter condition. - + The type representing a Document. + + The number of documents you want to skip. Default value is 0. + The number of documents you want to take. Default value is 50. + An optional partition key. + + + + Asynchronously returns a paginated list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. The number of documents you want to skip. Default value is 0. The number of documents you want to take. Default value is 50. @@ -550,7 +1145,18 @@ GetAndUpdateOne with filter - + The type representing a Document. + + + + + + + + GetAndUpdateOne with filter + + The type representing a Document. + The type of the primary key for a Document. @@ -584,6 +1190,14 @@ The value of the partition key. + + + Returns a collection for a document type that has a partition key. + + The type representing a Document. + The type of the primary key for a Document. + The value of the partition key. + Drops a collection, use very carefully. @@ -622,23 +1236,29 @@ The version of the schema of the document - + This class represents a basic document that can be stored in MongoDb. Your document must implement this class in order for the MongoDbRepository to handle them. - + - The Guid, which must be decorated with the [BsonId] attribute + The Primary Key, which must be decorated with the [BsonId] attribute if you want the MongoDb C# driver to consider it to be the document ID. - + A version number, to indicate the version of the schema. + + + This class represents a basic document that can be stored in MongoDb. + Your document must implement this class in order for the MongoDbRepository to handle them. + + This class represents a document that can be inserted in a collection that can be partitioned. @@ -705,33 +1325,41 @@ The private GetCollection method - + The type representing a Document. Returns a collection for a document type that has a partition key. - + The type representing a Document. + The value of the partition key. + + + + Returns a collection for a document type that has a partition key. + + The type representing a Document. + The type of the primary key for a Document. The value of the partition key. Drops a collection, use very carefully. - + The type representing a Document. Drops a collection having a partitionkey, use very carefully. - + The type representing a Document. Very naively pluralizes a TDocument type name. - + The type representing a Document. diff --git a/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.dll b/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.dll index 62f6c989bf06c6720dcf74c6b74699d0716c8e78..70088c776e8ed8255e44d13b650850715b80cb1c 100644 GIT binary patch literal 57856 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 literal 38912 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 diff --git a/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.xml b/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.xml index 9afe743..618ae3f 100644 --- a/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.xml +++ b/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.xml @@ -23,7 +23,7 @@ Asynchronously adds a document to the collection. - + The type representing a Document. The document you want to add. @@ -31,7 +31,7 @@ Adds a document to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -39,7 +39,7 @@ Asynchronously adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -47,14 +47,50 @@ Adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. + + + Asynchronously adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Asynchronously adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The documents you want to add. + + + + Adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The documents you want to add. + Asynchronously returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -62,7 +98,7 @@ Returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -70,7 +106,7 @@ Asynchronously returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -78,7 +114,7 @@ Returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -86,7 +122,7 @@ Returns a collection cursor. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -94,7 +130,7 @@ Asynchronously returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -102,7 +138,7 @@ Returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -110,7 +146,7 @@ Asynchronously returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -118,7 +154,7 @@ Returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -126,7 +162,7 @@ Asynchronously counts how many documents match the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -134,29 +170,144 @@ Counts how many documents match the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. + + + Asynchronously returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Asynchronously returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a collection cursor. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partitionKey + + + + Counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partitionKey + Asynchronously Updates a document. - + The type representing a Document. The document with the modifications you want to persist. Updates a document. - + The type representing a Document. + The document with the modifications you want to persist. + + + + Asynchronously Updates a document. + + The type representing a Document. + The type of the primary key for a Document. + The document with the modifications you want to persist. + + + + Updates a document. + + The type representing a Document. + The type of the primary key for a Document. The document with the modifications you want to persist. Asynchronously deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -164,7 +315,7 @@ Asynchronously deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -173,7 +324,7 @@ Deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -181,7 +332,7 @@ Deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -190,7 +341,7 @@ Asynchronously deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -199,7 +350,7 @@ Asynchronously deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -207,7 +358,7 @@ Deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -215,7 +366,83 @@ Deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Deletes a document. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -224,8 +451,19 @@ Asynchronously returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -234,8 +472,19 @@ Returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -244,8 +493,19 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -254,12 +514,65 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a paginated list of the documents matching the filter condition. + + The type representing a Document. + + The number of documents you want to skip. Default value is 0. + The number of documents you want to take. Default value is 50. + An optional partition key. + + + + Asynchronously returns a paginated list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + + The number of documents you want to skip. Default value is 0. + The number of documents you want to take. Default value is 50. + An optional partition key. + + + + GetAndUpdateOne with filter + + The type representing a Document. + + + + + + + + GetAndUpdateOne with filter + + The type representing a Document. + The type of the primary key for a Document. + + + + + The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. @@ -299,7 +612,7 @@ Asynchronously adds a document to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -307,7 +620,7 @@ Adds a document to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -315,7 +628,7 @@ Asynchronously adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The documents you want to add. @@ -323,14 +636,50 @@ Adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. + The documents you want to add. + + + + Asynchronously adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Asynchronously adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The documents you want to add. + + + + Adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. The documents you want to add. Asynchronously returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -338,7 +687,7 @@ Returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -346,7 +695,7 @@ Asynchronously returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -354,7 +703,7 @@ Returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -362,7 +711,7 @@ Returns a collection cursor. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -370,7 +719,7 @@ Returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -378,7 +727,7 @@ Returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -386,7 +735,7 @@ Asynchronously returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -394,7 +743,7 @@ Returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -402,7 +751,7 @@ Asynchronously counts how many documents match the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partitionKey @@ -410,7 +759,106 @@ Counts how many documents match the filter condition. - + The type representing a Document. + A LINQ expression filter. + An optional partitionKey + + + + Asynchronously returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Asynchronously returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a collection cursor. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partitionKey + + + + Counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. A LINQ expression filter. An optional partitionKey @@ -418,21 +866,37 @@ Asynchronously Updates a document. - + The type representing a Document. The document with the modifications you want to persist. Updates a document. - + The type representing a Document. + The document with the modifications you want to persist. + + + + Asynchronously Updates a document. + + The type representing a Document. + The type of the primary key for a Document. + The document with the modifications you want to persist. + + + + Updates a document. + + The type representing a Document. + The type of the primary key for a Document. The document with the modifications you want to persist. Asynchronously deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -440,7 +904,7 @@ Deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -448,7 +912,7 @@ Deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -457,7 +921,7 @@ Asynchronously deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -466,7 +930,7 @@ Asynchronously deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -475,7 +939,7 @@ Asynchronously deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -483,7 +947,7 @@ Deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -491,7 +955,83 @@ Deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Deletes a document. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -500,8 +1040,19 @@ Asynchronously returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -510,8 +1061,19 @@ Returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -520,8 +1082,19 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -530,8 +1103,19 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -540,7 +1124,18 @@ Asynchronously returns a paginated list of the documents matching the filter condition. - + The type representing a Document. + + The number of documents you want to skip. Default value is 0. + The number of documents you want to take. Default value is 50. + An optional partition key. + + + + Asynchronously returns a paginated list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. The number of documents you want to skip. Default value is 0. The number of documents you want to take. Default value is 50. @@ -550,7 +1145,18 @@ GetAndUpdateOne with filter - + The type representing a Document. + + + + + + + + GetAndUpdateOne with filter + + The type representing a Document. + The type of the primary key for a Document. @@ -584,6 +1190,14 @@ The value of the partition key. + + + Returns a collection for a document type that has a partition key. + + The type representing a Document. + The type of the primary key for a Document. + The value of the partition key. + Drops a collection, use very carefully. @@ -622,23 +1236,29 @@ The version of the schema of the document - + This class represents a basic document that can be stored in MongoDb. Your document must implement this class in order for the MongoDbRepository to handle them. - + - The Guid, which must be decorated with the [BsonId] attribute + The Primary Key, which must be decorated with the [BsonId] attribute if you want the MongoDb C# driver to consider it to be the document ID. - + A version number, to indicate the version of the schema. + + + This class represents a basic document that can be stored in MongoDb. + Your document must implement this class in order for the MongoDbRepository to handle them. + + This class represents a document that can be inserted in a collection that can be partitioned. @@ -705,33 +1325,41 @@ The private GetCollection method - + The type representing a Document. Returns a collection for a document type that has a partition key. - + The type representing a Document. + The value of the partition key. + + + + Returns a collection for a document type that has a partition key. + + The type representing a Document. + The type of the primary key for a Document. The value of the partition key. Drops a collection, use very carefully. - + The type representing a Document. Drops a collection having a partitionkey, use very carefully. - + The type representing a Document. Very naively pluralizes a TDocument type name. - + The type representing a Document. diff --git a/MongoDbGenericRepository/lib/netstandard2.0/MongoDbGenericRepository.dll b/MongoDbGenericRepository/lib/netstandard2.0/MongoDbGenericRepository.dll index 8a408e03c84adeb52e236746814d37bb5fcc5db1..5a2767f6275441cc84dd72945b7e708380cfd380 100644 GIT binary patch literal 57856 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 literal 38912 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 l)f~T#o)_%vzds){0=MJa7n-b Asynchronously adds a document to the collection. - + The type representing a Document. The document you want to add. @@ -31,7 +31,7 @@ Adds a document to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -39,7 +39,7 @@ Asynchronously adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -47,14 +47,50 @@ Adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. + + + Asynchronously adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Asynchronously adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The documents you want to add. + + + + Adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The documents you want to add. + Asynchronously returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -62,7 +98,7 @@ Returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -70,7 +106,7 @@ Asynchronously returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -78,7 +114,7 @@ Returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -86,7 +122,7 @@ Returns a collection cursor. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -94,7 +130,7 @@ Asynchronously returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -102,7 +138,7 @@ Returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -110,7 +146,7 @@ Asynchronously returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -118,7 +154,7 @@ Returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -126,7 +162,7 @@ Asynchronously counts how many documents match the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -134,29 +170,144 @@ Counts how many documents match the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. + + + Asynchronously returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Asynchronously returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a collection cursor. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partitionKey + + + + Counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partitionKey + Asynchronously Updates a document. - + The type representing a Document. The document with the modifications you want to persist. Updates a document. - + The type representing a Document. + The document with the modifications you want to persist. + + + + Asynchronously Updates a document. + + The type representing a Document. + The type of the primary key for a Document. + The document with the modifications you want to persist. + + + + Updates a document. + + The type representing a Document. + The type of the primary key for a Document. The document with the modifications you want to persist. Asynchronously deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -164,7 +315,7 @@ Asynchronously deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -173,7 +324,7 @@ Deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -181,7 +332,7 @@ Deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -190,7 +341,7 @@ Asynchronously deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -199,7 +350,7 @@ Asynchronously deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -207,7 +358,7 @@ Deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -215,7 +366,83 @@ Deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Deletes a document. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -224,8 +451,19 @@ Asynchronously returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -234,8 +472,19 @@ Returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -244,8 +493,19 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -254,12 +514,65 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a paginated list of the documents matching the filter condition. + + The type representing a Document. + + The number of documents you want to skip. Default value is 0. + The number of documents you want to take. Default value is 50. + An optional partition key. + + + + Asynchronously returns a paginated list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + + The number of documents you want to skip. Default value is 0. + The number of documents you want to take. Default value is 50. + An optional partition key. + + + + GetAndUpdateOne with filter + + The type representing a Document. + + + + + + + + GetAndUpdateOne with filter + + The type representing a Document. + The type of the primary key for a Document. + + + + + The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. @@ -299,7 +612,7 @@ Asynchronously adds a document to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -307,7 +620,7 @@ Adds a document to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The document you want to add. @@ -315,7 +628,7 @@ Asynchronously adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. The documents you want to add. @@ -323,14 +636,50 @@ Adds a list of documents to the collection. Populates the Id and AddedAtUtc fields if necessary. - + The type representing a Document. + The documents you want to add. + + + + Asynchronously adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Adds a document to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to add. + + + + Asynchronously adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. + The documents you want to add. + + + + Adds a list of documents to the collection. + Populates the Id and AddedAtUtc fields if necessary. + + The type representing a Document. + The type of the primary key for a Document. The documents you want to add. Asynchronously returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -338,7 +687,7 @@ Returns one document given its id. - + The type representing a Document. The Id of the document you want to get. An optional partition key. @@ -346,7 +695,7 @@ Asynchronously returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -354,7 +703,7 @@ Returns one document given an expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -362,7 +711,7 @@ Returns a collection cursor. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -370,7 +719,7 @@ Returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -378,7 +727,7 @@ Returns true if any of the document of the collection matches the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -386,7 +735,7 @@ Asynchronously returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -394,7 +743,7 @@ Returns a list of the documents matching the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partition key. @@ -402,7 +751,7 @@ Asynchronously counts how many documents match the filter condition. - + The type representing a Document. A LINQ expression filter. An optional partitionKey @@ -410,7 +759,106 @@ Counts how many documents match the filter condition. - + The type representing a Document. + A LINQ expression filter. + An optional partitionKey + + + + Asynchronously returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Returns one document given its id. + + The type representing a Document. + The type of the primary key for a Document. + The Id of the document you want to get. + An optional partition key. + + + + Asynchronously returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns one document given an expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a collection cursor. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns true if any of the document of the collection matches the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Returns a list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + + + + Asynchronously counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partitionKey + + + + Counts how many documents match the filter condition. + + The type representing a Document. + The type of the primary key for a Document. A LINQ expression filter. An optional partitionKey @@ -418,21 +866,37 @@ Asynchronously Updates a document. - + The type representing a Document. The document with the modifications you want to persist. Updates a document. - + The type representing a Document. + The document with the modifications you want to persist. + + + + Asynchronously Updates a document. + + The type representing a Document. + The type of the primary key for a Document. + The document with the modifications you want to persist. + + + + Updates a document. + + The type representing a Document. + The type of the primary key for a Document. The document with the modifications you want to persist. Asynchronously deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -440,7 +904,7 @@ Deletes a document. - + The type representing a Document. The document you want to delete. The number of documents deleted. @@ -448,7 +912,7 @@ Deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -457,7 +921,7 @@ Asynchronously deletes a document matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -466,7 +930,7 @@ Asynchronously deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -475,7 +939,7 @@ Asynchronously deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -483,7 +947,7 @@ Deletes a list of documents. - + The type representing a Document. The list of documents to delete. The number of documents deleted. @@ -491,7 +955,83 @@ Deletes the documents matching the condition of the LINQ expression filter. - + The type representing a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Deletes a document. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to delete. + The number of documents deleted. + + + + Deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a document matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. + A LINQ expression filter. + An optional partition key. + The number of documents deleted. + + + + Asynchronously deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes a list of documents. + + The type representing a Document. + The type of the primary key for a Document. + The list of documents to delete. + The number of documents deleted. + + + + Deletes the documents matching the condition of the LINQ expression filter. + + The type representing a Document. + The type of the primary key for a Document. A LINQ expression filter. An optional partition key. The number of documents deleted. @@ -500,8 +1040,19 @@ Asynchronously returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -510,8 +1061,19 @@ Returns a projected document matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Returns a projected document matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -520,8 +1082,19 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -530,8 +1103,19 @@ Asynchronously returns a list of projected documents matching the filter condition. - - + The type representing a Document. + The type representing the model you want to project to. + + The projection expression. + An optional partition key. + + + + Asynchronously returns a list of projected documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. + The type representing the model you want to project to. The projection expression. An optional partition key. @@ -540,7 +1124,18 @@ Asynchronously returns a paginated list of the documents matching the filter condition. - + The type representing a Document. + + The number of documents you want to skip. Default value is 0. + The number of documents you want to take. Default value is 50. + An optional partition key. + + + + Asynchronously returns a paginated list of the documents matching the filter condition. + + The type representing a Document. + The type of the primary key for a Document. The number of documents you want to skip. Default value is 0. The number of documents you want to take. Default value is 50. @@ -550,7 +1145,18 @@ GetAndUpdateOne with filter - + The type representing a Document. + + + + + + + + GetAndUpdateOne with filter + + The type representing a Document. + The type of the primary key for a Document. @@ -584,6 +1190,14 @@ The value of the partition key. + + + Returns a collection for a document type that has a partition key. + + The type representing a Document. + The type of the primary key for a Document. + The value of the partition key. + Drops a collection, use very carefully. @@ -622,23 +1236,29 @@ The version of the schema of the document - + This class represents a basic document that can be stored in MongoDb. Your document must implement this class in order for the MongoDbRepository to handle them. - + - The Guid, which must be decorated with the [BsonId] attribute + The Primary Key, which must be decorated with the [BsonId] attribute if you want the MongoDb C# driver to consider it to be the document ID. - + A version number, to indicate the version of the schema. + + + This class represents a basic document that can be stored in MongoDb. + Your document must implement this class in order for the MongoDbRepository to handle them. + + This class represents a document that can be inserted in a collection that can be partitioned. @@ -705,33 +1325,41 @@ The private GetCollection method - + The type representing a Document. Returns a collection for a document type that has a partition key. - + The type representing a Document. + The value of the partition key. + + + + Returns a collection for a document type that has a partition key. + + The type representing a Document. + The type of the primary key for a Document. The value of the partition key. Drops a collection, use very carefully. - + The type representing a Document. Drops a collection having a partitionkey, use very carefully. - + The type representing a Document. Very naively pluralizes a TDocument type name. - + The type representing a Document. From c07b1a5d7bfc09b4242c2a930a10a95d264471f5 Mon Sep 17 00:00:00 2001 From: alexandre-spieser Date: Sun, 1 Oct 2017 22:30:30 +0000 Subject: [PATCH 6/7] Added grouping functionality and tests. --- IntegrationTests/GroupTests/GroupingTests.cs | 108 +++++ IntegrationTests/Infrastructure/Child.cs | 14 + IntegrationTests/IntegrationTests.csproj | 2 + .../UpdatePartitionedTKeyTests.cs | 56 +++ IntegrationTests/UpdatePartitionedTests.cs | 154 +++++++ IntegrationTests/UpdateTKeyTests.cs | 136 ++++++ IntegrationTests/UpdateTests.cs | 154 +++++++ .../BaseMongoDbRepository.cs | 436 +++++++++++++++++- .../MongoDbGenericRepository.nuspec | 2 +- .../lib/net45/MongoDbGenericRepository.xml | 272 ++++++++++- 10 files changed, 1320 insertions(+), 14 deletions(-) create mode 100644 IntegrationTests/GroupTests/GroupingTests.cs create mode 100644 IntegrationTests/Infrastructure/Child.cs diff --git a/IntegrationTests/GroupTests/GroupingTests.cs b/IntegrationTests/GroupTests/GroupingTests.cs new file mode 100644 index 0000000..751af45 --- /dev/null +++ b/IntegrationTests/GroupTests/GroupingTests.cs @@ -0,0 +1,108 @@ +using IntegrationTests.Infrastructure; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace IntegrationTests.GroupTests +{ + public class GroupingTestsDocument : Document + { + public GroupingTestsDocument() + { + Version = 2; + Children = new List(); + } + public string SomeContent { get; set; } + public int GroupingKey { get; set; } + public List Children { get; set; } + } + + public class ProjectedGroup + { + public int Key { get; set; } + public List Content { get; set; } + } + + public class GroupingTests : BaseMongoDbRepositoryTests + { + [Test] + public void GroupByTProjection() + { + // Arrange + var documents = CreateTestDocuments(5); + for(var i = 0; i < documents.Count - 2; i++) + { + documents[i].GroupingKey = 1; + documents[i].SomeContent = $"content-{i}"; + } + for (var i = 3; i < documents.Count; i++) + { + documents[i].GroupingKey = 2; + documents[i].SomeContent = $"content-{i}"; + } + SUT.AddMany(documents); + + // Act + + var result = SUT.GroupBy( + e => e.GroupingKey, g => new ProjectedGroup { + Key = g.Key, + Content = g.Select(doc => doc.SomeContent).ToList() + }); + + // Assert + var key1Group = result.First(e => e.Key == 1); + Assert.NotNull(key1Group); + Assert.AreEqual(3, key1Group.Content.Count); + var key2Group = result.First(e => e.Key == 2); + Assert.NotNull(key2Group); + Assert.AreEqual(2, key2Group.Content.Count); + } + + [Test] + public void FilteredGroupByTProjection() + { + // Arrange + var documents = CreateTestDocuments(5); + for (var i = 0; i < documents.Count - 2; i++) + { + documents[i].GroupingKey = 4; + documents[i].SomeContent = $"content-{i}"; + } + for (var i = 3; i < documents.Count; i++) + { + documents[i].GroupingKey = 5; + documents[i].SomeContent = $"content-{i}"; + } + var guid1 = Guid.NewGuid().ToString("n"); + var guid2 = Guid.NewGuid().ToString("n"); + for (var i = 0; i < documents.Count - 1; i++) + { + documents[i].Children = new List { + new Child(guid1, guid2) + }; + } + + SUT.AddMany(documents); + + // Act + var result = SUT.GroupBy( + e => e.Children.Any(c => c.Type == guid1), + e => e.GroupingKey, g => new ProjectedGroup + { + Key = g.Key, + Content = g.Select(doc => doc.SomeContent).ToList() + }); + + // Assert + var key1Group = result.First(e => e.Key == 4); + Assert.NotNull(key1Group); + Assert.AreEqual(3, key1Group.Content.Count); + var key2Group = result.First(e => e.Key == 5); + Assert.NotNull(key2Group); + Assert.AreEqual(1, key2Group.Content.Count); + } + } +} diff --git a/IntegrationTests/Infrastructure/Child.cs b/IntegrationTests/Infrastructure/Child.cs new file mode 100644 index 0000000..cf9d1ec --- /dev/null +++ b/IntegrationTests/Infrastructure/Child.cs @@ -0,0 +1,14 @@ +namespace IntegrationTests.Infrastructure +{ + public class Child + { + public Child(string type, string value) + { + Type = type; + Value = value; + } + + public string Type { get; set; } + public string Value { get; set; } + } +} diff --git a/IntegrationTests/IntegrationTests.csproj b/IntegrationTests/IntegrationTests.csproj index f608e8b..d3bb63c 100644 --- a/IntegrationTests/IntegrationTests.csproj +++ b/IntegrationTests/IntegrationTests.csproj @@ -58,8 +58,10 @@ + + diff --git a/IntegrationTests/UpdatePartitionedTKeyTests.cs b/IntegrationTests/UpdatePartitionedTKeyTests.cs index 8cfb58a..41c66cf 100644 --- a/IntegrationTests/UpdatePartitionedTKeyTests.cs +++ b/IntegrationTests/UpdatePartitionedTKeyTests.cs @@ -1,8 +1,10 @@ using IntegrationTests.Infrastructure; using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver; using MongoDbGenericRepository.Models; using NUnit.Framework; using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace IntegrationTests @@ -18,9 +20,11 @@ namespace IntegrationTests Id = Guid.NewGuid(); Version = 2; PartitionKey = "TestPartitionKey"; + Children = new List(); } public string PartitionKey { get; set; } public string SomeContent { get; set; } + public List Children { get; set; } } [TestFixture] @@ -57,5 +61,57 @@ namespace IntegrationTests Assert.IsNotNull(updatedDocument); Assert.AreEqual("UpdateOneAsyncContent", updatedDocument.SomeContent); } + + [Test] + public async Task UpdateOneAsyncWithUpdateDefinition() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var updateDef = Builders.Update.AddToSetEach(p => p.Children, childrenToAdd); + + // Act + var result = await SUT.UpdateOneAsync(document, updateDef); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, document.PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithUpdateDefinition() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var updateDef = Builders.Update.AddToSetEach(p => p.Children, childrenToAdd); + + // Act + var result = SUT.UpdateOne(document, updateDef); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, document.PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } } } diff --git a/IntegrationTests/UpdatePartitionedTests.cs b/IntegrationTests/UpdatePartitionedTests.cs index 3c0fa8a..fd7e3f9 100644 --- a/IntegrationTests/UpdatePartitionedTests.cs +++ b/IntegrationTests/UpdatePartitionedTests.cs @@ -1,6 +1,8 @@ using IntegrationTests.Infrastructure; +using MongoDB.Driver; using MongoDbGenericRepository.Models; using NUnit.Framework; +using System.Collections.Generic; using System.Threading.Tasks; namespace IntegrationTests @@ -10,8 +12,10 @@ namespace IntegrationTests public UpdateTestsPartitionedDocument() : base("TestPartitionKey") { Version = 2; + Children = new List(); } public string SomeContent { get; set; } + public List Children { get; set; } } public class UpdatePartitionedTests : BaseMongoDbRepositoryTests @@ -47,5 +51,155 @@ namespace IntegrationTests Assert.IsNotNull(updatedDocument); Assert.AreEqual("UpdateOneAsyncContent", updatedDocument.SomeContent); } + + [Test] + public async Task UpdateOneAsyncWithUpdateDefinition() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var updateDef = Builders.Update.AddToSetEach(p => p.Children, childrenToAdd); + + // Act + var result = await SUT.UpdateOneAsync(document, updateDef); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, document.PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithUpdateDefinition() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var updateDef = Builders.Update.AddToSetEach(p => p.Children, childrenToAdd); + + // Act + var result = SUT.UpdateOne(document, updateDef); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, document.PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + // Act + var result = SUT.UpdateOne(document, x => x.Children, childrenToAdd); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, document.PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public async Task UpdateOneAsyncWithFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + // Act + var result = await SUT.UpdateOneAsync(document, x => x.Children, childrenToAdd); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, document.PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithFilterAndFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + // Act + var filter = Builders.Filter.Eq("Id", document.Id); + var result = SUT.UpdateOne(filter, x => x.Children, childrenToAdd, document.PartitionKey); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, document.PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public async Task UpdateOneAsyncWithFilterAndFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + // Act + var filter = Builders.Filter.Eq("Id", document.Id); + var result = await SUT.UpdateOneAsync(filter, x => x.Children, childrenToAdd, document.PartitionKey); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id, document.PartitionKey); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } } } diff --git a/IntegrationTests/UpdateTKeyTests.cs b/IntegrationTests/UpdateTKeyTests.cs index bcb77aa..f981196 100644 --- a/IntegrationTests/UpdateTKeyTests.cs +++ b/IntegrationTests/UpdateTKeyTests.cs @@ -1,8 +1,10 @@ using IntegrationTests.Infrastructure; using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver; using MongoDbGenericRepository.Models; using NUnit.Framework; using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace IntegrationTests @@ -17,8 +19,10 @@ namespace IntegrationTests { Id = Guid.NewGuid(); Version = 2; + Children = new List(); } public string SomeContent { get; set; } + public List Children { get; set; } } [TestFixture] @@ -55,5 +59,137 @@ namespace IntegrationTests Assert.IsNotNull(updatedDocument); Assert.AreEqual("UpdateOneAsyncContent", updatedDocument.SomeContent); } + + [Test] + public async Task UpdateOneAsyncWithUpdateDefinition() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var updateDef = Builders.Update.AddToSetEach(p => p.Children, childrenToAdd); + // Act + var result = await SUT.UpdateOneAsync(document, updateDef); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithUpdateDefinition() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var updateDef = Builders.Update.AddToSetEach(p => p.Children, childrenToAdd); + + // Act + var result = SUT.UpdateOne(document, updateDef); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var filter = Builders.Filter.Eq("Id", document.Id); + + // Act + var result = SUT.UpdateOne>(document, x => x.Children, childrenToAdd); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public async Task UpdateOneAsyncWithFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var filter = Builders.Filter.Eq("Id", document.Id); + + // Act + var result = await SUT.UpdateOneAsync>(document, x => x.Children, childrenToAdd); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithFilterAndFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var filter = Builders.Filter.Eq("Id", document.Id); + + // Act + var result = SUT.UpdateOne>(filter, x => x.Children, childrenToAdd); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } } } diff --git a/IntegrationTests/UpdateTests.cs b/IntegrationTests/UpdateTests.cs index 328c3f3..ee5bb17 100644 --- a/IntegrationTests/UpdateTests.cs +++ b/IntegrationTests/UpdateTests.cs @@ -1,6 +1,8 @@ using IntegrationTests.Infrastructure; +using MongoDB.Driver; using MongoDbGenericRepository.Models; using NUnit.Framework; +using System.Collections.Generic; using System.Threading.Tasks; namespace IntegrationTests @@ -10,8 +12,10 @@ namespace IntegrationTests public UpdateTestsDocument() { Version = 2; + Children = new List(); } public string SomeContent { get; set; } + public List Children { get; set; } } public class UpdateTests : BaseMongoDbRepositoryTests @@ -47,5 +51,155 @@ namespace IntegrationTests Assert.IsNotNull(updatedDocument); Assert.AreEqual("UpdateOneAsyncContent", updatedDocument.SomeContent); } + + [Test] + public async Task UpdateOneAsyncWithUpdateDefinition() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var updateDef = Builders.Update.AddToSetEach(p => p.Children, childrenToAdd); + + // Act + var result = await SUT.UpdateOneAsync(document, updateDef); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithUpdateDefinition() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + var updateDef = Builders.Update.AddToSetEach(p => p.Children, childrenToAdd); + + // Act + var result = SUT.UpdateOne(document, updateDef); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + // Act + var result = SUT.UpdateOne(document, x => x.Children, childrenToAdd); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public async Task UpdateOneAsyncWithFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + // Act + var result = await SUT.UpdateOneAsync(document, x => x.Children, childrenToAdd); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public void UpdateOneWithFilterAndFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + // Act + var filter = Builders.Filter.Eq("Id", document.Id); + var result = SUT.UpdateOne(filter, x => x.Children, childrenToAdd); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } + + [Test] + public async Task UpdateOneAsyncWithFilterAndFieldSelector() + { + // Arrange + var document = CreateTestDocument(); + SUT.AddOne(document); + var childrenToAdd = new List + { + new Child("testType1", "testValue1"), + new Child("testType2", "testValue2") + }; + + // Act + var filter = Builders.Filter.Eq("Id", document.Id); + var result = await SUT.UpdateOneAsync(filter, x => x.Children, childrenToAdd); + // Assert + Assert.IsTrue(result); + var updatedDocument = SUT.GetById(document.Id); + Assert.IsNotNull(updatedDocument); + Assert.AreEqual(childrenToAdd[0].Type, updatedDocument.Children[0].Type); + Assert.AreEqual(childrenToAdd[0].Value, updatedDocument.Children[0].Value); + Assert.AreEqual(childrenToAdd[1].Type, updatedDocument.Children[1].Type); + Assert.AreEqual(childrenToAdd[1].Value, updatedDocument.Children[1].Value); + } } } diff --git a/MongoDbGenericRepository/BaseMongoDbRepository.cs b/MongoDbGenericRepository/BaseMongoDbRepository.cs index 630a535..2b318ab 100644 --- a/MongoDbGenericRepository/BaseMongoDbRepository.cs +++ b/MongoDbGenericRepository/BaseMongoDbRepository.cs @@ -206,7 +206,7 @@ namespace MongoDbGenericRepository /// The type of the primary key for a Document. /// The Id of the document you want to get. /// An optional partition key. - Task GetByIdAsync(Guid id, string partitionKey = null) + Task GetByIdAsync(TKey id, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; @@ -217,7 +217,7 @@ namespace MongoDbGenericRepository /// The type of the primary key for a Document. /// The Id of the document you want to get. /// An optional partition key. - TDocument GetById(Guid id, string partitionKey = null) + TDocument GetById(TKey id, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; @@ -324,7 +324,6 @@ namespace MongoDbGenericRepository #endregion - #region Update /// @@ -341,6 +340,68 @@ namespace MongoDbGenericRepository /// The document with the modifications you want to persist. bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument; + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + bool UpdateOne(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + Task UpdateOneAsync(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + bool UpdateOne(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + Task UpdateOneAsync(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument; + + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The document you want to modify. + /// The update definition for the document. + Task UpdateOneAsync(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument; + + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The document you want to modify. + /// The update definition for the document. + bool UpdateOne(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument; + #endregion #region Update TKey @@ -365,6 +426,80 @@ namespace MongoDbGenericRepository where TDocument : IDocument where TKey : IEquatable; + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to modify. + /// The update definition for the document. + Task UpdateOneAsync(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to modify. + /// The update definition for the document. + bool UpdateOne(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + Task UpdateOneAsync(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + bool UpdateOne(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + Task UpdateOneAsync(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + bool UpdateOne(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + #endregion #region Delete @@ -535,7 +670,6 @@ namespace MongoDbGenericRepository #endregion - #region Project /// @@ -692,6 +826,43 @@ namespace MongoDbGenericRepository where TDocument : IDocument where TKey : IEquatable; + #region Grouping + + /// + /// Groups a collection of documents given a grouping criteria, + /// and returns a list of projected documents. + /// + /// The type representing a Document. + /// The type of the grouping criteria. + /// The type of the projected group. + /// The grouping criteria. + /// The projected group result. + /// The partition key of your document, if any. + List GroupBy( + Expression> groupingCriteria, + Expression, TProjection>> groupProjection, + string partitionKey = null) + where TDocument : IDocument + where TProjection : class, new(); + + /// Groups filtered a collection of documents given a grouping criteria, + /// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. + /// + /// The type representing a Document. + /// The type of the grouping criteria. + /// The type of the projected group. + /// The grouping criteria. + /// The projected group result. + /// The partition key of your document, if any. + /// + List GroupBy(Expression> filter, + Expression> selector, + Expression, TProjection>> projection, + string partitionKey = null) + where TDocument : IDocument + where TProjection : class, new(); + + #endregion } /// @@ -1017,7 +1188,7 @@ namespace MongoDbGenericRepository /// The type of the primary key for a Document. /// The Id of the document you want to get. /// An optional partition key. - public async Task GetByIdAsync(Guid id, string partitionKey = null) + public async Task GetByIdAsync(TKey id, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { @@ -1032,7 +1203,7 @@ namespace MongoDbGenericRepository /// The type of the primary key for a Document. /// The Id of the document you want to get. /// An optional partition key. - public TDocument GetById(Guid id, string partitionKey = null) + public TDocument GetById(TKey id, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { @@ -1194,6 +1365,98 @@ namespace MongoDbGenericRepository return updateRes.ModifiedCount == 1; } + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The document you want to modify. + /// The update definition for the document. + public async Task UpdateOneAsync(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", documentToModify.Id); + var updateRes = await HandlePartitioned(documentToModify).UpdateOneAsync(filter, update); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + public bool UpdateOne(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", documentToModify.Id); + var updateRes = HandlePartitioned(documentToModify).UpdateOne(filter, Builders.Update.Set(field, value)); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + public async Task UpdateOneAsync(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", documentToModify.Id); + var updateRes = await HandlePartitioned(documentToModify).UpdateOneAsync(filter, Builders.Update.Set(field, value)); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + public bool UpdateOne(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument + { + var collection = string.IsNullOrEmpty(partitionKey) ? GetCollection() : GetCollection(partitionKey); + var updateRes = collection.UpdateOne(filter, Builders.Update.Set(field, value)); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + public async Task UpdateOneAsync(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument + { + var collection = string.IsNullOrEmpty(partitionKey) ? GetCollection() : GetCollection(partitionKey); + var updateRes = await collection.UpdateOneAsync(filter, Builders.Update.Set(field, value)); + return updateRes.ModifiedCount == 1; + } + + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The document you want to modify. + /// The update definition for the document. + public bool UpdateOne(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", documentToModify.Id); + var updateRes = HandlePartitioned(documentToModify).UpdateOne(filter, update, new UpdateOptions { IsUpsert = true }); + return updateRes.ModifiedCount == 1; + } + #endregion Update #region Update TKey @@ -1228,6 +1491,110 @@ namespace MongoDbGenericRepository return updateRes.ModifiedCount == 1; } + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to modify. + /// The update definition for the document. + public async Task UpdateOneAsync(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument + where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", documentToModify.Id); + var updateRes = await HandlePartitioned(documentToModify).UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = true }); + return updateRes.ModifiedCount == 1; + } + + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to modify. + /// The update definition for the document. + public bool UpdateOne(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument + where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", documentToModify.Id); + var updateRes = HandlePartitioned(documentToModify).UpdateOne(filter, update, new UpdateOptions { IsUpsert = true }); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + public async Task UpdateOneAsync(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument + where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", documentToModify.Id); + var updateRes = await HandlePartitioned(documentToModify).UpdateOneAsync(filter, Builders.Update.Set(field, value)); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + public bool UpdateOne(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument + where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", documentToModify.Id); + var updateRes = HandlePartitioned(documentToModify).UpdateOne(filter, Builders.Update.Set(field, value)); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + public async Task UpdateOneAsync(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + var collection = string.IsNullOrEmpty(partitionKey) ? GetCollection() : GetCollection(partitionKey); + var updateRes = await collection.UpdateOneAsync(filter, Builders.Update.Set(field, value)); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + public bool UpdateOne(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + var collection = string.IsNullOrEmpty(partitionKey) ? GetCollection() : GetCollection(partitionKey); + var updateRes = collection.UpdateOne(filter, Builders.Update.Set(field, value)); + return updateRes.ModifiedCount == 1; + } + #endregion Update #region Delete @@ -1601,7 +1968,7 @@ namespace MongoDbGenericRepository /// The type representing a Document. /// The type of the primary key for a Document. /// The type representing the model you want to project to. - /// + /// The document filter. /// The projection expression. /// An optional partition key. public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) @@ -1614,6 +1981,60 @@ namespace MongoDbGenericRepository .ToList(); } + #endregion + + #region Grouping + + /// + /// Groups a collection of documents given a grouping criteria, + /// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. + /// + /// The type representing a Document. + /// The type of the grouping criteria. + /// The type of the projected group. + /// The grouping criteria. + /// The projected group result. + /// The partition key of your document, if any. + public List GroupBy( + Expression> groupingCriteria, + Expression, TProjection>> groupProjection, + string partitionKey = null) + where TDocument : IDocument + where TProjection : class, new() + { + var collection = string.IsNullOrEmpty(partitionKey) ? GetCollection() : GetCollection(partitionKey); + return collection.Aggregate() + .Group(groupingCriteria, groupProjection) + .ToList(); + + } + + /// Groups filtered a collection of documents given a grouping criteria, + /// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. + /// + /// The type representing a Document. + /// The type of the grouping criteria. + /// The type of the projected group. + /// The grouping criteria. + /// The projected group result. + /// The partition key of your document, if any. + /// + public List GroupBy(Expression> filter, + Expression> selector, + Expression, TProjection>> projection, + string partitionKey = null) + where TDocument : IDocument + where TProjection : class, new() + { + var collection = string.IsNullOrEmpty(partitionKey) ? GetCollection() : GetCollection(partitionKey); + + return collection.Aggregate() + .Match(Builders.Filter.Where(filter)) + .Group(selector, projection) + .ToList(); + } + + #endregion /// @@ -1732,7 +2153,6 @@ namespace MongoDbGenericRepository } } - private IMongoCollection GetCollection(string partitionKey) where TDocument : IDocument where TKey : IEquatable diff --git a/MongoDbGenericRepository/MongoDbGenericRepository.nuspec b/MongoDbGenericRepository/MongoDbGenericRepository.nuspec index 92ed6a0..2847dd6 100644 --- a/MongoDbGenericRepository/MongoDbGenericRepository.nuspec +++ b/MongoDbGenericRepository/MongoDbGenericRepository.nuspec @@ -2,7 +2,7 @@ MongoDbGenericRepository - 1.2.2 + 1.3 MongoDb Generic Repository Alexandre Spieser Alexandre Spieser diff --git a/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.xml b/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.xml index 618ae3f..9a99a51 100644 --- a/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.xml +++ b/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.xml @@ -174,7 +174,7 @@ A LINQ expression filter. An optional partition key. - + Asynchronously returns one document given its id. @@ -183,7 +183,7 @@ The Id of the document you want to get. An optional partition key. - + Returns one document given its id. @@ -287,6 +287,62 @@ The type representing a Document. The document with the modifications you want to persist. + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + Asynchronously Updates a document. @@ -303,6 +359,68 @@ The type of the primary key for a Document. The document with the modifications you want to persist. + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + Asynchronously deletes a document. @@ -573,6 +691,19 @@ + + + Groups a collection of documents given a grouping criteria, + and returns a list of projected documents. + + The type representing a Document. + The type of the grouping criteria. + The type of the projected group. + The grouping criteria. + The projected group result. + The partition key of your document, if any. + + The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. @@ -763,7 +894,7 @@ A LINQ expression filter. An optional partitionKey - + Asynchronously returns one document given its id. @@ -772,7 +903,7 @@ The Id of the document you want to get. An optional partition key. - + Returns one document given its id. @@ -876,6 +1007,62 @@ The type representing a Document. The document with the modifications you want to persist. + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + Asynchronously Updates a document. @@ -892,6 +1079,68 @@ The type of the primary key for a Document. The document with the modifications you want to persist. + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + Asynchronously deletes a document. @@ -1116,10 +1365,23 @@ The type representing a Document. The type of the primary key for a Document. The type representing the model you want to project to. - + The document filter. The projection expression. An optional partition key. + + + Groups a collection of documents given a grouping criteria, + and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. + + The type representing a Document. + The type of the grouping criteria. + The type of the projected group. + The grouping criteria. + The projected group result. + The partition key of your document, if any. + + Asynchronously returns a paginated list of the documents matching the filter condition. From 9c0cd0fe4746709fa993ff263a081e7f0fc4d31e Mon Sep 17 00:00:00 2001 From: alexandre-spieser Date: Sun, 1 Oct 2017 22:35:51 +0000 Subject: [PATCH 7/7] dll added. --- .../BaseMongoDbRepository.cs | 1 - .../lib/net45/MongoDbGenericRepository.dll | Bin 57856 -> 66048 bytes .../MongoDbGenericRepository.dll | Bin 57856 -> 66048 bytes .../MongoDbGenericRepository.xml | 272 +++++++++++++++++- .../MongoDbGenericRepository.dll | Bin 57856 -> 66048 bytes .../MongoDbGenericRepository.xml | 272 +++++++++++++++++- 6 files changed, 534 insertions(+), 11 deletions(-) diff --git a/MongoDbGenericRepository/BaseMongoDbRepository.cs b/MongoDbGenericRepository/BaseMongoDbRepository.cs index 2b318ab..3059736 100644 --- a/MongoDbGenericRepository/BaseMongoDbRepository.cs +++ b/MongoDbGenericRepository/BaseMongoDbRepository.cs @@ -2027,7 +2027,6 @@ namespace MongoDbGenericRepository where TProjection : class, new() { var collection = string.IsNullOrEmpty(partitionKey) ? GetCollection() : GetCollection(partitionKey); - return collection.Aggregate() .Match(Builders.Filter.Where(filter)) .Group(selector, projection) diff --git a/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.dll b/MongoDbGenericRepository/lib/net45/MongoDbGenericRepository.dll index 7ffaca9176ae34306411eade9b1f9d2a94f3b3c1..295d25def2747f1683be9ca788427fc82c7cde45 100644 GIT binary patch literal 66048 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 literal 57856 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 literal 57856 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 diff --git a/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.xml b/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.xml index 618ae3f..9a99a51 100644 --- a/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.xml +++ b/MongoDbGenericRepository/lib/netstandard1.5/MongoDbGenericRepository.xml @@ -174,7 +174,7 @@ A LINQ expression filter. An optional partition key. - + Asynchronously returns one document given its id. @@ -183,7 +183,7 @@ The Id of the document you want to get. An optional partition key. - + Returns one document given its id. @@ -287,6 +287,62 @@ The type representing a Document. The document with the modifications you want to persist. + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + Asynchronously Updates a document. @@ -303,6 +359,68 @@ The type of the primary key for a Document. The document with the modifications you want to persist. + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + Asynchronously deletes a document. @@ -573,6 +691,19 @@ + + + Groups a collection of documents given a grouping criteria, + and returns a list of projected documents. + + The type representing a Document. + The type of the grouping criteria. + The type of the projected group. + The grouping criteria. + The projected group result. + The partition key of your document, if any. + + The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. @@ -763,7 +894,7 @@ A LINQ expression filter. An optional partitionKey - + Asynchronously returns one document given its id. @@ -772,7 +903,7 @@ The Id of the document you want to get. An optional partition key. - + Returns one document given its id. @@ -876,6 +1007,62 @@ The type representing a Document. The document with the modifications you want to persist. + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + Asynchronously Updates a document. @@ -892,6 +1079,68 @@ The type of the primary key for a Document. The document with the modifications you want to persist. + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + Asynchronously deletes a document. @@ -1116,10 +1365,23 @@ The type representing a Document. The type of the primary key for a Document. The type representing the model you want to project to. - + The document filter. The projection expression. An optional partition key. + + + Groups a collection of documents given a grouping criteria, + and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. + + The type representing a Document. + The type of the grouping criteria. + The type of the projected group. + The grouping criteria. + The projected group result. + The partition key of your document, if any. + + Asynchronously returns a paginated list of the documents matching the filter condition. diff --git a/MongoDbGenericRepository/lib/netstandard2.0/MongoDbGenericRepository.dll b/MongoDbGenericRepository/lib/netstandard2.0/MongoDbGenericRepository.dll index 5a2767f6275441cc84dd72945b7e708380cfd380..c914cf7b55cbcbfe2e5687066d5f0e293454761b 100644 GIT binary patch literal 66048 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�Uv>L@NICuxlO7!q0XHN z-0;V}OS;+b2%!4rH~Dt`6AnYX10*W=2u`7!SS1TDwEK@4p@ATJ(;hSA{nLQA9>+- zCUM5~Eq~pwmPj;T9)_VaZb{|O_i<9JhZA3MC=K+1GdQ5}Dd>xm-U4moJ^Wc<)PB>f z#Hq6(-haOdZ^4KEg;s|x)?Qo_`Uj;({ZbE{#|b-+yF~75EG{jC9J)DSO=t9j$iGSE zc>~5cfN{Aw_fW=G=1ZG8n=$D%bN5lZ;8-91 X%u@sXp6NlC<^}WY_YwO4g$Diu(a=2+ literal 57856 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 diff --git a/MongoDbGenericRepository/lib/netstandard2.0/MongoDbGenericRepository.xml b/MongoDbGenericRepository/lib/netstandard2.0/MongoDbGenericRepository.xml index 618ae3f..9a99a51 100644 --- a/MongoDbGenericRepository/lib/netstandard2.0/MongoDbGenericRepository.xml +++ b/MongoDbGenericRepository/lib/netstandard2.0/MongoDbGenericRepository.xml @@ -174,7 +174,7 @@ A LINQ expression filter. An optional partition key. - + Asynchronously returns one document given its id. @@ -183,7 +183,7 @@ The Id of the document you want to get. An optional partition key. - + Returns one document given its id. @@ -287,6 +287,62 @@ The type representing a Document. The document with the modifications you want to persist. + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + Asynchronously Updates a document. @@ -303,6 +359,68 @@ The type of the primary key for a Document. The document with the modifications you want to persist. + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + Asynchronously deletes a document. @@ -573,6 +691,19 @@ + + + Groups a collection of documents given a grouping criteria, + and returns a list of projected documents. + + The type representing a Document. + The type of the grouping criteria. + The type of the projected group. + The grouping criteria. + The projected group result. + The partition key of your document, if any. + + The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. @@ -763,7 +894,7 @@ A LINQ expression filter. An optional partitionKey - + Asynchronously returns one document given its id. @@ -772,7 +903,7 @@ The Id of the document you want to get. An optional partition key. - + Returns one document given its id. @@ -876,6 +1007,62 @@ The type representing a Document. The document with the modifications you want to persist. + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The document you want to modify. + The update definition for the document. + Asynchronously Updates a document. @@ -892,6 +1079,68 @@ The type of the primary key for a Document. The document with the modifications you want to persist. + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Takes a document you want to modify and applies the update you have defined in MongoDb. + + The type representing a Document. + The type of the primary key for a Document. + The document you want to modify. + The update definition for the document. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document you want to modify. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + + + + Updates the property field with the given value update a property field in entities. + + The type representing a Document. + The type of the primary key for a Document. + The type of the field. + The document filter. + The field selector. + The new value of the property field. + Asynchronously deletes a document. @@ -1116,10 +1365,23 @@ The type representing a Document. The type of the primary key for a Document. The type representing the model you want to project to. - + The document filter. The projection expression. An optional partition key. + + + Groups a collection of documents given a grouping criteria, + and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. + + The type representing a Document. + The type of the grouping criteria. + The type of the projected group. + The grouping criteria. + The projected group result. + The partition key of your document, if any. + + Asynchronously returns a paginated list of the documents matching the filter condition.