Skip to content

Commit 10c84a0

Browse files
Dbid unify (#316)
* add database to taskui context * do not compute dbid in appstate calculation * pass db id to all downstream checks * bugfix useappstore * Speed up metabase state updates * add db id in one place * Remove unused functions * Fix imports --------- Co-authored-by: Sreejith <1743700+ppsreejith@users.noreply.github.com>
1 parent 600c75e commit 10c84a0

File tree

15 files changed

+199
-532
lines changed

15 files changed

+199
-532
lines changed

apps/src/metabase/appState.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,13 @@ export class MetabaseState extends DefaultAppState<MetabaseAppState> {
128128
actionController = new MetabaseController(this);
129129

130130
private async triggerMetabaseStateUpdate(url: string, elements: DOMQueryMapResponse) {
131-
const queryType = await RPCs.getMetabaseState('qb.card.dataset_query.type') as string;
132-
const state = this.useStore().getState();
131+
const [queryType, dbId, allDBs] = await Promise.all([
132+
RPCs.getMetabaseState('qb.card.dataset_query.type') as Promise<string>,
133+
getSelectedDbId(),
134+
RPCs.getMetabaseState('entities.databases')
135+
]);
136+
133137
const getState = this.useStore().getState
134-
const dbId = await getSelectedDbId();
135-
const allDBs = await RPCs.getMetabaseState('entities.databases') as object;
136138
const minifiedDBs = Object.values(allDBs || {}).map((db: any) => ({ id: db.id, name: db.name }))
137139

138140
let toolEnabledNew = shouldEnable(elements, url);
@@ -460,7 +462,8 @@ Here's what I need modified:
460462
}
461463

462464
public async getState(): Promise<MetabaseAppState> {
463-
return await convertDOMtoState();
465+
const currentDBId = this.useStore().getState().toolContext?.dbId || undefined;
466+
return await convertDOMtoState(currentDBId);
464467
}
465468

466469
public async getPlannerConfig() {
@@ -490,7 +493,7 @@ Here's what I need modified:
490493
}))
491494
const isCancelled = () => taskStatus.status === 'cancelled';
492495
const [relevantTables, dbInfo] = await Promise.all([
493-
handlePromise(abortable(getRelevantTablesForSelectedDb(), isCancelled), "Failed to get relevant tables", []),
496+
handlePromise(abortable(getRelevantTablesForSelectedDb(dbId), isCancelled), "Failed to get relevant tables", []),
494497
handlePromise(abortable(getDatabaseTablesAndModelsWithoutFields(dbId), isCancelled), "Failed to get database info", DB_INFO_DEFAULT)
495498
])
496499
state.getState().update((oldState) => ({
@@ -505,7 +508,7 @@ Here's what I need modified:
505508
// Perf caching
506509
if (!isCancelled() && dbId !== oldDbId) {
507510
console.log('Running perf caching')
508-
processAllMetadata()
511+
processAllMetadata(false, dbId)
509512
getDatabaseInfo(dbId)
510513
}
511514
})

apps/src/metabase/helpers/DOMToState.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export type MetabaseAppState = MetabaseAppStateSQLEditor | MetabaseAppStateDashb
104104

105105
// no need to fetch fields since we don't want that in limited entities
106106

107-
export async function convertDOMtoStateSQLQueryV2(pageType: MetabasePageType) : Promise<MetabaseAppStateSQLEditorV2> {
107+
export async function convertDOMtoStateSQLQueryV2(pageType: MetabasePageType, currentDBId: number) : Promise<MetabaseAppStateSQLEditorV2> {
108108
const [metabaseUrl, currentCardRaw, outputMarkdown, parameterValues] = await Promise.all([
109109
RPCs.queryURL(),
110110
getCurrentCard() as Promise<Card>,
@@ -115,8 +115,8 @@ export async function convertDOMtoStateSQLQueryV2(pageType: MetabasePageType) :
115115
const metabaseOrigin = new URL(metabaseUrl).origin;
116116
const isEmbedded = getParsedIframeInfo().isEmbedded
117117
const sqlQuery = get(currentCard, 'dataset_query.native.query', '') || ''
118-
const limitedEntities = await getLimitedEntities(sqlQuery);
119-
const dbId = await getSelectedDbId();
118+
const dbId = currentDBId
119+
const limitedEntities = await getLimitedEntities(sqlQuery, currentDBId);
120120
const selectedDatabaseInfo = dbId ? await getDatabaseInfo(dbId) : undefined;
121121
const sqlErrorMessage = await getSqlErrorMessage();
122122
const appStateType = pageType === 'sql' ? MetabaseAppStateType.SQLEditor : MetabaseAppStateType.RandomPage;
@@ -153,27 +153,27 @@ export async function convertDOMtoStateSQLQueryV2(pageType: MetabasePageType) :
153153
}
154154
}
155155

156-
export async function convertDOMtoStateSQLQuery() {
156+
export async function convertDOMtoStateSQLQuery(currentDBId: number) {
157157
// CAUTION: This one does not update when changed via ui for some reason
158158
// const dbId = _.get(hashMetadata, 'dataset_query.database');
159159
const fullUrl = await RPCs.queryURL();
160160
const url = new URL(fullUrl).origin;
161161
const availableDatabases = (await getDatabases())?.data?.map(({ name }) => name);
162-
const dbId = await getSelectedDbId();
162+
const dbId = currentDBId;
163163
const selectedDatabaseInfo = dbId ? await getDatabaseInfo(dbId) : undefined;
164164
const defaultSchema = selectedDatabaseInfo?.default_schema;
165-
let sqlQuery = await getCurrentQuery()
166-
const appSettings = RPCs.getAppSettings()
167-
const cache = RPCs.getCache()
168-
const sqlTables = getTablesFromSqlRegex(sqlQuery)
165+
let sqlQuery = await getCurrentQuery();
166+
const appSettings = RPCs.getAppSettings();
167+
const cache = RPCs.getCache();
168+
const sqlTables = getTablesFromSqlRegex(sqlQuery);
169169
if (defaultSchema) {
170170
sqlTables.forEach((table) => {
171171
if (table.schema === undefined || table.schema === '') {
172172
table.schema = defaultSchema
173173
}
174174
})
175175
}
176-
let relevantTablesWithFields = await getTablesWithFields(appSettings.tableDiff, appSettings.drMode, false, sqlTables, [])
176+
let relevantTablesWithFields = await getTablesWithFields(appSettings.tableDiff, appSettings.drMode, false, sqlTables, [], dbId);
177177
// add defaultSchema back to relevantTablesWithFields. kind of hacky but whatever
178178
relevantTablesWithFields = relevantTablesWithFields.map(table => {
179179
if (table.schema === undefined || table.schema === '') {
@@ -241,13 +241,13 @@ export async function convertDOMtoStateSQLQuery() {
241241
return metabaseAppStateSQLEditor;
242242
}
243243

244-
export async function convertDOMtoStateMBQLQuery() {
245-
return await getMBQLAppState() as MetabaseAppStateMBQLEditor;
244+
export async function convertDOMtoStateMBQLQuery(currentDBId: number): Promise<MetabaseAppStateMBQLEditor> {
245+
return await getMBQLAppState(currentDBId) as MetabaseAppStateMBQLEditor;
246246
}
247247

248248
// check if on dashboard page
249-
export async function convertDOMtoStateDashboard(): Promise<MetabaseAppStateDashboard> {
250-
const dashboardInfo = await getDashboardAppState();
249+
export async function convertDOMtoStateDashboard(currentDBId: number): Promise<MetabaseAppStateDashboard> {
250+
const dashboardInfo = await getDashboardAppState(currentDBId);
251251
return dashboardInfo as MetabaseAppStateDashboard;
252252
};
253253

@@ -272,21 +272,21 @@ export async function semanticQueryState() {
272272
return metabaseSemanticQueryAppState;
273273
}
274274

275-
export async function convertDOMtoState() {
275+
export async function convertDOMtoState(currentDBId: number) {
276276
const url = await queryURL();
277277
const qlType = await getQLType();
278278
const metabasePageType = determineMetabasePageType({}, url, qlType);
279279
if (metabasePageType === 'dashboard') {
280-
return await convertDOMtoStateDashboard();
280+
return await convertDOMtoStateDashboard(currentDBId);
281281
}
282282
if (metabasePageType === 'mbql') {
283-
return await convertDOMtoStateMBQLQuery();
283+
return await convertDOMtoStateMBQLQuery(currentDBId);
284284
}
285285
const appSettings = RPCs.getAppSettings()
286286
if (appSettings.useV2States && appSettings.analystMode) {
287-
return await convertDOMtoStateSQLQueryV2(metabasePageType);
287+
return await convertDOMtoStateSQLQueryV2(metabasePageType, currentDBId);
288288
}
289-
return await convertDOMtoStateSQLQuery();
289+
return await convertDOMtoStateSQLQuery(currentDBId);
290290
}
291291

292292
async function getSqlVariables() {

apps/src/metabase/helpers/dashboard/appState.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { DashboardInfo, DashboardMetabaseState } from './types';
22
import _, { forEach, reduce, template, values } from 'lodash';
33
import { MetabaseAppStateDashboard} from '../DOMToState';
4-
import { getTablesWithFields } from '../getDatabaseSchema';
54
import { getAllRelevantModelsForSelectedDb, getDatabaseInfo, getFieldResolvedName } from '../metabaseAPIHelpers';
65
import { getDashboardState, getSelectedDbId } from '../metabaseStateAPI';
76
import { getParsedIframeInfo, RPCs } from 'web';
@@ -332,14 +331,11 @@ async function substituteParameters(
332331
return sql;
333332
};
334333

335-
export async function getDashboardAppState(): Promise<MetabaseAppStateDashboard | null> {
334+
export async function getDashboardAppState(currentDBId: number): Promise<MetabaseAppStateDashboard | null> {
336335
const fullUrl = await RPCs.queryURL();
337336
const url = new URL(fullUrl).origin;
338-
const appSettings = RPCs.getAppSettings();
339-
const selectedCatalog = get(find(appSettings.availableCatalogs, { name: appSettings.selectedCatalog }), 'content')
340-
const dbId = await getSelectedDbId();
337+
const dbId = currentDBId
341338
const selectedDatabaseInfo = dbId ? await getDatabaseInfo(dbId) : undefined
342-
const defaultSchema = selectedDatabaseInfo?.default_schema;
343339
const dashboardMetabaseState: DashboardMetabaseState = await getDashboardState() as DashboardMetabaseState;
344340
if (!dashboardMetabaseState || !dashboardMetabaseState.dashboards || !dashboardMetabaseState.dashboardId) {
345341
console.warn('Could not get dashboard info');
@@ -364,12 +360,14 @@ export async function getDashboardAppState(): Promise<MetabaseAppStateDashboard
364360
const limitedEntitiesSQL = await getLimitedEntitiesFromQueries(
365361
filteredCards.flatMap(card =>
366362
card?.dataset_query?.native?.query ? [card.dataset_query.native.query] : []
367-
)
363+
),
364+
dbId
368365
);
369366
const limitedEntitiesMBQL = await getLimitedEntitiesFromMBQLQueries(
370367
filteredCards.flatMap(card =>
371368
card?.dataset_query?.query ? [card.dataset_query.query] : []
372-
)
369+
),
370+
dbId
373371
);
374372
const limitedEntities = [...limitedEntitiesSQL, ...limitedEntitiesMBQL];
375373
// remove duplicates based on id and type

apps/src/metabase/helpers/getDatabaseSchema.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { FormattedTable } from './types';
22
import { getTablesFromSqlRegex, TableAndSchema } from './parseSql';
33
import _ from 'lodash';
4-
import { getSelectedDbId } from './metabaseStateAPI';
54
import { getUserTables, searchUserQueries, getDatabaseTablesAndModelsWithoutFields } from './metabaseAPIHelpers';
65
import { applyTableDiffs, handlePromise } from '../../common/utils';
76
import { TableDiff } from 'web/types';
@@ -102,8 +101,8 @@ export const searchTables = async (userId: number, dbId: number, query: string):
102101
return dedupedTables
103102
}
104103

105-
export const getTablesWithFields = async (tableDiff?: TableDiff, drMode = false, isCatalogSelected: boolean = false, sqlTables: TableAndSchema[] = [], mbqlTableIds: number[] = []) => {
106-
const dbId = await getSelectedDbId();
104+
export const getTablesWithFields = async (tableDiff?: TableDiff, drMode = false, isCatalogSelected: boolean = false, sqlTables: TableAndSchema[] = [], mbqlTableIds: number[] = [], currentDBId?: number) => {
105+
const dbId = currentDBId;
107106
if (!dbId) {
108107
console.warn("[minusx] No database selected when getting tables with fields");
109108
return [];
@@ -128,8 +127,8 @@ export const getTablesWithFields = async (tableDiff?: TableDiff, drMode = false,
128127

129128

130129

131-
export const getRelevantTablesForSelectedDb = async (): Promise<FormattedTable[]> => {
132-
const dbId = await getSelectedDbId();
130+
export const getRelevantTablesForSelectedDb = async (currentDBId?: number): Promise<FormattedTable[]> => {
131+
const dbId = currentDBId;
133132
if (!dbId) {
134133
console.warn("[minusx] No database selected when getting relevant tables");
135134
return [];

apps/src/metabase/helpers/mbql/appState.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import { getAndFormatOutputTable } from '../operations';
1111
import { MetabaseAppStateType } from '../analystModeTypes';
1212

1313

14-
export async function getMBQLAppState(): Promise<MetabaseAppStateMBQLEditor | null> {
14+
export async function getMBQLAppState(currentDBId: number): Promise<MetabaseAppStateMBQLEditor | null> {
1515
const fullUrl = await RPCs.queryURL();
1616
const url = new URL(fullUrl).origin;
1717

1818
const appSettings = RPCs.getAppSettings();
1919
const selectedCatalog = get(find(appSettings.availableCatalogs, { name: appSettings.selectedCatalog }), 'content')
20-
const dbId = await getSelectedDbId();
20+
const dbId = currentDBId
2121
const selectedDatabaseInfo = dbId ? await getDatabaseInfo(dbId) : undefined
2222
const defaultSchema = selectedDatabaseInfo?.default_schema;
2323
const mbqlState = await getMBQLState();
@@ -32,7 +32,7 @@ export async function getMBQLAppState(): Promise<MetabaseAppStateMBQLEditor | nu
3232
const relevantModels = await getSelectedAndRelevantModels('', appSettings.selectedModels, allModels, sourceTableModelIds)
3333
const relevantModelsWithFields = await getModelsWithFields(relevantModels)
3434

35-
let relevantTablesWithFields = await getTablesWithFields(appSettings.tableDiff, appSettings.drMode, !!selectedCatalog, [], sourceTableModelIds)
35+
let relevantTablesWithFields = await getTablesWithFields(appSettings.tableDiff, appSettings.drMode, !!selectedCatalog, [], sourceTableModelIds, dbId);
3636
relevantTablesWithFields = relevantTablesWithFields.map(table => {
3737
if (table.schema === undefined || table.schema === '') {
3838
table.schema = defaultSchema || 'unknown'

apps/src/metabase/helpers/metabaseAPIHelpers.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -200,16 +200,16 @@ type ResultMetadataElm = {
200200
field_ref: [string, string, { "base-type": string }];
201201
};
202202

203-
export async function getAllCardsAndModels(forceRefresh = false) {
203+
export async function getAllCardsAndModels(forceRefresh = false, currentDBId: number) {
204204
const cards = await handlePromise(
205205
forceRefresh ? fetchCards.refresh({}) : fetchCards({}),
206206
"[minusx] Error getting all cards",
207207
[]
208208
);
209209

210210
// Get selected database ID
211-
const selectedDbId = await getSelectedDbId();
212-
211+
const selectedDbId = currentDBId;
212+
213213
console.log('[minusx] getAllCards - Total cards:', cards.length);
214214

215215
// Filter cards by database_id only
@@ -299,14 +299,9 @@ export async function getAllCardsAndModels(forceRefresh = false) {
299299
return { cards: processedCards, tables: relevantTables, modelFields: processedModelFields };
300300
}
301301

302-
export async function getAllCardsLegacy() {
303-
const result = await getAllCardsAndModels();
304-
return result.cards;
305-
}
306-
307-
export async function getAllFields() {
302+
export async function getAllFields(currentDBId: number) {
308303
// Get selected database ID
309-
const selectedDbId = await getSelectedDbId();
304+
const selectedDbId = currentDBId;
310305

311306
if (!selectedDbId) {
312307
console.log('[minusx] getAllFields - No database selected');
@@ -329,14 +324,14 @@ export async function getAllFields() {
329324
return limitedFields;
330325
}
331326

332-
export async function getAllFieldsFiltered(tableNames: string[]) {
327+
export async function getAllFieldsFiltered(tableNames: string[], currentDBId: number) {
333328
if (!tableNames || tableNames.length === 0) {
334329
console.log('[minusx] getAllFieldsFiltered - No table names provided, returning empty array');
335330
return [];
336331
}
337332

338333
// Get selected database ID
339-
const selectedDbId = await getSelectedDbId();
334+
const selectedDbId = currentDBId
340335

341336
if (!selectedDbId) {
342337
console.log('[minusx] getAllFieldsFiltered - No database selected');

apps/src/metabase/helpers/utils.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,23 @@ export function determineMetabasePageType(elements: DOMQueryMapResponse, url: st
5252
return 'unknown';
5353
}
5454

55-
export async function getLimitedEntitiesFromMBQLQueries(mbqlQueries: any): Promise<MetabaseTableOrModel[]> {
55+
export async function getLimitedEntitiesFromMBQLQueries(mbqlQueries: any, currentDBId: number): Promise<MetabaseTableOrModel[]> {
5656
const entities : MetabaseTableOrModel[] = [];
5757
for (const mbqlQuery of mbqlQueries) {
58-
const limitedEntities = await getLimitedMBQLEntities(mbqlQuery);
58+
const limitedEntities = await getLimitedMBQLEntities(mbqlQuery, currentDBId);
5959
entities.push(...limitedEntities);
6060
}
6161
// Remove duplicates based on id and type
6262
const uniqueEntities = Array.from(new Map(entities.map(entity => [entity.id, entity])).values());
6363
return uniqueEntities;
6464
}
6565

66-
async function getLimitedMBQLEntities(mbqlQuery: any): Promise<MetabaseTableOrModel[]> {
66+
async function getLimitedMBQLEntities(mbqlQuery: any, currentDBId: number): Promise<MetabaseTableOrModel[]> {
6767
const appSettings = RPCs.getAppSettings();
6868
if (!appSettings.analystMode || !appSettings.manuallyLimitContext) {
6969
return [];
7070
}
71-
const dbId = await getSelectedDbId();
71+
const dbId = currentDBId;
7272
const selectedDatabaseInfo = dbId ? await getDatabaseInfo(dbId) : undefined
7373
const defaultSchema = selectedDatabaseInfo?.default_schema;
7474
const selectedCatalogObj = find(appSettings.availableCatalogs, { name: appSettings.selectedCatalog });
@@ -80,7 +80,7 @@ async function getLimitedMBQLEntities(mbqlQuery: any): Promise<MetabaseTableOrMo
8080
const relevantModels = await getSelectedAndRelevantModels('', appSettings.selectedModels, allModels, sourceTableModelIds)
8181
const relevantModelsWithFields = await getModelsWithFields(relevantModels)
8282

83-
let relevantTablesWithFields = await getTablesWithFields(appSettings.tableDiff, appSettings.drMode, !!selectedCatalog, [], sourceTableModelIds)
83+
let relevantTablesWithFields = await getTablesWithFields(appSettings.tableDiff, appSettings.drMode, !!selectedCatalog, [], sourceTableModelIds, dbId)
8484
relevantTablesWithFields = relevantTablesWithFields.map(table => {
8585
if (table.schema === undefined || table.schema === '') {
8686
table.schema = defaultSchema || 'unknown'
@@ -97,26 +97,26 @@ async function getLimitedMBQLEntities(mbqlQuery: any): Promise<MetabaseTableOrMo
9797
}
9898

9999

100-
export async function getLimitedEntitiesFromQueries(sqlQueries: string[]): Promise<MetabaseTableOrModel[]> {
100+
export async function getLimitedEntitiesFromQueries(sqlQueries: string[], currentDBId: number): Promise<MetabaseTableOrModel[]> {
101101
const entities : MetabaseTableOrModel[] = [];
102102
for (const sqlQuery of sqlQueries) {
103-
const limitedEntities = await getLimitedEntities(sqlQuery);
103+
const limitedEntities = await getLimitedEntities(sqlQuery, currentDBId);
104104
entities.push(...limitedEntities);
105105
}
106106
// Remove duplicates based on id and type
107107
const uniqueEntities = Array.from(new Map(entities.map(entity => [entity.id, entity])).values());
108108
return uniqueEntities;
109109
}
110110

111-
export async function getLimitedEntities(sqlQuery: string): Promise<MetabaseTableOrModel[]> {
111+
export async function getLimitedEntities(sqlQuery: string, currentDBId: number): Promise<MetabaseTableOrModel[]> {
112112
const appSettings = RPCs.getAppSettings();
113113

114114
// Early return if conditions not met
115115
if (!appSettings.analystMode || !appSettings.manuallyLimitContext) {
116116
return [];
117117
}
118118

119-
const dbId = await getSelectedDbId();
119+
const dbId = currentDBId;
120120
const selectedDatabaseInfo = dbId ? await getDatabaseInfo(dbId) : undefined;
121121
const defaultSchema = selectedDatabaseInfo?.default_schema;
122122

@@ -133,7 +133,7 @@ export async function getLimitedEntities(sqlQuery: string): Promise<MetabaseTabl
133133
});
134134
}
135135

136-
let relevantTablesWithFields = await getTablesWithFields(appSettings.tableDiff, appSettings.drMode, !!selectedCatalog, sqlTables, []);
136+
let relevantTablesWithFields = await getTablesWithFields(appSettings.tableDiff, appSettings.drMode, !!selectedCatalog, sqlTables, [], dbId);
137137

138138
// Add defaultSchema back to relevantTablesWithFields
139139
relevantTablesWithFields = relevantTablesWithFields.map(table => {

apps/src/package.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export { getAppStateConfigs } from "./appStateConfigs";
22
export { applyTableDiffs } from "./common/utils";
33
export { getTableContextYAML, filterTablesByCatalog } from "./metabase/helpers/catalog";
4-
export { getTableData, getDatabaseTablesAndModelsWithoutFields, getAllCardsAndModels as getAllCards, getAllCardsLegacy, getAllFields, getAllFieldsFiltered } from "./metabase/helpers/metabaseAPIHelpers";
4+
export { getAllCardsAndModels, getTableData, getDatabaseTablesAndModelsWithoutFields, getAllCardsAndModels as getAllCards, getAllFields, getAllFieldsFiltered } from "./metabase/helpers/metabaseAPIHelpers";
55
export { fetchModelInfo } from "./metabase/helpers/metabaseAPI";
66
export { getAllTemplateTagsInQuery, applySQLEdits, type SQLEdits } from "./metabase/helpers/sqlQuery";
77
export { getModelsWithFields, getSelectedAndRelevantModels, modifySqlForMetabaseModels, replaceLLMFriendlyIdentifiersInSqlWithModels } from "./metabase/helpers/metabaseModels";

0 commit comments

Comments
 (0)