Add complete integration with Metabase API to fetch data from 'facturador supabase' database. Features: - Server-side Metabase authentication using session tokens - Utility functions for Metabase API requests with auto-retry - API endpoints to proxy Metabase requests - GET /api/metabase/databases - List all databases - GET /api/metabase/tables/:databaseId - Get tables and metadata - POST /api/metabase/query - Execute queries against tables - useMetabase() composable for frontend consumption - getDatabases() - Fetch available databases - getDatabaseMetadata() - Get tables and fields info - queryTable() - Execute queries with filters and limits - resultToObjects() - Helper to convert results to objects Session tokens are cached and auto-refreshed when expired. This enables the application to display real data from the facturador database without using embeds or iframes.
155 lines
3.3 KiB
TypeScript
155 lines
3.3 KiB
TypeScript
/**
|
|
* Composable for interacting with Metabase API
|
|
*
|
|
* Provides methods to query databases, tables, and execute queries
|
|
* through the Nuxt server API endpoints
|
|
*/
|
|
|
|
export interface MetabaseDatabase {
|
|
id: number
|
|
name: string
|
|
engine: string
|
|
[key: string]: any
|
|
}
|
|
|
|
export interface MetabaseTable {
|
|
id: number
|
|
name: string
|
|
display_name: string
|
|
schema: string
|
|
fields: MetabaseField[]
|
|
[key: string]: any
|
|
}
|
|
|
|
export interface MetabaseField {
|
|
id: number
|
|
name: string
|
|
display_name: string
|
|
base_type: string
|
|
semantic_type: string | null
|
|
[key: string]: any
|
|
}
|
|
|
|
export interface MetabaseQueryResult {
|
|
data: {
|
|
rows: any[][]
|
|
cols: Array<{
|
|
name: string
|
|
display_name: string
|
|
base_type: string
|
|
[key: string]: any
|
|
}>
|
|
}
|
|
row_count: number
|
|
status: string
|
|
[key: string]: any
|
|
}
|
|
|
|
export function useMetabase() {
|
|
const loading = ref(false)
|
|
const error = ref<Error | null>(null)
|
|
|
|
/**
|
|
* Get all available databases
|
|
*/
|
|
async function getDatabases(): Promise<MetabaseDatabase[]> {
|
|
loading.value = true
|
|
error.value = null
|
|
|
|
try {
|
|
const databases = await $fetch<MetabaseDatabase[]>('/api/metabase/databases')
|
|
return databases
|
|
} catch (err: any) {
|
|
error.value = err
|
|
console.error('[useMetabase] Failed to get databases:', err)
|
|
throw err
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get metadata for a specific database (includes all tables and fields)
|
|
*/
|
|
async function getDatabaseMetadata(databaseId: number): Promise<any> {
|
|
loading.value = true
|
|
error.value = null
|
|
|
|
try {
|
|
const metadata = await $fetch(`/api/metabase/tables/${databaseId}`)
|
|
return metadata
|
|
} catch (err: any) {
|
|
error.value = err
|
|
console.error(`[useMetabase] Failed to get metadata for database ${databaseId}:`, err)
|
|
throw err
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute a query against a specific table
|
|
*
|
|
* @param databaseId - The Metabase database ID
|
|
* @param tableId - The Metabase table ID
|
|
* @param query - Optional query parameters (limit, filters, etc.)
|
|
*/
|
|
async function queryTable(
|
|
databaseId: number,
|
|
tableId: number,
|
|
query: {
|
|
limit?: number
|
|
filter?: any[]
|
|
'order-by'?: any[]
|
|
[key: string]: any
|
|
} = {}
|
|
): Promise<MetabaseQueryResult> {
|
|
loading.value = true
|
|
error.value = null
|
|
|
|
try {
|
|
const result = await $fetch<MetabaseQueryResult>('/api/metabase/query', {
|
|
method: 'POST',
|
|
body: {
|
|
databaseId,
|
|
tableId,
|
|
query
|
|
}
|
|
})
|
|
return result
|
|
} catch (err: any) {
|
|
error.value = err
|
|
console.error('[useMetabase] Failed to execute query:', err)
|
|
throw err
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper to convert Metabase query result to array of objects
|
|
* Makes it easier to work with the data in components
|
|
*/
|
|
function resultToObjects(result: MetabaseQueryResult): Record<string, any>[] {
|
|
const cols = result.data.cols
|
|
const rows = result.data.rows
|
|
|
|
return rows.map(row => {
|
|
const obj: Record<string, any> = {}
|
|
cols.forEach((col, index) => {
|
|
obj[col.name] = row[index]
|
|
})
|
|
return obj
|
|
})
|
|
}
|
|
|
|
return {
|
|
loading,
|
|
error,
|
|
getDatabases,
|
|
getDatabaseMetadata,
|
|
queryTable,
|
|
resultToObjects
|
|
}
|
|
}
|