using System; using System.Collections.Generic; using System.Reflection; using System.Linq; using System.Collections; using ln.types.net; using ln.types.odb.ng.storage; using ln.collections; using ln.types.odb.ng.mappings; using ln.types.odb.ng.storage.fs; using ln.objects.catalog; namespace ln.types.odb.ng { public delegate ODBEntity ODBMap(Mapper mapper, object value); public delegate object ODBUnmap(Mapper mapper, ODBEntity oval); public delegate ODBEntity ODBMap(Mapper mapper, T value); public delegate T ODBUnmap(Mapper mapper, ODBEntity oval); public partial class Mapper : IDisposable { public static Mapper Default { get; set; } = new Mapper((IStorageContainer)null); public IStorageContainer StorageContainer { get; private set; } public IdentityCache IdentityCache { get; } = new IdentityCache(); Dictionary mappings = new Dictionary(); mappings.ObjectMapping ObjectMapping { get; } public Mapper(string basePath) :this(new FSStorageContainer(basePath)) { StorageContainer.Open(); } public Mapper(IStorageContainer storageContainer) { if (Default?.StorageContainer == null) Default = this; this.StorageContainer = storageContainer; RegisterMapping( (mapper, value) => new ODBStringValue(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBInteger(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBInteger(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBInteger(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBUInteger(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBUInteger(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBUInteger(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBDouble(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBDouble(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBLong(DateTime.MinValue.Equals(value) ? 0 : new DateTimeOffset(value.ToUniversalTime()).ToUnixTimeMilliseconds() ), (mapper, oval) => DateTimeOffset.FromUnixTimeMilliseconds(oval.As()).DateTime ); RegisterMapping( (mapper, value) => new ODBDouble(value.TotalMilliseconds), (mapper, oval) => TimeSpan.FromMilliseconds(oval.As()) ); RegisterMapping( (mapper, value) => new ODBGuid(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBLong(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBULong(value), (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => (bool)value ? ODBBool.True : ODBBool.False, (mapper, oval) => oval.As() ); RegisterMapping( (mapper, value) => new ODBUInteger(value.AsUInt), (mapper, oval) => new IPv4(oval.As()) ); RegisterMapping( (mapper, value) => new ODBByteBuffer(value.ToCIDRBytes()), (mapper, oval) => new IPv6((oval.As())) ); ObjectMapping = new mappings.ObjectMapping(); RegisterMapping(typeof(object),ObjectMapping); } public void RegisterMapping(Type nativeType, IODBMapping mapping) { lock (mappings) { mappings[nativeType] = mapping; } } public void RegisterMapping(Type nativeType, ODBMap map, ODBUnmap unmap) { lock (mappings) { mappings[nativeType] = new mappings.SimpleMapping(map, unmap); } } public void RegisterMapping(ODBMap map, ODBUnmap unmap) { lock (mappings) { mappings[typeof(T)] = new mappings.SimpleMapping( (mapper, value) => map(mapper, (T)value), (mapper, value) => unmap(mapper, value) ); } } public IStorage GetStorage(Type type) => GetStorage(type, type.FullName); public IStorage GetStorage(Type type,string typeName) { IStorage storage = StorageContainer.GetStorage(typeName); if (!storage.IsOpen) storage.Open(); return storage; } public IODBMapping GetMapping() => GetMapping(typeof(T)); public IODBMapping GetMapping(Type type) { lock (this.mappings) { if (type == null) throw new ArgumentNullException(); if (mappings.ContainsKey(type)) return mappings[type]; if (typeof(string).Equals(type)) { return null; } else if (type.IsGenericType && (type.GetGenericTypeDefinition().Equals(typeof(Dictionary<,>)))) { mappings.Add(type, new mappings.DictionaryMapping()); return mappings[type]; } else if (type.IsGenericType && (type.GetGenericTypeDefinition().Equals(typeof(List<>)) || type.GetGenericTypeDefinition().Equals(typeof(HashSet<>)))) { mappings.Add(type, new mappings.ListMapping(type)); return mappings[type]; } else if (type.GetInterfaces().Contains(typeof(IDictionary))) { mappings.Add(type, new mappings.DictionaryMapping()); return mappings[type]; } else if (type.IsArray) { mappings.Add(type, new mappings.ListMapping(type)); return mappings[type]; } else if (type.IsEnum) { mappings.Add(type, new SimpleMapping( (mapper, value) => new ODBStringValue(Enum.GetName(type, value)), (mapper, oval) => Enum.Parse(type, (oval as ODBStringValue).Value as String) )); return mappings[type]; } else if (!type.IsPrimitive) { mappings.Add(type, new mappings.ClassMapping(type)); return mappings[type]; } return null; } } //public object GetDocumentID(object o) //{ // IODBMapping mapping = GetMapping(o.GetType()); // if (mapping is mappings.ClassMapping) // { // mappings.ClassMapping classMapping = mapping as mappings.ClassMapping; // return classMapping.getID(o); // } // return null; //} //public Type GetDocumentIDType(Type type) //{ // IODBMapping mapping = GetMapping(type); // if (mapping is mappings.ClassMapping) // { // mappings.ClassMapping classMapping = mapping as mappings.ClassMapping; // return classMapping.IDType; // } // return null; //} public virtual ODBEntity MapValue(object value) { if (value == null) return ODBNull.Instance; IODBMapping mapping = GetMapping(value.GetType()); if (mapping != null) return mapping.MapValue(this,value); throw new NotSupportedException(String.Format("Can't map {0} ({1})",value.GetType(),value)); } public virtual object UnmapValue(Type targetType,ODBEntity value) { if (ODBNull.Instance.Equals(value)) return null; if (value is Document) { Document doc = value as Document; String asmname = doc["__asm__"].As(); String typename = doc["__type__"].As(); if (typename != null) targetType = Type.GetType(String.Format("{0}, {1}",typename,asmname)); //Assembly.Load(asmname).GetType(typename); } //else if (value is ODBTypedValue) //{ // ODBTypedValue typedValue = value as ODBTypedValue; // targetType = typedValue.TargetType; //} IODBMapping mapping = GetMapping(targetType); if (mapping != null) return mapping.UnmapValue(this,value); return value.As(targetType); } public virtual object TryImplicitMapping(object value,Type targetType) { Type sourceType = value.GetType(); foreach (MethodInfo mop in sourceType.GetMethods(BindingFlags.Static | BindingFlags.Public)) { if (mop.Name.Equals("op_Implicit") && (mop.ReturnType.Equals(targetType))) if( (sourceType.Equals(mop.GetParameters().FirstOrDefault().ParameterType)) ) { return mop.Invoke(null, new object[] { value }); } } return value; } public void Dispose() {} public static String GetTypeName(Type type) { if (type == null) return null; return string.Format("{0}, {1}",type.FullName,type.Assembly.GetName().Name); } } }