public IClickHouseTableColumn EndRead(ClickHouseColumnSettings?settings) { var column = _underlyingReader.EndRead(settings); var dispatcher = new MapColumnDispatcher(column); return(TypeDispatcher.Dispatch(_fieldType, dispatcher)); }
internal ITypeDispatcher?GetColumnTypeDispatcher() { if (ColumnType == null) { return(null); } return(_columnTypeDispatcher ??= TypeDispatcher.Create(ColumnType)); }
private async ValueTask WriteRow(IReadOnlyCollection <object?> values, bool async, CancellationToken cancellationToken) { if (values == null) { throw new ArgumentNullException(nameof(values)); } if (values.Count != _columns.Count) { throw new ArgumentException("The number of values must be equal to the number of columns."); } var columnWriters = new List <IClickHouseColumnWriter>(_columns.Count); foreach (var value in values) { int i = columnWriters.Count; var columnInfo = _columns[i]; SingleRowColumnWriterDispatcher dispatcher; Type valueType; if (value != null && !(value is DBNull)) { dispatcher = new SingleRowColumnWriterDispatcher(value, columnInfo, _columnSettings?[i]); valueType = value.GetType(); } else if (columnInfo.TypeInfo.TypeName != "Nullable") { throw new ClickHouseException(ClickHouseErrorCodes.ColumnMismatch, $"The column \"{columnInfo.Name}\" at the position {i} doesn't support nulls."); } else { dispatcher = new SingleRowColumnWriterDispatcher(null, columnInfo, _columnSettings?[i]); valueType = columnInfo.TypeInfo.GetFieldType(); } IClickHouseColumnWriter columnWriter; try { columnWriter = TypeDispatcher.Dispatch(valueType, dispatcher); } catch (ClickHouseException ex) { throw new ClickHouseException(ex.ErrorCode, $"Column \"{columnInfo.Name}\" (position {i}): {ex.Message}", ex); } columnWriters.Add(columnWriter); } var table = new ClickHouseTableWriter(string.Empty, 1, columnWriters); await SendTable(table, async, cancellationToken); }
static ClickHouseParameterTests() { var properties = new Dictionary <string, Action <ClickHouseParameter, ClickHouseParameter> >(); foreach (var property in typeof(ClickHouseParameter).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (property.GetMethod == null || property.SetMethod == null || !property.GetMethod.IsPublic || !property.SetMethod.IsPublic) { continue; } var comparer = TypeDispatcher.Dispatch(property.PropertyType, new PropertyComparerDispatcher(property)); properties.Add(property.Name, comparer); } ParameterPublicProperties = new ReadOnlyDictionary <string, Action <ClickHouseParameter, ClickHouseParameter> >(properties); }
public IClickHouseColumnWriter CreateColumnWriter <T>(string columnName, IReadOnlyList <T> rows, ClickHouseColumnSettings?columnSettings) { if (_elementTypeInfo == null) { throw new ClickHouseException(ClickHouseErrorCodes.TypeNotFullySpecified, $"The type \"{ComplexTypeName}\" is not fully specified."); } Type?elementType = null; foreach (var genericItf in typeof(T).GetInterfaces().Where(itf => itf.IsGenericType)) { if (genericItf.GetGenericTypeDefinition() != typeof(IReadOnlyList <>)) { continue; } if (elementType == null) { elementType = genericItf.GetGenericArguments()[0]; } else { var elementTypeCandidate = genericItf.GetGenericArguments()[0]; if (elementType.IsAssignableFrom(elementTypeCandidate)) { elementType = elementTypeCandidate; } else if (!elementTypeCandidate.IsAssignableFrom(elementType)) { throw new ClickHouseException(ClickHouseErrorCodes.TypeNotSupported, $"Can't detect a type of the array's element. Candidates are: \"{elementType}\" and \"{elementTypeCandidate}\"."); } } } if (elementType == null) { throw new ClickHouseException(ClickHouseErrorCodes.TypeNotSupported, $"Can't detect a type of the array's element. The type \"{typeof(T)}\" doesn't implement \"{typeof(IReadOnlyList<>)}\"."); } var dispatcher = new ArrayColumnWriterDispatcher(columnName, ComplexTypeName, rows, columnSettings, _elementTypeInfo); return(TypeDispatcher.Dispatch(elementType, dispatcher)); }
public IClickHouseTableColumn EndRead(ClickHouseColumnSettings?settings) { var elementColumnReader = _elementColumnReader ?? _elementType.CreateColumnReader(0); var column = elementColumnReader.EndRead(settings); var ranges = _position == _ranges.Count ? _ranges : _ranges.Take(_position).ToList(); var columnType = column.GetType(); Type?recognizedElementType = null; foreach (var itf in columnType.GetInterfaces().Where(i => i.IsGenericType)) { var typeDef = itf.GetGenericTypeDefinition(); if (typeDef != typeof(IClickHouseTableColumn <>)) { continue; } if (recognizedElementType == null) { recognizedElementType = itf.GenericTypeArguments[0]; } else { recognizedElementType = null; break; } } if (recognizedElementType != null) { var reinterpretedColumn = TypeDispatcher.Dispatch(recognizedElementType, new ArrayTableColumnTypeDispatcher(column, ranges)); if (reinterpretedColumn != null) { return(reinterpretedColumn); } } return(new ArrayTableColumn(column, ranges)); }
public IClickHouseColumnWriter CreateColumnWriter <T>(string columnName, IReadOnlyList <T> rows, ClickHouseColumnSettings?columnSettings) { if (_elementTypeInfo == null) { throw new ClickHouseException(ClickHouseErrorCodes.TypeNotFullySpecified, $"The type \"{ComplexTypeName}\" is not fully specified."); } var rowType = typeof(T); Type?elementType = null; if (rowType.IsArray) { var rank = rowType.GetArrayRank(); if (rank > 1) { elementType = rowType.GetElementType() !; Debug.Assert(elementType != null); var listAdapterInfo = MultiDimensionalArrayReadOnlyListAdapter.Dispatch(elementType, rowType.GetArrayRank()); var mdaDispatcher = new MultiDimensionalArrayColumnWriterDispatcher( columnName, (IReadOnlyList <Array>)rows, columnSettings, _elementTypeInfo, listAdapterInfo.createList); return(TypeDispatcher.Dispatch(listAdapterInfo.listElementType, mdaDispatcher)); } } foreach (var genericItf in rowType.GetInterfaces().Where(itf => itf.IsGenericType)) { if (genericItf.GetGenericTypeDefinition() != typeof(IReadOnlyList <>)) { continue; } if (elementType == null) { elementType = genericItf.GetGenericArguments()[0]; } else { var elementTypeCandidate = genericItf.GetGenericArguments()[0]; if (elementType.IsAssignableFrom(elementTypeCandidate)) { elementType = elementTypeCandidate; } else if (!elementTypeCandidate.IsAssignableFrom(elementType)) { throw new ClickHouseException( ClickHouseErrorCodes.TypeNotSupported, $"Can't detect a type of the array's element. Candidates are: \"{elementType}\" and \"{elementTypeCandidate}\"."); } } } ArrayColumnWriterDispatcherBase dispatcher; if (elementType == null) { var rowGenericTypeDef = rowType.GetGenericTypeDefinition(); if (rowGenericTypeDef == typeof(ReadOnlyMemory <>)) { elementType = rowType.GetGenericArguments()[0] !; dispatcher = new ReadOnlyColumnWriterDispatcher(columnName, rows, columnSettings, _elementTypeInfo); } else if (rowGenericTypeDef == typeof(Memory <>)) { elementType = rowType.GetGenericArguments()[0] !; dispatcher = new MemoryColumnWriterDispatcher(columnName, rows, columnSettings, _elementTypeInfo); } else { throw new ClickHouseException( ClickHouseErrorCodes.TypeNotSupported, $"Can't detect a type of the array's element. The type \"{typeof(T)}\" doesn't implement \"{typeof(IReadOnlyList<>)}\"."); } } else { dispatcher = new ArrayColumnWriterDispatcher(columnName, rows, columnSettings, _elementTypeInfo); } try { return(TypeDispatcher.Dispatch(elementType, dispatcher)); } catch (ClickHouseException ex) when(ex.ErrorCode == ClickHouseErrorCodes.TypeNotSupported) { throw new ClickHouseException(ex.ErrorCode, $"The type \"{rowType}\" can't be converted to the ClickHouse type \"{ComplexTypeName}\". See the inner exception for details.", ex); } }
private async ValueTask WriteTable(IReadOnlyList <object?> columns, int rowCount, bool async, CancellationToken cancellationToken) { if (columns == null) { throw new ArgumentNullException(nameof(columns)); } if (columns.Count != _columns.Count) { throw new ArgumentException("The number of columns for writing must be equal to the number of columns in the table.", nameof(columns)); } if (rowCount < 0) { throw new ArgumentOutOfRangeException(nameof(rowCount)); } if (rowCount == 0) { throw new ArgumentException("The number of rows must be grater than zero.", nameof(rowCount)); } if (IsClosed) { throw new ClickHouseException(ClickHouseErrorCodes.InvalidConnectionState, "The writer is closed."); } var writers = new List <IClickHouseColumnWriter>(_columns.Count); for (int i = 0; i < _columns.Count; i++) { var column = columns[i]; var columnInfo = _columns[i]; if (column == null) { if (!columnInfo.TypeInfo.TypeName.StartsWith("Nullable")) { throw new ClickHouseException(ClickHouseErrorCodes.ColumnMismatch, $"The column \"{columnInfo.Name}\" at the position {i} doesn't support nulls."); } var constColumn = TypeDispatcher.Dispatch(columnInfo.TypeInfo.GetFieldType(), new NullColumnWriterDispatcher(columnInfo, _columnSettings?[i], rowCount)); writers.Add(constColumn); continue; } var columnType = column.GetType(); bool isEnumerable = false; Type?enumerable = null, asyncEnumerable = null, readOnlyList = null, list = null; foreach (var ifs in columnType.GetInterfaces()) { if (ifs == typeof(IEnumerable)) { isEnumerable = true; } else if (ifs.IsGenericType) { var ifsDefinition = ifs.GetGenericTypeDefinition(); if (ifsDefinition == typeof(IEnumerable <>)) { enumerable ??= ifs; } else if (ifsDefinition == typeof(IAsyncEnumerable <>)) { asyncEnumerable ??= ifs; } else if (ifsDefinition == typeof(IReadOnlyList <>)) { readOnlyList ??= ifs; } else if (ifsDefinition == typeof(IList <>)) { list ??= ifs; } } } Type dispatchedElementType; if (readOnlyList != null) { dispatchedElementType = readOnlyList.GetGenericArguments()[0]; } else if (list != null) { dispatchedElementType = list.GetGenericArguments()[0]; } else { if (asyncEnumerable != null) { if (async) { var genericArg = asyncEnumerable.GetGenericArguments()[0]; var asyncDispatcher = new AsyncColumnWriterDispatcher(column, columnInfo, _columnSettings?[i], rowCount, i, cancellationToken); var asyncColumn = await TypeDispatcher.Dispatch(genericArg, asyncDispatcher); writers.Add(asyncColumn); continue; } if (!isEnumerable && enumerable == null) { throw new ClickHouseException( ClickHouseErrorCodes.ColumnMismatch, $"The column \"{columnInfo.Name}\" at the position {i} implements interface \"{asyncEnumerable}\". Call async method \"{nameof(WriteTableAsync)}\"."); } } if (enumerable != null) { dispatchedElementType = enumerable.GetGenericArguments()[0]; } else if (isEnumerable) { dispatchedElementType = columnInfo.TypeInfo.GetFieldType(); } else { throw new ClickHouseException(ClickHouseErrorCodes.ColumnMismatch, $"The column \"{columnInfo.Name}\" at the position {i} is not a collection."); } } var dispatcher = new ColumnWriterDispatcher(column, columnInfo, _columnSettings?[i], rowCount, i); var columnWriter = TypeDispatcher.Dispatch(dispatchedElementType, dispatcher); writers.Add(columnWriter); } var table = new ClickHouseTableWriter(string.Empty, rowCount, writers); await SendTable(table, async, cancellationToken); }