Skip to content

Latest commit

 

History

History
174 lines (138 loc) · 4.21 KB

File metadata and controls

174 lines (138 loc) · 4.21 KB

Plugin Development Guide

This guide explains how to create custom database drivers for Open Data Diff.

Plugin Structure

A plugin is a Node.js module that exports a function returning a DatabaseDriver implementation.

Directory Structure

my-plugin/
├── package.json
├── index.js (or index.ts)
└── README.md

package.json Requirements

{
  "name": "my-database-plugin",
  "version": "1.0.0",
  "description": "Custom database driver for MyDB",
  "main": "index.js",
  "databaseDriver": "mydb",
  "author": "Your Name",
  "keywords": ["database", "open-data-diff", "plugin"]
}

The databaseDriver field is required and specifies the driver name.

DatabaseDriver Interface

interface DatabaseDriver {
  name: string;
  testConnection(connection: any): Promise<boolean>;
  getSchema(connection: any): Promise<DatabaseSchema>;
  executeQuery(connection: any, query: string): Promise<any[]>;
  disconnect(): Promise<void>;
}

Methods

testConnection(connection)

Tests if a connection can be established to the database.

  • Parameters: Connection configuration object
  • Returns: Promise<boolean> - true if connection successful

getSchema(connection)

Retrieves the complete database schema.

  • Parameters: Connection configuration object
  • Returns: Promise<DatabaseSchema> - schema object with tables, views, etc.

executeQuery(connection, query)

Executes a SQL query and returns results.

  • Parameters:
    • connection: Connection configuration object
    • query: SQL query string
  • Returns: Promise<any[]> - array of result rows

disconnect()

Closes all connections and cleans up resources.

  • Returns: Promise<void>

Example Plugin

// index.js
const mysql = require('mysql2/promise');

class MySQLDriver {
  constructor() {
    this.name = 'mysql';
    this.pools = new Map();
  }

  async testConnection(connection) {
    try {
      const pool = await this.getPool(connection);
      const [rows] = await pool.execute('SELECT 1 as test');
      return rows.length > 0;
    } catch (error) {
      return false;
    }
  }

  async getSchema(connection) {
    const pool = await this.getPool(connection);
    
    // Implement schema retrieval logic
    const tables = await this.getTables(pool);
    const views = await this.getViews(pool);
    
    return {
      tables,
      views,
      procedures: [],
      functions: []
    };
  }

  async executeQuery(connection, query) {
    const pool = await this.getPool(connection);
    const [rows] = await pool.execute(query);
    return rows;
  }

  async disconnect() {
    for (const pool of this.pools.values()) {
      await pool.end();
    }
    this.pools.clear();
  }

  async getPool(connection) {
    const key = `${connection.host}:${connection.port}:${connection.database}`;
    
    if (!this.pools.has(key)) {
      const pool = mysql.createPool({
        host: connection.host,
        port: connection.port || 3306,
        user: connection.username,
        password: connection.password,
        database: connection.database,
        waitForConnections: true,
        connectionLimit: 10,
        queueLimit: 0
      });
      
      this.pools.set(key, pool);
    }
    
    return this.pools.get(key);
  }

  // Implement getTables, getViews, etc.
}

module.exports = function() {
  return new MySQLDriver();
};

Installation

  1. Place your plugin directory in the plugins/ folder of the application
  2. The plugin will be automatically discovered on startup
  3. Load the plugin through the UI or API

Best Practices

  • Always handle connection errors gracefully
  • Implement proper connection pooling
  • Clean up resources in the disconnect() method
  • Use parameterized queries to prevent SQL injection
  • Follow the schema format exactly as defined in the types
  • Test your plugin thoroughly with different connection scenarios

Schema Format

Ensure your getSchema() method returns data in the correct format:

interface DatabaseSchema {
  tables: TableSchema[];
  views: ViewSchema[];
  procedures: ProcedureSchema[];
  functions: FunctionSchema[];
}

See the TypeScript definitions in src/types/database.ts for complete schema structure.