Repository navigation
Type cursor.description columns from the returned values - #86
aminghadersohi wants to merge 2 commits into
Conversation
An explicit SELECT column list was described as STRING for every column, whatever the attributes held, and a SELECT evaluated by the superset connector's query DB had no type at all. Tools that build datasets from cursor.description (e.g. a Superset virtual dataset) therefore saw no numeric or temporal column. Each column is now typed from every non-NULL value the statement returned: numbers NUMBER, booleans BOOL, ISO-8601 date/timestamp strings (how DynamoDB stores dates) DATE/DATETIME; mixed values stay STRING. Columns with a type conversion function keep that function's type, and a column with no non-NULL value keeps its previous type.
|
@aminghadersohi Thank you for creating this PR. Actually, I did consider adding a feature to return the actual data type. The reason I didn’t implement it is that DynamoDB, as a NoSQL database, does not enforce a fixed data type for each column (or field). Determining the data type implicitly could require scanning the entire dataset for every query, which could introduce performance concerns. That’s why I added the data type annotation function, which allows users to explicitly specify the expected data type when needed. |
|
Thanks for the context — and agreed, inferring types by scanning a table up front would be a real problem for a NoSQL store like this. This isn't doing that: The type-annotation function stays authoritative: for a column using If you'd rather this be opt-in instead of the new default, I'm happy to gate it behind a cursor/connect-string flag — let me know and I'll add it. |
|
@aminghadersohi A flag in the connection string would be a great idea. It would allow users to decide whether they want to enable data type conversion by default. Thank you! |
Problem
cursor.descriptiondoes not describe what a SELECT returns:STRING, whatever the attributes hold.SELECT id, amount FROM tdescribes two numbers asSTRING.None).DATE/DATETIMEunless the query wraps them inDATETIME(...).Tools that build a dataset from
cursor.descriptionsee no numeric or temporal column. For example, a Superset virtual dataset overSELECT id, amount, ts, label FROM tgets fourSTRINGcolumns, so it cannot use SUM metrics or time grains.Fix
The executor records the type of every non-NULL value it returns, per column. The description uses that type:
NUMBERBOOLDATETor space separator, optional fraction andZ/±HH:MM) →DATETIME; a mix of dates and timestamps is alsoDATETIMESTRINGA column with a type conversion function (
NUMBER(x),DATETIME(x)) keeps that function's type. A column with no non-NULL value keeps its previous type. Rows produced by the superset connector's query DB are typed the same way. The query DB's own column types are not changed.Tests
tests/test_value_types.pycovers the type merge rules: 15 tests, no database needed.test_reserved_word:size[0]returns 100 and 500 and is now described asNUMBER. This test previously asserted the oldSTRING.test_function_in_columns: a plain column list over number, date, timestamp and text attributes.test_execute_nested_select: the superset connector's query-DB result.-sharedDb -inMemory), Python 3.11.15, SQLAlchemy 2.0.52:main: 156 passed, 1 skipped.main's code: 3 failed, and the new unit module cannot import.black --checkpasses.