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
16 changes: 12 additions & 4 deletions superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { mountExploreUrl } from 'src/explore/exploreUtils';
import { postFormData } from 'src/explore/exploreUtils/formData';
import { URL_PARAMS } from 'src/constants';
import { isEmpty } from 'lodash';
import { clearDatasetCache } from 'src/utils/datasetCache';

interface QueryDatabase {
id?: number;
Expand Down Expand Up @@ -169,6 +170,10 @@ const updateDataset = async (
headers,
body,
});

// Clear the dataset cache after updating to ensure fresh data
clearDatasetCache(datasetId);

return data.json.result;
};

Expand Down Expand Up @@ -335,15 +340,18 @@ export const SaveDatasetModal = ({
datasourceName: datasetName,
}),
)
.then((data: { id: number }) =>
postFormData(data.id, 'table', {
.then((data: { id: number }) => {
// Clear cache for the newly created dataset
clearDatasetCache(data.id);

return postFormData(data.id, 'table', {
...formDataWithDefaults,
datasource: `${data.id}__table`,
...(defaultVizType === VizType.Table && {
all_columns: selectedColumns.map(column => column.column_name),
}),
}),
)
});
})
.then((key: string) => {
setLoading(false);
const url = mountExploreUrl(null, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
} from '@superset-ui/core/components';
import withToasts from 'src/components/MessageToasts/withToasts';
import { ErrorMessageWithStackTrace } from 'src/components';
import { clearDatasetCache } from 'src/utils/datasetCache';
import type { DatasetObject } from 'src/features/datasets/types';
import type { DatasourceModalProps } from '../types';

Expand Down Expand Up @@ -203,6 +204,11 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
const { json } = await SupersetClient.get({
endpoint: `/api/v1/dataset/${currentDatasource?.id}`,
});

// Clear the dataset cache to ensure fresh data when fetching columns for filters
// This ensures that changes to the dataset are immediately reflected
clearDatasetCache(currentDatasource.id);

This comment was marked as resolved.


addSuccessToast(t('The dataset has been saved'));
// eslint-disable-next-line no-param-reassign
json.result.type = 'table';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import {
resetDatabaseState,
} from 'src/database/actions';
import Mousetrap from 'mousetrap';
import { clearDatasetCache } from 'src/utils/datasetCache';
import { DatabaseSelector } from '../../../DatabaseSelector';
import CollectionTable from '../CollectionTable';
import Fieldset from '../Fieldset';
Expand Down Expand Up @@ -837,6 +838,11 @@ class DatasourceEditor extends PureComponent {
col => !col.expression, // remove calculated columns
),
});

// Clear the dataset cache to ensure fresh data when fetching columns for filters
// This ensures that newly synced columns are immediately available in filter creation
clearDatasetCache(datasource.id);

this.props.addSuccessToast(t('Metadata has been synced'));
this.setState({ metadataLoading: false });
} catch (error) {
Expand Down
70 changes: 70 additions & 0 deletions superset-frontend/src/utils/datasetCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { supersetGetCache } from './cachedSupersetGet';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would keep all this stuff within cachedSupersetGet to keep things contained. I think the goal is ultimately to deprecate cachedSupersetGet. When debugging around this before there was some clear nonsense around this. Plus the dataset is already in redux, and there are subtle variations around the schema/endpoint to try and work around datasets with lots of columns.

Client-side cache fighting with redux is super confusing.


/**
* Clear all cached API responses for a specific dataset.
* This ensures that any subsequent API calls will fetch fresh data from the server.
*
* @param datasetId - The ID of the dataset to clear from cache
*/
export function clearDatasetCache(datasetId: number | string): void {
if (!datasetId) return;

This comment was marked as resolved.


const keysToDelete: string[] = [];

// Find all cache keys related to this dataset
supersetGetCache.forEach((_value, key) => {
// Match any endpoint that references this dataset ID
// This includes:
// - /api/v1/dataset/{id}
// - /api/v1/dataset/{id}?q=...
// - /api/v1/dataset/{id}/related_objects
// - etc.
if (
key.includes(`/api/v1/dataset/${datasetId}`) ||
key.includes(`/api/v1/dataset/${datasetId}/`) ||
key.includes(`/api/v1/dataset/${datasetId}?`)
) {
Comment on lines +41 to +45

This comment was marked as resolved.

keysToDelete.push(key);
}
});
Comment on lines +28 to +48

This comment was marked as resolved.


// Delete all matching keys
keysToDelete.forEach(key => {
supersetGetCache.delete(key);
});
}

/**
* Clear the entire dataset cache.
* Use this when you need to ensure all dataset data is refreshed.
*/
export function clearAllDatasetCache(): void {
const keysToDelete: string[] = [];

supersetGetCache.forEach((_value, key) => {
if (key.includes('/api/v1/dataset/')) {
keysToDelete.push(key);
}
});

keysToDelete.forEach(key => supersetGetCache.delete(key));
}
Loading