luban/src/Luban.Job.Cfg/Source/DataCreators/SheetDataCreator.cs

557 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Luban.Common.Utils;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataSources.Excel;
using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.RawDefs;
using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Cfg.DataCreators
{
class SheetDataCreator : ITypeFuncVisitor<Sheet, TitleRow, DType>
{
public static SheetDataCreator Ins { get; } = new();
private bool CheckNull(bool nullable, object o)
{
return nullable && (o == null || (o is string s && s == "null"));
}
private bool CheckDefault(object o)
{
return o == null || (o is string s && s.Length == 0);
}
public DType Accept(TBool type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DBool.ValueOf(false);
}
if (x is bool v)
{
return DBool.ValueOf(v);
}
return DBool.ValueOf(bool.Parse(x.ToString()));
}
public DType Accept(TByte type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DByte.Default;
}
return DByte.ValueOf(byte.Parse(x.ToString()));
}
public DType Accept(TShort type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DShort.Default;
}
return DShort.ValueOf(short.Parse(x.ToString()));
}
public DType Accept(TFshort type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DFshort.Default;
}
return DFshort.ValueOf(short.Parse(x.ToString()));
}
public DType Accept(TInt type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DInt.Default;
}
return DInt.ValueOf(int.Parse(x.ToString()));
}
public DType Accept(TFint type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DFint.Default;
}
return DFint.ValueOf(int.Parse(x.ToString()));
}
public DType Accept(TLong type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DLong.Default;
}
return DLong.ValueOf(long.Parse(x.ToString()));
}
public DType Accept(TFlong type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DFlong.Default;
}
return DFlong.ValueOf(long.Parse(x.ToString()));
}
public DType Accept(TFloat type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DFloat.Default;
}
return DFloat.ValueOf(float.Parse(x.ToString()));
}
public DType Accept(TDouble type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
return DDouble.Default;
}
return DDouble.ValueOf(double.Parse(x.ToString()));
}
public DType Accept(TEnum type, Sheet sheet, TitleRow row)
{
object x = row.Current.Value;
if (CheckNull(type.IsNullable, x))
{
return null;
}
return new DEnum(type, x.ToString());
}
private static string ParseString(object d)
{
if (d == null)
{
return string.Empty;
}
else if (d is string s)
{
return DataUtil.UnEscapeString(s);
}
else
{
return d.ToString();
}
}
public DType Accept(TString type, Sheet sheet, TitleRow row)
{
var s = ParseString(row.Current);
if (s == null)
{
if (type.IsNullable)
{
return null;
}
else
{
throw new InvalidExcelDataException("字段不是nullable类型不能为null");
}
}
return DString.ValueOf(s);
}
public DType Accept(TBytes type, Sheet sheet, TitleRow row)
{
throw new NotImplementedException();
}
public DType Accept(TText type, Sheet sheet, TitleRow row)
{
if (row.Row.Count != 2)
{
throw new Exception($"text 要求两个字段");
}
var key = ParseString(row.Row[0].Value);
var text = ParseString(row.Row[1].Value);
DataUtil.ValidateText(key, text);
return new DText(key, text);
}
private List<DType> CreateBeanFields(DefBean bean, Sheet sheet, TitleRow row)
{
var list = new List<DType>();
foreach (DefField f in bean.HierarchyFields)
{
string fname = f.Name;
TitleRow field = row.GetSubTitleNamedRow(fname);
if (field == null)
{
throw new Exception($"bean:'{bean.FullName}' 缺失 列:'{fname}',请检查是否写错或者遗漏");
}
try
{
list.Add(f.CType.Apply(this, sheet, field));
}
catch (DataCreateException dce)
{
dce.Push(bean, f);
throw;
}
catch (Exception e)
{
var dce = new DataCreateException(e, $"列:{fname}");
dce.Push(bean, f);
throw dce;
}
}
return list;
}
public DType Accept(TBean type, Sheet sheet, TitleRow row)
{
string sep = GetSep(type);
if (row.Row != null)
{
var s = row.AsStream(sep);
return type.Apply(ExcelStreamDataCreator.Ins, s);
}
else if (row.Rows != null)
{
throw new NotSupportedException();
//var s = row.AsMultiRowStream(sep);
//return new DArray(type, ReadList(type.ElementType, s));
}
else if (row.Fields != null)
{
var originBean = (DefBean)type.Bean;
if (originBean.IsAbstractType)
{
string subType = row.GetSubTitleNamedRow(DefBean.TYPE_NAME_KEY).Current.Value.ToString().Trim();
if (subType.ToLower() == DefBean.BEAN_NULL_STR)
{
if (!type.IsNullable)
{
throw new Exception($"type:'{type}' 不是可空类型 '{type.Bean.FullName}?' , 不能为空");
}
return null;
}
string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType);
DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType);
if (implType == null)
{
throw new Exception($"type:'{fullType}' 不是 bean 类型");
}
return new DBean(originBean, implType, CreateBeanFields(implType, sheet, row));
}
else
{
if (type.IsNullable)
{
string subType = row.GetSubTitleNamedRow(DefBean.TYPE_NAME_KEY).Current.Value.ToString().Trim();
if (subType == DefBean.BEAN_NULL_STR)
{
return null;
}
else if (subType != DefBean.BEAN_NOT_NULL_STR && subType != originBean.Name)
{
throw new Exception($"type:'{type.Bean.FullName}' 可空标识:'{subType}' 不合法(只能为{DefBean.BEAN_NOT_NULL_STR}或{DefBean.BEAN_NULL_STR}或{originBean.Name})");
}
}
return new DBean(originBean, originBean, CreateBeanFields(originBean, sheet, row));
}
}
else if (row.Elements != null)
{
throw new NotSupportedException();
}
else
{
throw new Exception();
}
}
const string SimpleContainerSep = ",;";
public string GetSep(TType type)
{
if (type.Tags.TryGetValue("sep", out var s) && !string.IsNullOrWhiteSpace(s))
{
return s;
}
switch (type)
{
case TBean tb: return (tb.Bean as DefBean).Sep;
case TArray ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? SimpleContainerSep : "";
case TList ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? SimpleContainerSep : "";
case TSet ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? SimpleContainerSep : "";
default: return "";
}
}
public List<DType> ReadList(TType type, ExcelStream stream)
{
var datas = new List<DType>();
while (!stream.TryReadEOF())
{
datas.Add(type.Apply(ExcelStreamDataCreator.Ins, stream));
}
return datas;
}
private static List<DType> ReadList(TType type, IEnumerable<ExcelStream> streams)
{
var datas = new List<DType>();
foreach (var stream in streams)
{
while (!stream.TryReadEOF())
{
datas.Add(type.Apply(ExcelStreamDataCreator.Ins, stream));
}
}
return datas;
}
public DType Accept(TArray type, Sheet sheet, TitleRow row)
{
string sep = GetSep(type);
if (row.Row != null)
{
var s = row.AsStream(sep);
return new DArray(type, ReadList(type.ElementType, s));
}
else if (row.Rows != null)
{
var s = row.AsMultiRowStream(sep);
return new DArray(type, ReadList(type.ElementType, s));
}
else if (row.Fields != null)
{
throw new NotSupportedException();
}
else if (row.Elements != null)
{
return new DArray(type, row.Elements.Select(e => type.ElementType.Apply(this, sheet, e)).ToList());
}
else
{
throw new Exception();
}
}
public DType Accept(TList type, Sheet sheet, TitleRow row)
{
string sep = GetSep(type);
if (row.Row != null)
{
var s = row.AsStream(sep);
return new DList(type, ReadList(type.ElementType, s));
}
else if (row.Rows != null)
{
var s = row.AsMultiRowStream(sep);
return new DList(type, ReadList(type.ElementType, s));
}
else if (row.Fields != null)
{
throw new NotSupportedException();
}
else if (row.Elements != null)
{
return new DList(type, row.Elements.Select(e => type.ElementType.Apply(this, sheet, e)).ToList());
}
else
{
throw new Exception();
}
}
public DType Accept(TSet type, Sheet sheet, TitleRow row)
{
string sep = GetSep(type);
if (row.Row != null)
{
var s = row.AsStream(sep);
return new DSet(type, ReadList(type.ElementType, s));
}
else if (row.Rows != null)
{
var s = row.AsMultiRowStream(sep);
return new DSet(type, ReadList(type.ElementType, s));
}
else if (row.Fields != null)
{
throw new NotSupportedException();
}
else if (row.Elements != null)
{
throw new NotSupportedException();
}
else
{
throw new Exception();
}
}
public DType Accept(TMap type, Sheet sheet, TitleRow row)
{
string sep = GetSep(type);
if (row.Row != null)
{
var s = row.AsStream(sep);
var datas = new Dictionary<DType, DType>();
while (!s.TryReadEOF())
{
var key = type.KeyType.Apply(ExcelStreamDataCreator.Ins, s);
var value = type.ValueType.Apply(ExcelStreamDataCreator.Ins, s);
datas.Add(key, value);
}
return new DMap(type, datas);
}
else if (row.Rows != null)
{
var datas = new Dictionary<DType, DType>();
foreach (ExcelStream s in row.AsMultiRowStream(sep))
{
while (!s.TryReadEOF())
{
var key = type.KeyType.Apply(ExcelStreamDataCreator.Ins, s);
var value = type.ValueType.Apply(ExcelStreamDataCreator.Ins, s);
datas.Add(key, value);
}
}
return new DMap(type, datas);
}
else if (row.Fields != null)
{
var datas = new Dictionary<DType, DType>();
foreach (var e in row.Fields)
{
var keyData = type.KeyType.Apply(StringDataCreator.Ins, e.Key);
var valueData = type.ValueType.Apply(ExcelStreamDataCreator.Ins, e.Value.AsStream(sep));
datas.Add(keyData, valueData);
}
return new DMap(type, datas);
}
else if (row.Elements != null)
{
throw new NotSupportedException();
}
else
{
throw new Exception();
}
}
public DType Accept(TVector2 type, Sheet sheet, TitleRow row)
{
var d = row.Current.Value;
if (CheckNull(type.IsNullable, d))
{
return null;
}
return DataUtil.CreateVector(type, d.ToString());
}
public DType Accept(TVector3 type, Sheet sheet, TitleRow row)
{
var d = row.Current.Value;
if (CheckNull(type.IsNullable, d))
{
return null;
}
return DataUtil.CreateVector(type, d.ToString());
}
public DType Accept(TVector4 type, Sheet sheet, TitleRow row)
{
var d = row.Current.Value;
if (CheckNull(type.IsNullable, d))
{
return null;
}
return DataUtil.CreateVector(type, d.ToString());
}
public DType Accept(TDateTime type, Sheet sheet, TitleRow row)
{
var d = row.Current.Value;
if (CheckNull(type.IsNullable, d))
{
return null;
}
if (d is System.DateTime datetime)
{
return new DDateTime(datetime);
}
return DataUtil.CreateDateTime(d.ToString());
}
}
}