ln.types/odb/ng/ODBMapper.cs

272 lines
9.5 KiB
C#

using System;
using ln.types.odb.values;
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.types.btree;
using ln.types.odb.ng.mappings;
namespace ln.types.odb.ng
{
public delegate ODBValue ODBMap(ODBMapper mapper, object value);
public delegate object ODBUnmap(ODBMapper mapper, ODBValue oval);
public delegate ODBValue ODBMap<T>(ODBMapper mapper, T value);
public delegate T ODBUnmap<T>(ODBMapper mapper, ODBValue oval);
public partial class ODBMapper
{
public static ODBMapper Default { get; set; }
public IStorageContainer StorageContainer { get; private set; }
Dictionary<Type, IODBMapping> mappings = new Dictionary<Type, IODBMapping>();
mappings.ObjectMapping ObjectMapping { get; }
public ODBMapper(string basePath)
:this(new FSStorageContainer(basePath))
{ }
public ODBMapper(IStorageContainer storageContainer)
{
if (Default == null)
Default = this;
this.StorageContainer = storageContainer;
RegisterMapping<string>(
(mapper, value) => new ODBStringValue(value),
(mapper, oval) => oval.AsString
);
RegisterMapping<int>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.AsInt
);
RegisterMapping<short>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.AsShort
);
RegisterMapping<byte>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.AsByte
);
RegisterMapping<uint>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.AsUInt
);
RegisterMapping<ushort>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.AsUShort
);
RegisterMapping<char>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.AsChar
);
RegisterMapping<double>(
(mapper, value) => new ODBDouble(value),
(mapper, oval) => oval.AsDouble
);
RegisterMapping<float>(
(mapper, value) => new ODBDouble(value),
(mapper, oval) => oval.AsFloat
);
RegisterMapping<DateTime>(
(mapper, value) => new ODBLong(DateTime.MinValue.Equals(value) ? 0 : new DateTimeOffset(value.ToUniversalTime()).ToUnixTimeMilliseconds() ),
(mapper, oval) => DateTimeOffset.FromUnixTimeMilliseconds(oval.AsLong).DateTime
);
RegisterMapping<TimeSpan>(
(mapper, value) => new ODBDouble(value.TotalMilliseconds),
(mapper, oval) => TimeSpan.FromMilliseconds(oval.AsDouble)
);
RegisterMapping<Guid>(
(mapper, value) => new ODBGuid(value),
(mapper, oval) => oval.AsGuid
);
RegisterMapping<long>(
(mapper, value) => new ODBLong(value),
(mapper, oval) => oval.AsLong
);
RegisterMapping<ulong>(
(mapper, value) => new ODBULong(value),
(mapper, oval) => oval.AsULong
);
RegisterMapping<bool>(
(mapper, value) => new ODBBool(value),
(mapper, oval) => oval.AsBool
);
RegisterMapping<IPv4>(
(mapper, value) => new ODBUInteger(value.AsUInt),
(mapper, oval) => new IPv4(oval.AsUInt)
);
ObjectMapping = new mappings.ObjectMapping();
RegisterMapping(typeof(object),ObjectMapping);
}
public void RegisterMapping(Type nativeType, IODBMapping mapping)
{
mappings[nativeType] = mapping;
}
public void RegisterMapping(Type nativeType, ODBMap map, ODBUnmap unmap)
{
mappings[nativeType] = new mappings.SimpleMapping(map, unmap);
}
public void RegisterMapping<T>(ODBMap<T> map, ODBUnmap<T> unmap)
{
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)
{
return StorageContainer.GetStorage(typeName);
}
public IODBMapping GetMapping<T>() => null;
public IODBMapping GetMapping(Type type)
{
lock (this)
{
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.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 ODBValue MapValue(object value)
{
if (value == null)
return ODBNull.Instance;
IODBMapping mapping = GetMapping(value.GetType());
if (mapping != null)
return mappings[value.GetType()].MapValue(this,value);
throw new NotSupportedException(String.Format("Can't map {0} ({1})",value.GetType(),value));
}
public virtual object UnmapValue(Type targetType,ODBValue value)
{
if (ODBNull.Instance.Equals(value))
return null;
if (value is Document)
{
Document doc = value as Document;
String asmname = doc["__asm__"].AsString;
String typename = doc["__type__"].AsString;
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 mappings[targetType].UnmapValue(this,value);
return Convert.ChangeType(value.Value, targetType);
}
public virtual T ToNativeValue<T>(ODB odb,ODBValue value)
{
return (T)UnmapValue(typeof(T), value);
}
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 static String GetTypeName(Type type)
{
if (type == null)
return null;
return string.Format("{0}, {1}",type.FullName,type.Assembly.GetName().Name);
}
}
}