title: Extension Examples sidebar_position: 1 hide_title: true

Extension Examples

Learn from real-world extension implementations that showcase different capabilities of the Superset extension system.

Dataset References Panel

A SQL Lab panel that analyzes queries and displays information about referenced tables.

Features

  • Parses SQL to extract table references
  • Shows table owners and permissions
  • Displays last partition information
  • Provides row count estimates

Key Implementation

// 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);
}

Manifest

{
  "name": "dataset-references",
  "contributions": {
    "views": {
      "sqllab.panels": [{
        "id": "dataset-references.panel",
        "name": "Dataset References",
        "icon": "DatabaseOutlined",
        "location": "right"
      }]
    }
  }
}

Query Optimizer

Analyzes SQL queries and suggests optimizations.

Features

  • Detects missing indexes
  • Suggests query rewrites
  • Identifies expensive operations
  • Provides execution plan analysis

Implementation Highlights

// 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"
    }]
  }
}

Natural Language to SQL

Converts natural language questions to SQL queries using LLM integration.

Features

  • Natural language input
  • Context-aware SQL generation
  • Query validation
  • History tracking

Key Components

// 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>
  );
}

Schema Visualizer

Interactive database schema visualization.

Features

  • Visual ERD diagram
  • Table relationships
  • Column details on hover
  • Export to image

Implementation

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%' }} />;
}

SQL Formatter

Formats and beautifies SQL code with customizable rules.

Features

  • Multiple formatting styles
  • Custom rule configuration
  • Batch formatting
  • Format on save

Simple Implementation

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));
  }
});

Query History Search

Enhanced query history with advanced search and filtering.

Features

  • Full-text search
  • Filter by date, user, database
  • Query statistics
  • Export capabilities

UI Component

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>
  );
}

Git Integration

Version control for SQL queries and dashboards.

Features

  • Save queries to Git
  • Track changes
  • Collaborative editing
  • Branch management

Backend Integration

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
        }

Best Practices from Examples

1. User Experience

  • Provide clear feedback for async operations
  • Handle errors gracefully
  • Include loading states
  • Add keyboard shortcuts

2. Performance

  • Debounce expensive operations
  • Cache API responses
  • Use virtual scrolling for large lists
  • Lazy load heavy components

3. Integration

  • Respect Superset's theme
  • Use provided UI components
  • Follow existing UX patterns
  • Integrate with existing menus

4. Code Organization

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/

5. Testing

// 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' },
    ]);
  });
});

Learn More