Learn from real-world extension implementations that showcase different capabilities of the Superset extension system.
A SQL Lab panel that analyzes queries and displays information about referenced tables.
// Parse SQL and extract tables function extractTables(sql: string): TableReference[] { const tables = []; const tableRegex = /FROM\s+(\w+\.?\w+)/gi; let match; while ((match = tableRegex.exec(sql)) !== null) { tables.push({ schema: match[1].split('.')[0], table: match[1].split('.')[1] || match[1], }); } return tables; } // Register panel export function activate(context: ExtensionContext) { const panel = context.core.registerView('dataset-references.panel', () => ( <DatasetReferencesPanel /> )); // Listen for query changes const listener = context.sqlLab.onDidChangeEditorContent((content) => { const tables = extractTables(content); updatePanelWithTables(tables); }); context.subscriptions.push(panel, listener); }
{ "name": "dataset-references", "contributions": { "views": { "sqllab.panels": [{ "id": "dataset-references.panel", "name": "Dataset References", "icon": "DatabaseOutlined", "location": "right" }] } } }
Analyzes SQL queries and suggests optimizations.
// Register optimization command const optimizeCommand = context.commands.registerCommand('query-optimizer.analyze', { title: 'Analyze Query Performance', icon: 'ThunderboltOutlined', execute: async () => { const query = context.sqlLab.getCurrentQuery(); const database = context.sqlLab.getCurrentDatabase(); // Get execution plan const plan = await getExecutionPlan(database.id, query); // Analyze and suggest improvements const suggestions = analyzeExecutionPlan(plan); // Show results in panel showOptimizationResults(suggestions); } }); // Add to editor menu "menus": { "sqllab.editor": { "primary": [{ "command": "query-optimizer.analyze", "when": "editorHasContent" }] } }
Converts natural language questions to SQL queries using LLM integration.
// Backend API endpoint @rest_api.route('/nl2sql/generate') def generate_sql(prompt: str, context: dict): # Use LLM to generate SQL sql = llm_client.generate( prompt=prompt, schema=context['schema'], examples=context['examples'] ) # Validate generated SQL validation = validate_sql(sql) return { 'sql': sql, 'valid': validation.is_valid, 'errors': validation.errors }
// Frontend integration function NL2SQLPanel() { const [prompt, setPrompt] = useState(''); const [loading, setLoading] = useState(false); const generateSQL = async () => { setLoading(true); const response = await context.network.api.post('/extensions/nl2sql/generate', { prompt, context: { database: context.sqlLab.getCurrentDatabase(), schema: await context.sqlLab.getCurrentSchema(), } }); if (response.valid) { // Insert SQL into editor context.sqlLab.insertText(response.sql); } setLoading(false); }; return ( <div> <Input.TextArea value={prompt} onChange={(e) => setPrompt(e.target.value)} placeholder="Describe what data you want..." /> <Button onClick={generateSQL} loading={loading}> Generate SQL </Button> </div> ); }
Interactive database schema visualization.
import { Graph } from '@antv/g6'; function SchemaVisualizer() { const containerRef = useRef<HTMLDivElement>(null); const [graph, setGraph] = useState<Graph>(); useEffect(() => { if (!containerRef.current) return; const g = new Graph({ container: containerRef.current, layout: { type: 'dagre', rankdir: 'LR', }, defaultNode: { type: 'sql-table-node', }, defaultEdge: { type: 'sql-relation-edge', }, }); setGraph(g); loadSchemaData(g); return () => g.destroy(); }, []); const loadSchemaData = async (g: Graph) => { const tables = await context.sqlLab.getTables(); const nodes = tables.map(table => ({ id: table.name, label: table.name, columns: table.columns, })); const edges = extractRelationships(tables); g.data({ nodes, edges }); g.render(); }; return <div ref={containerRef} style={{ height: '100%' }} />; }
Formats and beautifies SQL code with customizable rules.
import { format } from 'sql-formatter'; const formatCommand = context.commands.registerCommand('sql-formatter.format', { title: 'Format SQL', execute: () => { const sql = context.sqlLab.getCurrentQuery(); const formatted = format(sql, { language: 'sql', indent: ' ', uppercase: true, linesBetweenQueries: 2, }); context.sqlLab.replaceQuery(formatted); } }); // Auto-format on save context.sqlLab.onWillSaveQuery((event) => { if (context.storage.local.get('autoFormat')) { const formatted = format(event.query); event.waitUntil(Promise.resolve(formatted)); } });
Enhanced query history with advanced search and filtering.
function QueryHistoryPanel() { const [queries, setQueries] = useState<Query[]>([]); const [filters, setFilters] = useState<Filters>({}); useEffect(() => { loadQueries(); }, [filters]); const loadQueries = async () => { const history = await context.network.api.get('/api/v1/query', { params: { ...filters, page_size: 100, } }); setQueries(history.result); }; return ( <div> <SearchFilters onChange={setFilters} /> <Table dataSource={queries} columns={[ { title: 'Query', dataIndex: 'sql', ellipsis: true }, { title: 'Database', dataIndex: 'database' }, { title: 'Status', dataIndex: 'status' }, { title: 'Duration', dataIndex: 'duration' }, { title: 'User', dataIndex: 'user' }, { title: 'Actions', render: (query) => ( <Button icon={<CopyOutlined />} onClick={() => context.sqlLab.insertText(query.sql)} /> ), }, ]} /> </div> ); }
Version control for SQL queries and dashboards.
from git import Repo class GitExtension: def __init__(self, repo_path): self.repo = Repo(repo_path) def save_query(self, query, message): # Save query to file path = f"queries/{query.name}.sql" with open(path, 'w') as f: f.write(query.sql) # Commit to Git self.repo.index.add([path]) self.repo.index.commit(message) return { 'status': 'success', 'commit': self.repo.head.commit.hexsha }
extension/ ├── frontend/ │ ├── src/ │ │ ├── components/ # UI components │ │ ├── hooks/ # Custom hooks │ │ ├── services/ # API services │ │ ├── utils/ # Utilities │ │ └── index.tsx # Entry point │ └── tests/ ├── backend/ │ ├── src/ │ │ ├── api/ # REST endpoints │ │ ├── models/ # Data models │ │ ├── services/ # Business logic │ │ └── entrypoint.py │ └── tests/
// Test example describe('DatasetReferences', () => { it('should extract tables from SQL', () => { const sql = 'SELECT * FROM users JOIN orders ON users.id = orders.user_id'; const tables = extractTables(sql); expect(tables).toEqual([ { schema: 'public', table: 'users' }, { schema: 'public', table: 'orders' }, ]); }); });