using System; using System.Collections.Generic; using ln.bson.mapper.mappings; namespace ln.bson.mapper { public class BsonMapper { private static BsonMapper _defaultInstance; public static BsonMapper DefaultInstance { get { if (_defaultInstance is null) _defaultInstance = new BsonMapper(); return _defaultInstance; } } private Dictionary _bsonMappings = new Dictionary(); public BsonDocument Map(T o) => Map(typeof(T), o); public BsonDocument Map(object o) => Map(o.GetType(), o); public BsonDocument Map(Type type, object o) { if (TryGetMapping(type, out BsonMapping bsonMapping)) { if (bsonMapping.TryMapValue(this, o, out BsonValue bsonValue) && (bsonValue is BsonDocument bsonDocument)) return bsonDocument; throw new FormatException("could not map object to BsonDocument"); } throw new NotSupportedException(); } public T Unmap(BsonDocument document) => (T)Unmap(typeof(T), document); public object Unmap(Type type, BsonDocument document) { if (TryGetMapping(type, out BsonMapping bsonMapping) && bsonMapping.TryMapValue(this, document, out object o) ) return o; return null; } public bool TryGetMapping(Type type, out BsonMapping bsonMapping) { if (!_defaultMappings.TryGetValue(type, out bsonMapping) && !_bsonMappings.TryGetValue(type, out bsonMapping)) { if (type.IsArray) { Type mappingType = typeof(ArrayMapping<>).MakeGenericType(type.GetElementType()); bsonMapping = (BsonMapping) Activator.CreateInstance(mappingType); AddMapping(bsonMapping); } else if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Dictionary<,>)) && type.GetGenericArguments()[0].Equals(typeof(string))) { Type mappingType = typeof(DictionaryMapping<>).MakeGenericType(type.GetGenericArguments()[1]); bsonMapping = (BsonMapping)Activator.CreateInstance(mappingType); AddMapping(bsonMapping); } else if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(IList<>))) { Type mappingType = typeof(IListMapping<,>).MakeGenericType(type, type.GetGenericArguments()[0]); bsonMapping = (BsonMapping)Activator.CreateInstance(mappingType); AddMapping(bsonMapping); } else if (!type.IsPrimitive) { Type mappingType = typeof(ClassStructMapping<>).MakeGenericType(type); bsonMapping = (BsonMapping) Activator.CreateInstance(mappingType); AddMapping(bsonMapping); } else throw new NotSupportedException(); } return true; } public void AddMapping(BsonMapping bsonMapping) => AddMapping(bsonMapping, false); public void AddMapping(BsonMapping bsonMapping, bool replace) { _bsonMappings.Add(bsonMapping.SourceType, bsonMapping); } public BsonMapping CreateMapping() { if (TryGetMapping(typeof(T), out BsonMapping mapping)) return mapping; return null; } private static Dictionary _defaultMappings = new Dictionary(); public static void AddDefaultMapping(BsonMapping bsonMapping) => _defaultMappings.Add(bsonMapping.SourceType, bsonMapping); static BsonMapper() { AddDefaultMapping(new BsonMapping.Int32()); AddDefaultMapping(new BsonMapping.Int64()); AddDefaultMapping(new BsonMapping.Double()); AddDefaultMapping(new BsonMapping.String()); AddDefaultMapping(new BsonMapping.Guid()); AddDefaultMapping(new BsonMapping.Boolean()); AddDefaultMapping(new BsonMapping.Binary()); AddDefaultMapping(new BsonMapping.DateTime()); } } }