272 lines
9.5 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|