ln.objects/ng/Mapper.cs

303 lines
11 KiB
C#

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<T>(Mapper mapper, T value);
public delegate T ODBUnmap<T>(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<Type, IODBMapping> mappings = new Dictionary<Type, IODBMapping>();
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<string>(
(mapper, value) => new ODBStringValue(value),
(mapper, oval) => oval.As<String>()
);
RegisterMapping<int>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.As<int>()
);
RegisterMapping<short>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.As<short>()
);
RegisterMapping<byte>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.As<Byte>()
);
RegisterMapping<uint>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.As<uint>()
);
RegisterMapping<ushort>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.As<ushort>()
);
RegisterMapping<char>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.As<Char>()
);
RegisterMapping<double>(
(mapper, value) => new ODBDouble(value),
(mapper, oval) => oval.As<double>()
);
RegisterMapping<float>(
(mapper, value) => new ODBDouble(value),
(mapper, oval) => oval.As<float>()
);
RegisterMapping<DateTime>(
(mapper, value) => new ODBLong(DateTime.MinValue.Equals(value) ? 0 : new DateTimeOffset(value.ToUniversalTime()).ToUnixTimeMilliseconds() ),
(mapper, oval) => DateTimeOffset.FromUnixTimeMilliseconds(oval.As<long>()).DateTime
);
RegisterMapping<TimeSpan>(
(mapper, value) => new ODBDouble(value.TotalMilliseconds),
(mapper, oval) => TimeSpan.FromMilliseconds(oval.As<double>())
);
RegisterMapping<Guid>(
(mapper, value) => new ODBGuid(value),
(mapper, oval) => oval.As<Guid>()
);
RegisterMapping<long>(
(mapper, value) => new ODBLong(value),
(mapper, oval) => oval.As<long>()
);
RegisterMapping<ulong>(
(mapper, value) => new ODBULong(value),
(mapper, oval) => oval.As<ulong>()
);
RegisterMapping<bool>(
(mapper, value) => (bool)value ? ODBBool.True : ODBBool.False,
(mapper, oval) => oval.As<bool>()
);
RegisterMapping<IPv4>(
(mapper, value) => new ODBUInteger(value.AsUInt),
(mapper, oval) => new IPv4(oval.As<uint>())
);
RegisterMapping<IPv6>(
(mapper, value) => new ODBByteBuffer(value.ToCIDRBytes()),
(mapper, oval) => new IPv6((oval.As<byte[]>()))
);
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<T>(ODBMap<T> map, ODBUnmap<T> 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<T>() => 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>();
String typename = doc["__type__"].As<string>();
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);
}
}
}