ln.types/odb/ODBMapper.cs

221 lines
7.1 KiB
C#

using System;
using ln.types.odb.values;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using System.Reflection;
using System.Linq;
using System.Collections;
namespace ln.types.odb
{
public class IgnoreFieldAttribute : Attribute
{
}
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 interface IODBMapping
{
ODBValue MapValue(ODBMapper mapper, object value);
object UnmapValue(ODBMapper mapper, ODBValue oval);
}
public interface IODBMapping<T>
{
ODBValue MapValue(ODBMapper mapper, T value);
T UnmapValue(ODBMapper mapper, ODBValue oval);
}
public class SimpleMapping : IODBMapping
{
ODBMap map;
ODBUnmap unmap;
public SimpleMapping(ODBMap map,ODBUnmap unmap)
{
this.map = map;
this.unmap = unmap;
}
public ODBValue MapValue(ODBMapper mapper, object value)
{
return map(mapper, value);
}
public object UnmapValue(ODBMapper mapper, ODBValue oval)
{
return unmap(mapper, oval);
}
}
public class SimpleMapping<T> : SimpleMapping
{
public SimpleMapping(ODBMap<T> map, ODBUnmap<T> unmap)
:base((mapper, value) => map(mapper,(T)value),(mapper, oval) => unmap(mapper,oval))
{}
}
public class ODBMapper
{
public static ODBMapper Default { get; } = new ODBMapper();
Dictionary<Type, IODBMapping> mappings = new Dictionary<Type, IODBMapping>();
private ODBMapper()
{
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).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 ODBInteger(value ? -1 : 0),
(mapper, oval) => oval.AsBool
);
RegisterMapping(typeof(object),new ObjectMapping());
}
public void RegisterMapping(Type nativeType,IODBMapping mapping)
{
mappings[nativeType] = mapping;
}
public void RegisterMapping(Type nativeType, ODBMap map, ODBUnmap unmap)
{
mappings[nativeType] = new SimpleMapping(map, unmap);
}
public void RegisterMapping<T>(ODBMap<T> map, ODBUnmap<T> unmap)
{
mappings[typeof(T)] = new SimpleMapping<T>(map, unmap);
}
public IODBMapping GetMapping<T>() => null;
public IODBMapping GetMapping(Type type)
{
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 DictionaryMapping());
return mappings[type];
}
else if (type.GetInterfaces().Contains(typeof(IDictionary)))
{
mappings.Add(type, new DictionaryMapping());
return mappings[type];
}
else if (type.IsArray)
{
mappings.Add(type, new ListMapping(type));
return mappings[type];
}
else if (!type.IsPrimitive)
{
mappings.Add(type, new ClassMapping(type));
return mappings[type];
}
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 ODBDocument)
{
ODBDocument doc = value as ODBDocument;
String asmname = doc["__asm__"].AsString;
String typename = doc["__type__"].AsString;
targetType = Assembly.Load(asmname).GetType(typename);
}
IODBMapping mapping = GetMapping(targetType);
if (mapping != null)
return mappings[targetType].UnmapValue(this,value);
return Convert.ChangeType(value.Value, targetType);
}
public virtual T ToNativeValue<T>(ODBValue value)
{
return (T)UnmapValue(typeof(T), value);
}
}
}