Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,40 @@ describe("Columns types parser - Tuple", () => {
});
});

it("should parse Tuple with named elements", async () => {
const args: TestArgs[] = [
{
sourceType: "Tuple(s String, i Int64)",
expected: {
type: "Tuple",
elements: [
{ type: "Simple", columnType: "String", sourceType: "String" },
{ type: "Simple", columnType: "Int64", sourceType: "Int64" },
],
sourceType: "Tuple(s String, i Int64)",
},
},
{
sourceType: 'Tuple(`display name` String, "item count" UInt64)',
expected: {
type: "Tuple",
elements: [
{ type: "Simple", columnType: "String", sourceType: "String" },
{ type: "Simple", columnType: "UInt64", sourceType: "UInt64" },
],
sourceType: 'Tuple(`display name` String, "item count" UInt64)',
},
},
];
args.forEach(({ expected, sourceType }) => {
const result = parseTupleType({ columnType: sourceType, sourceType });
expect(
result,
`Expected ${sourceType} to have ${joinElements(expected)} elements`,
).toEqual(expected);
});
});

it("should parse Tuple with Decimals", async () => {
const args: TestArgs[] = [
{
Expand Down
29 changes: 28 additions & 1 deletion packages/client-common/src/parse/column_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ export function parseTupleType({
}
columnType = columnType.slice(TuplePrefix.length, -1);
const elements = getElementsTypes({ columnType, sourceType }, 1).map((type) =>
parseColumnType(type),
parseTupleElementType(type),
);
Comment thread
sidsri14 marked this conversation as resolved.
return {
type: "Tuple",
Expand All @@ -551,6 +551,30 @@ export function parseTupleType({
};
}

function parseTupleElementType(elementSourceType: string): ParsedColumnType {
try {
return parseColumnType(elementSourceType);
} catch (originalError) {
if (!(originalError instanceof ColumnTypeParseError)) {
throw originalError;
}
const namedElementType =
NamedTupleElementPattern.exec(elementSourceType)?.[1];
if (namedElementType === undefined) {
throw originalError;
}

try {
return parseColumnType(namedElementType);
} catch (namedElementError) {
if (!(namedElementError instanceof ColumnTypeParseError)) {
throw namedElementError;
}
throw originalError;
}
}
}

export function parseArrayType({
columnType,
sourceType,
Expand Down Expand Up @@ -795,6 +819,9 @@ const DateTimePrefix = "DateTime" as const;
const DateTimeWithTimezonePrefix = "DateTime(" as const;
const DateTime64Prefix = "DateTime64(" as const;
const FixedStringPrefix = "FixedString(" as const;
// Tuple element names may be bare or quoted with backticks/double quotes.
const NamedTupleElementPattern =
/^(?:`(?:\\.|``|[^`])*`|"(?:\\.|""|[^"])*"|\S+)\s+(.+)$/;

const SingleQuoteASCII = 39 as const;
const LeftParenASCII = 40 as const;
Expand Down
2 changes: 2 additions & 0 deletions packages/client-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
## Bug fixes

- Fixed `Array(Date)` / `Array(Date32)` query-parameter binding (and other temporal element types nested in arrays, tuples, and maps). A JS `Date` inside a container was serialized as a bare Unix timestamp (e.g. `[1683244800]`), which the server's `Array(Date)` element parser rejects (`CANNOT_PARSE_INPUT_ASSERTION_FAILED`). Container-nested `Date` values are now emitted as a quoted UTC date string (e.g. `['2023-05-05']`), the one encoding every temporal element type accepts. Note: a `Date` used inside `Array(DateTime)` / `Array(DateTime64)` is now bound at day precision (the time-of-day is dropped), since date-only is the only form `Array(Date)` accepts; scalar `Date` / `DateTime` binding is unchanged. ([#947])
- Fixed the deprecated `parseColumnType` function to parse named Tuple elements (for example, `Tuple(name String, count UInt64)`) instead of throwing `Unsupported column type`. Element names remain omitted from the legacy `ParsedColumnTuple` output; use `@clickhouse/datatype-parser` when names are needed. ([#964])

[#947]: https://github.com/ClickHouse/clickhouse-js/pull/947
[#964]: https://github.com/ClickHouse/clickhouse-js/pull/964
Comment thread
sidsri14 marked this conversation as resolved.

# 1.23.1

Expand Down
2 changes: 2 additions & 0 deletions packages/client-web/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
## Bug fixes

- Fixed `Array(Date)` / `Array(Date32)` query-parameter binding (and other temporal element types nested in arrays, tuples, and maps). A JS `Date` inside a container was serialized as a bare Unix timestamp (e.g. `[1683244800]`), which the server's `Array(Date)` element parser rejects (`CANNOT_PARSE_INPUT_ASSERTION_FAILED`). Container-nested `Date` values are now emitted as a quoted UTC date string (e.g. `['2023-05-05']`), the one encoding every temporal element type accepts. Note: a `Date` used inside `Array(DateTime)` / `Array(DateTime64)` is now bound at day precision (the time-of-day is dropped), since date-only is the only form `Array(Date)` accepts; scalar `Date` / `DateTime` binding is unchanged. ([#947])
- Fixed the deprecated `parseColumnType` function to parse named Tuple elements (for example, `Tuple(name String, count UInt64)`) instead of throwing `Unsupported column type`. Element names remain omitted from the legacy `ParsedColumnTuple` output; use `@clickhouse/datatype-parser` when names are needed. ([#964])

[#947]: https://github.com/ClickHouse/clickhouse-js/pull/947
[#964]: https://github.com/ClickHouse/clickhouse-js/pull/964
Comment thread
sidsri14 marked this conversation as resolved.

# 1.23.1

Expand Down