using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading; using System.Threading.Tasks; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Driver; using MongoDB.Driver.Linq; using PoweredSoft.DynamicLinq.Helpers; using PoweredSoft.ObjectStorage.Core; namespace PoweredSoft.ObjectStorage.MongoDB { public class MongoObjectStorageCollection : IObjectStorageCollection { public MongoObjectStorageCollection(IMongoCollection collection) { if (collection == null) throw new ArgumentNullException("collection"); Collection = collection; } public string CollectionName => Collection.CollectionNamespace.CollectionName; public IMongoCollection Collection { get; } public async Task AddAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken)) { await Collection.InsertOneAsync(entity, cancellationToken: cancellationToken); return entity; } public Task AnyAsync(Expression> predicate, CancellationToken cancellationToken = default(CancellationToken)) { return MongoQueryable.AnyAsync(Collection.AsQueryable(), predicate, cancellationToken); } public IQueryable AsQueryable() { return Collection.AsQueryable(); } protected virtual Expression> CreateEntityExpression(TEntity entity) { var objectKey = GetBsonIdProperty(); var constant = objectKey.GetValue(entity); var expression = QueryableHelpers.CreateConditionExpression(objectKey.Name, DynamicLinq.ConditionOperators.Equal, constant, DynamicLinq.QueryConvertStrategy.LeaveAsIs); return expression; } protected virtual PropertyInfo GetBsonIdProperty() { var objectKey = typeof(TEntity) .GetProperties(BindingFlags.Public | BindingFlags.Instance) .FirstOrDefault(t => t.GetCustomAttribute() != null); if (objectKey == null) throw new Exception("Must have a BsonIdAttribute on one of the properties."); return objectKey; } public async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken)) { var expression = CreateEntityExpression(entity); await Collection.DeleteOneAsync(expression); } public async Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken)) { var expression = CreateEntityExpression(entity); await Collection.ReplaceOneAsync(expression, entity); return entity; } public Task> GetAllAsync(CancellationToken cancellationToken = default(CancellationToken)) { return Collection.AsQueryable().ToListAsync(cancellationToken); } public Task> GetAllAsync(Expression> predicate, CancellationToken cancellationToken = default(CancellationToken)) { return Collection.Find(predicate).ToListAsync(cancellationToken); } public Task GetAsync(object key, CancellationToken cancellationToken = default(CancellationToken)) { var keyProp = GetBsonIdProperty(); var expression = QueryableHelpers.CreateConditionExpression(keyProp.Name, DynamicLinq.ConditionOperators.Equal, key, DynamicLinq.QueryConvertStrategy.LeaveAsIs); var result = Collection.Find(expression).FirstOrDefaultAsync(); return result; } public List GetObjectKeys() { return new List() { GetBsonIdProperty() }; } public Task FirstOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default) { return this.Collection.AsQueryable().FirstOrDefaultAsync(predicate, cancellationToken); } public Task FirstAsync(Expression> predicate, CancellationToken cancellationToken = default) { return this.Collection.AsQueryable().FirstAsync(predicate, cancellationToken); } public async Task UpdateManyAsync(Expression> predicate, Expression> fieldExpression, TField value, CancellationToken cancellationToken = default) { var updateDefinition = Builders.Update.Set(fieldExpression, value); await Collection.UpdateManyAsync(predicate, updateDefinition, new UpdateOptions() { IsUpsert = false }, cancellationToken); } public async Task UpdateManyAsync(Expression> predicate, Expression> fieldExpression, TField value, Expression> fieldExpression2, TField2 value2, CancellationToken cancellationToken = default) { var updateDefinition = Builders.Update .Set(fieldExpression, value) .Set(fieldExpression2, value2) ; await Collection.UpdateManyAsync(predicate, updateDefinition, new UpdateOptions() { IsUpsert = false }, cancellationToken); } public async Task UpdateManyAsync(Expression> predicate, Expression> fieldExpression, TField value, Expression> fieldExpression2, TField2 value2, Expression> fieldExpression3, TField3 value3, CancellationToken cancellationToken = default) { var updateDefinition = Builders.Update .Set(fieldExpression, value) .Set(fieldExpression2, value2) .Set(fieldExpression3, value3) ; await Collection.UpdateManyAsync(predicate, updateDefinition, new UpdateOptions() { IsUpsert = false }, cancellationToken); } public async Task UpdateOneAsync(Expression> predicate, Expression> fieldExpression, TField value, CancellationToken cancellationToken = default) { var updateDefinition = Builders.Update.Set(fieldExpression, value); await Collection.UpdateOneAsync(predicate, updateDefinition, new UpdateOptions() { IsUpsert = false }, cancellationToken); } public async Task UpdateOneAsync(Expression> predicate, Expression> fieldExpression, TField value, Expression> fieldExpression2, TField2 value2, CancellationToken cancellationToken = default) { var updateDefinition = Builders.Update .Set(fieldExpression, value) .Set(fieldExpression2, value2); await Collection.UpdateOneAsync(predicate, updateDefinition, new UpdateOptions() { IsUpsert = false }, cancellationToken); } public async Task UpdateOneAsync(Expression> predicate, Expression> fieldExpression, TField value, Expression> fieldExpression2, TField2 value2, Expression> fieldExpression3, TField3 value3, CancellationToken cancellationToken = default) { var updateDefinition = Builders.Update .Set(fieldExpression, value) .Set(fieldExpression2, value2) .Set(fieldExpression3, value3) ; await Collection.UpdateOneAsync(predicate, updateDefinition, new UpdateOptions() { IsUpsert = false }, cancellationToken); } public async Task UpdateOneAsync(Expression> predicate, UpdateDefinition updateDefinition, CancellationToken cancellationToken = default) { await Collection.UpdateOneAsync(predicate, updateDefinition, new UpdateOptions() { IsUpsert = false }, cancellationToken); } public async Task UpdateManyAsync(Expression> predicate, UpdateDefinition updateDefinition, CancellationToken cancellationToken = default) { await Collection.UpdateManyAsync(predicate, updateDefinition, new UpdateOptions() { IsUpsert = false }, cancellationToken); } public async Task CountAsync(Expression> predicate, CancellationToken cancellationToken = default) { var longResult = await Collection.CountDocumentsAsync(predicate, null, cancellationToken); if (longResult > int.MaxValue) throw new Exception("Exceeds integer maximum value"); return (int)longResult; } public Task LongCountAsync(Expression> predicate, CancellationToken cancellationToken = default) { return Collection.CountDocumentsAsync(predicate, null, cancellationToken); } } }