Skip to content

Commit ac475d7

Browse files
add modelFields entry in db_metadata for model fields (#275)
* add modelFields entry in db_metadata for model fields * use the /cards endpoint itself to get model fields * revert metabaseModels.ts * handle null result_metadata
1 parent d51ed0f commit ac475d7

File tree

5 files changed

+52
-19
lines changed

5 files changed

+52
-19
lines changed

apps/src/metabase/helpers/metabaseAPIHelpers.ts

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* from metabaseAPI.ts and state functions from metabaseStateAPI.ts.
66
*/
77

8-
import _, { map, get, isEmpty, flatMap, filter, sortBy, reverse, pick, omit } from 'lodash';
8+
import _, { map, get, isEmpty, flatMap, filter, sortBy, reverse, pick, omit, partition } from 'lodash';
99
import { getTablesFromSqlRegex, TableAndSchema } from './parseSql';
1010
import { handlePromise, deterministicSample } from '../../common/utils';
1111
import { getCurrentUserInfo, getSelectedDbId } from './metabaseStateAPI';
@@ -189,7 +189,16 @@ export async function getDatabases() {
189189
return await fetchDatabases({}) as DatabaseResponse;
190190
}
191191

192-
export async function getAllCards(forceRefresh = false) {
192+
type ResultMetadataElm = {
193+
display_name: string;
194+
source: string;
195+
name: string;
196+
base_type: string;
197+
semantic_type: string;
198+
field_ref: [string, string, { "base-type": string }];
199+
};
200+
201+
export async function getAllCardsAndModels(forceRefresh = false) {
193202
const cards = await handlePromise(
194203
forceRefresh ? fetchCards.refresh({}) : fetchCards({}),
195204
"[minusx] Error getting all cards",
@@ -207,18 +216,18 @@ export async function getAllCards(forceRefresh = false) {
207216
console.log('[minusx] getAllCards - Total cards:', cards);
208217

209218
// Filter cards by database_id and last_used_at (last 3 months only)
210-
const filteredCards = filter(cards, (card) => {
219+
const filteredCardsAndModels = filter(cards, (card) => {
211220
const lastUsedAt = get(card, 'last_used_at');
212221
const databaseId = get(card, 'database_id');
213222

214223
// Filter by selected database and last 3 months
215224
const matchesDatabase = selectedDbId ? databaseId === selectedDbId : true;
216225
const isRecent = lastUsedAt && lastUsedAt > cutoffDate;
217-
const isModel = get(card, 'type') === 'model';
218226

219-
return matchesDatabase && isRecent && !isModel;
227+
return matchesDatabase && isRecent;
220228
});
221-
229+
// split into cards and models
230+
const [filteredCards, filteredModels] = partition(filteredCardsAndModels, (card) => get(card, 'type') !== 'model');
222231
// Sort by view_count descending
223232
// if length > 1000, limit to 1000
224233
const sortedCards = reverse(sortBy(filteredCards, 'view_count'));
@@ -261,7 +270,25 @@ export async function getAllCards(forceRefresh = false) {
261270

262271
return cleanCard;
263272
});
264-
273+
274+
const processedModelFields = filteredModels.flatMap((model) => {
275+
const result_metadata = get(model, 'result_metadata', [])
276+
if (result_metadata == null) {
277+
console.warn("[minusx] model has no result_metadata: ", model)
278+
return []
279+
}
280+
const columns = result_metadata.map((column: ResultMetadataElm) => {
281+
return {
282+
id: get(column, 'name'),
283+
name: get(column, 'name'),
284+
type: get(column, 'base_type'),
285+
model_id: get(model, 'id'),
286+
model_name: get(model, 'name')
287+
}
288+
})
289+
return columns
290+
})
291+
265292
console.log('Processed cards:', processedCards);
266293
const tables: Record<string, TableAndSchema> = {};
267294
_.forEach(processedCards, (card) => {
@@ -279,11 +306,11 @@ export async function getAllCards(forceRefresh = false) {
279306
const relevantTables = _.chain(tables).values().sortBy('count').reverse().value();
280307
console.log('Tables from cards:', relevantTables);
281308

282-
return { cards: processedCards, tables: relevantTables };
309+
return { cards: processedCards, tables: relevantTables, modelFields: processedModelFields };
283310
}
284311

285312
export async function getAllCardsLegacy() {
286-
const result = await getAllCards();
313+
const result = await getAllCardsAndModels();
287314
return result.cards;
288315
}
289316

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, getAllCards, getAllCardsLegacy, getAllFields, getAllFieldsFiltered } from "./metabase/helpers/metabaseAPIHelpers";
4+
export { getTableData, getDatabaseTablesAndModelsWithoutFields, getAllCardsAndModels as getAllCards, getAllCardsLegacy, getAllFields, getAllFieldsFiltered } from "./metabase/helpers/metabaseAPIHelpers";
55
export { fetchModelInfo } from "./metabase/helpers/metabaseAPI";
66
export { getAllTemplateTagsInQuery } from "./metabase/helpers/sqlQuery";
77
export { getModelsWithFields, getSelectedAndRelevantModels, modifySqlForMetabaseModels, replaceLLMFriendlyIdentifiersInSqlWithModels } from "./metabase/helpers/metabaseModels";

web/src/helpers/LLM/remote.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ export async function planActionsRemote({
3737
const currentState = getState();
3838
if (currentState.settings.drMode && currentState.settings.analystMode) {
3939
try {
40-
const { cardsHash, dbSchemaHash, fieldsHash } = await getAllMetadataPromise;
40+
const { cardsHash, dbSchemaHash, fieldsHash, modelFieldsHash } = await getAllMetadataPromise;
4141
// @ts-ignore
4242
payload.cardsHash = cardsHash;
4343
// @ts-ignore
4444
payload.dbSchemaHash = dbSchemaHash;
4545
// @ts-ignore
4646
payload.fieldsHash = fieldsHash;
47+
// @ts-ignore
48+
payload.modelFieldsHash = modelFieldsHash;
4749
console.log('[minusx] Added metadata hashes to request for analyst mode');
4850
} catch (error) {
4951
console.warn('[minusx] Failed to fetch metadata for analyst mode:', error);

web/src/helpers/metadataProcessor.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ import { get, isEmpty } from 'lodash';
1212
import { MetadataProcessingResult, setMetadataHash, setMetadataProcessingCache, clearMetadataProcessingCache } from '../state/settings/reducer';
1313
import { getState } from '../state/store';
1414
import { dispatch } from '../state/dispatch';
15-
import { getAllCards, getAllCardsLegacy, getDatabaseTablesAndModelsWithoutFields, getAllFields } from '../../../apps/src/metabase/helpers/metabaseAPIHelpers';
15+
import { getAllCardsAndModels, getAllCardsLegacy, getDatabaseTablesAndModelsWithoutFields, getAllFields } from '../../../apps/src/metabase/helpers/metabaseAPIHelpers';
1616
import { fetchDatabaseFields } from '../../../apps/src/metabase/helpers/metabaseAPI';
1717
import { getSelectedDbId } from '../../../apps/src/metabase/helpers/metabaseStateAPI';
18+
import { getModelsWithFields } from '../../../apps/src/metabase/helpers/metabaseModels';
1819

1920
export interface MetadataItem {
2021
metadata_type: string;
@@ -200,12 +201,11 @@ export async function processAllMetadata(forceRefresh = false) : Promise<Metadat
200201
const processingPromise = (async () => {
201202
try {
202203

203-
const [dbSchema, { cards, tables: referencedTables }, allFields] = await Promise.all([
204+
const [dbSchema, { cards, tables: referencedTables, modelFields }, allFields] = await Promise.all([
204205
getDatabaseTablesAndModelsWithoutFields(selectedDbId, forceRefresh, forceRefresh),
205-
getAllCards(forceRefresh),
206+
getAllCardsAndModels(forceRefresh),
206207
forceRefresh ? fetchDatabaseFields.refresh({ db_id: selectedDbId }) : fetchDatabaseFields({ db_id: selectedDbId })
207208
])
208-
209209
console.log('[minusx] All API calls completed. Processing data...')
210210

211211
// Step 2: Create sets for efficient lookup of existing tables
@@ -261,21 +261,24 @@ export async function processAllMetadata(forceRefresh = false) : Promise<Metadat
261261

262262
console.log('[minusx] Fields after filtering:', filteredFields.length, 'out of', allFields.length)
263263

264-
// Step 5: Process metadata for all three with filtered data
264+
console.log("[minusx] modelFields: ", modelFields.length)
265+
// Step 5: Process metadata for all four with filtered data
265266
console.log('[minusx] Processing metadata with filtered data...')
266267

267-
const [cardsHash, dbSchemaHash, fieldsHash] = await Promise.all([
268+
const [cardsHash, dbSchemaHash, fieldsHash, modelFieldsHash] = await Promise.all([
268269
processMetadataWithCaching('cards', async () => cards),
269270
processMetadataWithCaching('dbSchema', async () => dbSchema),
270-
processMetadataWithCaching('fields', async () => filteredFields)
271+
processMetadataWithCaching('fields', async () => filteredFields),
272+
processMetadataWithCaching('modelFields', async () => modelFields)
271273
])
272274

273275
console.log('[minusx] Coordinated metadata processing complete')
274276

275277
const result = {
276278
cardsHash,
277279
dbSchemaHash,
278-
fieldsHash
280+
fieldsHash,
281+
modelFieldsHash
279282
}
280283

281284
// Cache the result for this database ID

web/src/state/settings/reducer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface MetadataProcessingResult {
88
cardsHash?: string;
99
dbSchemaHash?: string;
1010
fieldsHash?: string;
11+
modelFieldsHash?: string;
1112
}
1213

1314
interface MetadataProcessingCacheEntry {

0 commit comments

Comments
 (0)