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

611 lines
19 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);
}
private void ThrowIfNonEmpty(TitleRow row)
{
if (row.SelfTitle.NonEmpty)
{
throw new Exception($"字段不允许为空");
}
}
public DType Accept(TBool type, Sheet sheet, TitleRow row)
{
object x = row.Current;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
ThrowIfNonEmpty(row);
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;
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;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
ThrowIfNonEmpty(row);
return DShort.Default;
}
return DShort.ValueOf(short.Parse(x.ToString()));
}
public DType Accept(TFshort type, Sheet sheet, TitleRow row)
{
object x = row.Current;
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;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
ThrowIfNonEmpty(row);
return DInt.Default;
}
return DInt.ValueOf(int.Parse(x.ToString()));
}
public DType Accept(TFint type, Sheet sheet, TitleRow row)
{
object x = row.Current;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
ThrowIfNonEmpty(row);
return DFint.Default;
}
return DFint.ValueOf(int.Parse(x.ToString()));
}
public DType Accept(TLong type, Sheet sheet, TitleRow row)
{
object x = row.Current;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
ThrowIfNonEmpty(row);
return DLong.Default;
}
return DLong.ValueOf(long.Parse(x.ToString()));
}
public DType Accept(TFlong type, Sheet sheet, TitleRow row)
{
object x = row.Current;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
ThrowIfNonEmpty(row);
return DFlong.Default;
}
return DFlong.ValueOf(long.Parse(x.ToString()));
}
public DType Accept(TFloat type, Sheet sheet, TitleRow row)
{
object x = row.Current;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
ThrowIfNonEmpty(row);
return DFloat.Default;
}
return DFloat.ValueOf(float.Parse(x.ToString()));
}
public DType Accept(TDouble type, Sheet sheet, TitleRow row)
{
object x = row.Current;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (CheckDefault(x))
{
ThrowIfNonEmpty(row);
return DDouble.Default;
}
return DDouble.ValueOf(double.Parse(x.ToString()));
}
public DType Accept(TEnum type, Sheet sheet, TitleRow row)
{
object x = row.Current;
if (CheckNull(type.IsNullable, x))
{
return null;
}
if (x == null)
{
throw new InvalidExcelDataException($"枚举值不能为空");
}
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)
{
object x = row.Current;
if (CheckDefault(x))
{
ThrowIfNonEmpty(row);
}
var s = ParseString(x);
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 (string.IsNullOrEmpty(row.SelfTitle.Sep))
{
if (row.CellCount != 2)
{
throw new Exception($"text 要求两个字段");
}
int startIndex = row.SelfTitle.FromIndex;
var key = ParseString(row.Row[startIndex].Value);
var text = ParseString(row.Row[startIndex + 1].Value);
if (type.IsNullable && key == null && text == null)
{
return null;
}
DataUtil.ValidateText(key, text);
return new DText(key, text);
}
else
{
var s = row.AsStream("");
return type.Apply(ExcelStreamDataCreator.Ins, s);
}
}
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} 位置:{field.Location}");
dce.Push(bean, f);
throw dce;
}
}
return list;
}
public DType Accept(TBean type, Sheet sheet, TitleRow row)
{
string sep = DataUtil.GetSep(type);
if (row.Row != null)
{
var s = row.AsStream("");
if (type.IsNullable && s.TryReadEOF())
{
return null;
}
return type.Apply(ExcelStreamDataCreator.Ins, s);
}
else if (row.Rows != null)
{
var s = row.AsMultiRowConcatStream("");
if (type.IsNullable && s.TryReadEOF())
{
return null;
}
return type.Apply(ExcelStreamDataCreator.Ins, s);
}
else if (row.Fields != null)
{
var originBean = (DefBean)type.Bean;
if (originBean.IsAbstractType)
{
string subType = row.GetSubTitleNamedRow(DefBean.TYPE_NAME_KEY).Current.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.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)
{
var s = row.AsMultiRowConcatElements(sep);
return type.Apply(ExcelStreamDataCreator.Ins, s);
}
else
{
throw new Exception();
}
}
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 = DataUtil.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 Exception($"array 不支持 子字段. 忘记将字段设为多行模式? {row.SelfTitle.Name} => *{row.SelfTitle.Name}");
}
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 = DataUtil.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 Exception($"list 不支持 子字段. 忘记将字段设为多行模式? {row.SelfTitle.Name} => *{row.SelfTitle.Name}");
}
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 = DataUtil.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 Exception($"set 不支持 子字段");
}
else if (row.Elements != null)
{
throw new NotSupportedException();
}
else
{
throw new Exception();
}
}
public DType Accept(TMap type, Sheet sheet, TitleRow row)
{
string sep = DataUtil.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);
if (Sheet.IsBlankRow(e.Value.Row, e.Value.SelfTitle.FromIndex, e.Value.SelfTitle.ToIndex))
{
continue;
}
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)
{
var datas = new Dictionary<DType, DType>();
foreach (var e in row.Elements)
{
var stream = e.AsStream("");
var keyData = type.KeyType.Apply(ExcelStreamDataCreator.Ins, stream);
var valueData = type.ValueType.Apply(ExcelStreamDataCreator.Ins, stream);
datas.Add(keyData, valueData);
}
return new DMap(type, datas);
}
else
{
throw new Exception();
}
}
public DType Accept(TVector2 type, Sheet sheet, TitleRow row)
{
var d = row.Current;
if (CheckNull(type.IsNullable, d))
{
return null;
}
if (CheckDefault(d))
{
ThrowIfNonEmpty(row);
return DVector2.Default;
}
return DataUtil.CreateVector(type, d.ToString());
}
public DType Accept(TVector3 type, Sheet sheet, TitleRow row)
{
var d = row.Current;
if (CheckNull(type.IsNullable, d))
{
return null;
}
if (CheckDefault(d))
{
ThrowIfNonEmpty(row);
return DVector3.Default;
}
return DataUtil.CreateVector(type, d.ToString());
}
public DType Accept(TVector4 type, Sheet sheet, TitleRow row)
{
var d = row.Current;
if (CheckNull(type.IsNullable, d))
{
return null;
}
if (CheckDefault(d))
{
ThrowIfNonEmpty(row);
return DVector4.Default;
}
return DataUtil.CreateVector(type, d.ToString());
}
public DType Accept(TDateTime type, Sheet sheet, TitleRow row)
{
var d = row.Current;
if (CheckNull(type.IsNullable, d))
{
return null;
}
if (d is System.DateTime datetime)
{
return new DDateTime(datetime);
}
return DataUtil.CreateDateTime(d.ToString());
}
}
}