From 044198778eaeb7e9fd4f12eeb77e20d080c958db Mon Sep 17 00:00:00 2001 From: Don McCurdy Date: Mon, 7 Oct 2024 16:56:24 -0400 Subject: [PATCH] fix(widgets): Prevent case change in table column names --- examples/components/widgets/table-widget.ts | 15 ++++++- src/sources/widget-base-source.ts | 5 ++- test/sources/widget-base-source.test.ts | 47 +++++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/examples/components/widgets/table-widget.ts b/examples/components/widgets/table-widget.ts index 1e180b1..f400101 100644 --- a/examples/components/widgets/table-widget.ts +++ b/examples/components/widgets/table-widget.ts @@ -67,7 +67,7 @@ export class TableWidget extends BaseWidget { return widgetSource.getTable({ columns, ...(sortBy && {sortBy, sortDirection}), - rowsPerPage: limit, + limit, spatialFilter: this.getSpatialFilterOrViewState(), }); }, @@ -132,6 +132,17 @@ function renderTableBody(response: TableResponse) { function renderTableRow(row: unknown[]) { return html` - ${map(row, (value) => html`${value}`)} + ${map(row, renderTableCell)} `; } + +const _numberFormatter = new Intl.NumberFormat(); +function renderTableCell(value: unknown) { + let formattedValue: string; + if (typeof value === 'number') { + return _numberFormatter.format(value); + } else { + formattedValue = String(value); + } + return html`${formattedValue}`; +} diff --git a/src/sources/widget-base-source.ts b/src/sources/widget-base-source.ts index 25b8bf9..0b3d787 100644 --- a/src/sources/widget-base-source.ts +++ b/src/sources/widget-base-source.ts @@ -258,8 +258,9 @@ export abstract class WidgetBaseSource { }, opts: {abortController}, }).then((res: TableModelResponse) => ({ - rows: normalizeObjectKeys(res.rows), - totalCount: res.metadata.total, + // Avoid `normalizeObjectKeys()`, which changes column names. + rows: res.rows ?? (res as any).ROWS, + totalCount: res.metadata?.total ?? (res as any).METADATA?.TOTAL, })); } diff --git a/test/sources/widget-base-source.test.ts b/test/sources/widget-base-source.test.ts index d7ffc6f..92ddfe8 100644 --- a/test/sources/widget-base-source.test.ts +++ b/test/sources/widget-base-source.test.ts @@ -346,6 +346,53 @@ test('getTable', async () => { }); }); +test('getTable - snowflake', async () => { + const widgetSource = new WidgetTestSource({ + accessToken: '', + connectionName: 'carto_dw', + }); + + const expectedRows = [ + {name: 'Veggie Mart', rEVenUe: 1200}, + {name: 'EZ Drive Thru', rEVenUe: 400}, + {name: "Buddy's Convenience", rEVenUe: 800}, + ]; + + // NOTICE: Snowflake returns uppercase keys. + const mockFetch = vi + .fn() + .mockResolvedValueOnce( + createMockResponse({ROWS: expectedRows, METADATA: {TOTAL: 3}}) + ); + vi.stubGlobal('fetch', mockFetch); + + const actualTable = await widgetSource.getTable({ + columns: ['name', 'revenue'], + limit: 20, + offset: 10, + }); + + expect(mockFetch).toHaveBeenCalledOnce(); + expect(actualTable).toEqual({ + rows: expectedRows, + totalCount: 3, + }); + + const params = new URL(mockFetch.mock.lastCall[0]).searchParams.entries(); + expect(Object.fromEntries(params)).toMatchObject({ + type: 'test', + source: 'test-data', + params: JSON.stringify({ + column: ['name', 'revenue'], + limit: 20, + offset: 10, + }), + queryParameters: '', + filters: JSON.stringify({}), + filtersLogicalOperator: 'and', + }); +}); + /****************************************************************************** * getScatter */