Repository navigation
Conversation
…oris The connectors hand-rolled nested-type parsing in _get_column for their custom get_columns_and_constraints override: a greedy regex child extraction plus a naive split on ','/':' silently lost struct fields (StarRocks) and crashed on the missing field separator for Doris — columns ingested without children. Route STRUCT/ARRAY/MAP type strings through the shared bracket-aware ColumnTypeParser via new shared helpers (parse_complex_column_type, column_from_parsed) in column_helpers.py, normalizing the space separated (StarRocks) and colon separated (Doris) field-name forms first, with a soft-fail (warn + ingest without children) on unparsable types. - column_helpers.py: shared parse_complex_column_type / column_from_parsed - starrocks: children now parsed for structs and array<struct> elements - doris: same; malformed types no longer crash (caught, skipped with warning) - tests: 24 unit tests incl. 2-level nesting, decimal(10,2) inside a struct field, array<struct>, both separator forms, malformed input - basedpyright baseline: down-shift only, no entries added
❌ PR checklist incompleteThis PR cannot be merged until the following are addressed on its linked issue:
The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically. Maintainers can bypass this check by adding the |
Code Review ✅ Approved🟡 Medium risk · Parsing nested StarRocks and Doris types changes catalog column metadata; incorrect parsing could misrepresent child fields and affect downstream nested-column queries. Adds recursive child-column parsing for STRUCT, ARRAY<STRUCT>, and MAP types in the StarRocks and Doris connectors, so nested fields are ingested into VerificationRules No rules evaluated Functional validation Not enabledAuto-approval Not enabledFor more verification details, comment OptionsDisplay: compact → Showing compact verification results. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source |
|



Description
The StarRocks and Doris connectors ingest nested columns (
STRUCT,ARRAY<STRUCT>,MAP) without their child fields:Show Full Columnsreturns the full type string (struct<latitude double, ...>), but the hand-rolled child parser in_get_column— a greedy regex child extraction plus a naivesplit(",")/split(":")— silently loses every struct field (StarRocks) and crashes on the missing field separator (Doris: the caught exception skips the column entirely). The ingestedColumn.childrenends up empty, which blocks the nested-column DQ representation accepted by the backend since fix(dq): allow attaching test cases to nested columns #36385 (ADR:2026-10-27-nested-column-dq-tests-address-nested-paths).Related: #36278 (epic), #36385 (backend slice — the API-side nested path resolution this unblocks end-to-end).
What changed
column_helpers.py(new shared home, alongsidetruncate_column_name):parse_complex_column_type(type_str)— parses STRUCT/ARRAY/MAP type strings through the shared, bracket-awareColumnTypeParser._parse_datatype_string(the same code path Trino/Databricks route through), returning the OM column dict with recursivechildren; soft-fails (warns, ingests the column without children) on unparsable types.column_from_parsed(ordinal, parsed)— maps a parsed child dict onto theColumnentity; deeper levels validate recursively._colonize_field_*helpers normalize field-name separators — StarRocks printsname type(space), Doris printsname:type(colon), and one form can appear nested inside the other; the split prefers whichever boundary is closer. Parameters likedecimal(10, 2)are preserved via the bracket-aware split.starrocks/metadata.py—_get_columnnow parses children forSTRUCTand forarray<struct>element fields; the customget_columns_and_constraintsoverride maps them throughcolumn_from_parsed.doris/metadata.py— same shape; the previous naivesplit(":")could alsoIndexError/skip columns.dataType/dataTypeDisplayare unchanged for both connectors (display keeps the raw source string verbatim).ingestion/.basedpyright/baseline.json— down-shift only (entries removed in the two fixed files; no new baseline entries added).No schema/migration change (
Column.childrenalready exists; BigQuery/Trino/Databricks already populate it).How Has This Been Tested?
test_starrocks_metadata.py,test_doris_metadata.py): 2-level nesting (struct field of struct),array<struct>children,map<...>,decimal(10,2)inside a struct field (precision/scale preserved), both separator forms, malformed type soft-fail, primitive types → no children, and children →Columnrecursion.ingestion/tests/unit/source/database/starrocks/+.../doris/suites (35 passed) andingestion/tests/unit/topology/database/test_starrocks.py+test_doris.py(39 passed) — all green.SHOW FULL COLUMNStype strings from a table withlocation STRUCT<...address STRUCT<...>>andvehicles ARRAY<STRUCT<...>>parse to 5 and 4 children respectively, with grandchildren on the nested struct.ruff format/ruff checkclean on all touched files; basedpyright 0 errors on the touchedsrcfiles; pre-commit hooks pass.Checklist
.gitignore: ignoreCLAUDE.local.md(local-only agent instructions file, prevents accidental commits)