private static void ErrorWhenSpecified(ValueKinds errorOnKinds, XArray source, bool[] couldNotConvert, string errorContextMessage) { // If not erroring on anything, nothing to check if (errorOnKinds == ValueKinds.None) { return; } // TODO: Use table failure logs. Log should track absolute row count to improve message because this is an IColumn and can't tell. if (errorOnKinds == ValueKinds.InvalidOrNull) { if (couldNotConvert != null) { throw new InvalidOperationException($"{errorContextMessage} failed for at least one value."); } } else if (errorOnKinds == ValueKinds.Invalid) { if (couldNotConvert != null && source.HasNulls) { for (int i = 0; i < source.Count; ++i) { if (couldNotConvert[i] == true && !source.NullRows[source.Index(i)]) { throw new InvalidOperationException($"{errorContextMessage} failed for at least one value."); } } } } else { throw new NotImplementedException(errorOnKinds.ToString()); } }
public IXColumn Build(IXTable source, XDatabaseContext context) { // Column and ToType are required IXColumn column = context.Parser.NextColumn(source, context); Type toType = context.Parser.NextType(); // ErrorOn, DefaultValue, and ChangeToDefaultOn are optional ValueKinds errorOn = ValueKindsDefaults.ErrorOn; object defaultValue = null; ValueKinds changeToDefaultOn = ValueKindsDefaults.ChangeToDefault; if (context.Parser.HasAnotherArgument) { // Parse ErrorOn if there's another argument errorOn = context.Parser.NextEnum <ValueKinds>(); // If there's another argument, both of the last two are required if (context.Parser.HasAnotherArgument) { defaultValue = context.Parser.NextLiteralValue(); changeToDefaultOn = context.Parser.NextEnum <ValueKinds>(); } } return(CastedColumn.Build(source, column, toType, errorOn, defaultValue, changeToDefaultOn)); }
private CastedColumn(IXColumn column, Type targetType, ValueKinds errorOnKinds = ValueKindsDefaults.ErrorOn, object defaultValue = null, ValueKinds changeToDefaultKinds = ValueKindsDefaults.ChangeToDefault) { _column = column; ColumnDetails = column.ColumnDetails.ChangeType(targetType); _converter = TypeConverterFactory.GetConverter(column.ColumnDetails.Type, targetType, errorOnKinds, defaultValue, changeToDefaultKinds); _targetType = targetType; _errorOnKinds = errorOnKinds; _defaultValue = defaultValue; _changeToDefaultKinds = changeToDefaultKinds; }
public static Func <XArray, XArray> TryGetConverter(Type sourceType, Type targetType, ValueKinds errorOn = ValueKindsDefaults.ErrorOn, object defaultValue = null, ValueKinds changeToDefault = ValueKindsDefaults.ChangeToDefault) { // Error if there's a default but nothing will be changed to it if (defaultValue != null && changeToDefault == ValueKinds.None) { throw new ArgumentException("Cast with a default value must have [ChangeToDefaultOn] not 'None'."); } // Convert the defaultValue to the right type defaultValue = ConvertSingle(defaultValue, targetType); Func <XArray, XArray> converter = null; // See if the target type provides conversion ITypeProvider targetTypeProvider = TypeProviderFactory.TryGet(targetType); if (targetTypeProvider != null) { converter = NegatedTryConvertToConverter(targetTypeProvider.TryGetNegatedTryConvert(sourceType, targetType, defaultValue), "", errorOn, changeToDefault); if (converter != null) { return(converter); } } // See if the source type provides conversion ITypeProvider sourceTypeProvider = TypeProviderFactory.TryGet(sourceType); if (sourceTypeProvider != null) { converter = NegatedTryConvertToConverter(sourceTypeProvider.TryGetNegatedTryConvert(sourceType, targetType, defaultValue), "", errorOn, changeToDefault); if (converter != null) { return(converter); } } // Try again with implicit string to String8 conversion if (sourceType == typeof(string)) { converter = TryGetConverter(typeof(String8), targetType, errorOn, defaultValue, changeToDefault); // If found, encode the string to String8 conversion and then the String8 to target conversion if (converter != null) { Func <XArray, XArray> innerConverter = GetConverter(typeof(string), typeof(String8), errorOn, defaultValue, changeToDefault); return((xarray) => converter(innerConverter(xarray))); } } return(null); }
public static Func <XArray, XArray> GetConverter(Type sourceType, Type targetType, ValueKinds errorOn = ValueKindsDefaults.ErrorOn, object defaultValue = null, ValueKinds changeToDefault = ValueKindsDefaults.ChangeToDefault) { Func <XArray, XArray> converter = TryGetConverter(sourceType, targetType, errorOn, defaultValue, changeToDefault); if (converter == null) { throw new ArgumentException($"No converter available from {sourceType.Name} to {targetType.Name}."); } return(converter); }
public static Func <XArray, XArray> NegatedTryConvertToConverter(NegatedTryConvert negatedTryConvert, string errorContextMessage, ValueKinds errorOn = ValueKindsDefaults.ErrorOn, ValueKinds changeToDefault = ValueKindsDefaults.ChangeToDefault) { if (negatedTryConvert == null) { return(null); } Array result; bool[] couldNotConvert; bool[] buffer = null; if (changeToDefault == ValueKinds.None) { // Invalid/Null/Empty -> Null, so couldNotConvert becomes IsNull return((values) => { couldNotConvert = negatedTryConvert(values, out result); ErrorWhenSpecified(errorOn, values, couldNotConvert, errorContextMessage); return XArray.All(result, values.Count, MergeNulls(values, couldNotConvert, ref buffer), values.Selector.IsSingleValue); }); } else if (changeToDefault == ValueKinds.Invalid) { // Invalid -> Default, so keep nulls from source return((values) => { couldNotConvert = negatedTryConvert(values, out result); ErrorWhenSpecified(errorOn, values, couldNotConvert, errorContextMessage); return XArray.All(result, values.Count, XArray.RemapNulls(values, ref couldNotConvert), values.Selector.IsSingleValue); }); } else if (changeToDefault == ValueKinds.InvalidOrNull) { // Invalid/Null/Empty -> Default, so negate all nulls return((values) => { couldNotConvert = negatedTryConvert(values, out result); ErrorWhenSpecified(errorOn, values, couldNotConvert, errorContextMessage); return XArray.All(result, values.Count, null, values.Selector.IsSingleValue); }); } else { throw new NotImplementedException(changeToDefault.ToString()); } }
public static Func <XArray, XArray> TryGetConverter(Type sourceType, Type targetType, ValueKinds errorOnKinds, object defaultValue, ValueKinds changeToDefaultKinds) { return(TypeConverterFactory.TryGetConverter(sourceType, targetType, errorOnKinds, defaultValue, changeToDefaultKinds)); }
public static IXColumn Build(IXTable source, IXColumn column, Type targetType, ValueKinds errorOnKinds = ValueKindsDefaults.ErrorOn, object defaultValue = null, ValueKinds changeToDefaultKinds = ValueKindsDefaults.ChangeToDefault) { // If the column is already the right type, just return it if (column.ColumnDetails.Type == targetType) { return(column); } // Convert constants individually if (column.IsConstantColumn()) { XArray array = column.ValuesGetter()(); return(new ConstantColumn(source, TypeConverterFactory.ConvertSingle(array.Array.GetValue(0), targetType), targetType)); } // Otherwise, wrap in a CastedColumn [Enums are automatically converted just once] return(new CastedColumn(column, targetType, errorOnKinds, defaultValue, changeToDefaultKinds)); }