New Code Generator - borkdominik/bigER GitHub Wiki

This page describes how the tool can be extended to include a new code generator.

Implementing the Generator

Generators are implemented on the server-side in Java or Xtend. The generators are located within the org.big.erd.generator package.

As a first step, a new code generator must implement the IErGenerator interface and its method. The code below, demonstrates how the interface is implemented for the SqlGenerator:

class SqlGenerator implements IErGenerator {
	
   override void generate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
      val model = resource.contents.get(0) as Model
      validate(resource, model)   // optional additional validation
      val fileName = (model.name ?: 'output') + ".sql"
      fsa.generateFile(fileName, generate(model))
   }
   
   def String generate(Model model) {
      // map model to generated code...
   }
}

By passing an instance of Resource the generator has access to the whole Model and files can be created by using the provided IFileSystemAccess2.

Execution of the Generator

The next step is to provide a command, such that the generator can be executed. This is accomplished in the ErCommandService class (located in the org.big.erd.ide.commands package), which stores commands and their corresponding generators in a hash map for look-up. The code below demonstrates how a new command can be added to the service.

static final String GENERATE_PREFIX = "erdiagram.generate"
static final String GENERATE_SQL_COMMAND = GENERATE_PREFIX + ".sql"
static final String GENERATE_EXAMPLE_COMMAND = GENERATE_PREFIX + ".example"

override initialize() {
   generators = new HashMap
   generators.put(GENERATE_SQL_COMMAND, new SqlGenerator)
   // add the command and corresponding generator to the map
   generators.put(GENERATE_EXAMPLE_COMMAND, new ExampleGenerator)    
   // initialize the command
   return #[ 
      GENERATE_SQL_COMMAND, GENERATE_EXAMPLE_COMMAND
   ]
}

The execute() method can handle execution of the commands by using the initialized hash map to retrieve a corresponding generator for the command that is getting passed.

Command Proxy for Extension

The final step is to add a proxy for the new command to the client, such that the generator can be executed from VS Code.

Start by adding a command contribution point in the package.json of the extension. Additionally, you can add the command to a menu such as editor/context or explorer/context, such that it can be executed from the context menu, when right-clicking .erd files.

"commands": [
   {
      "command": "erdiagram.generate.sql.proxy",
      "title": "Generate SQL",
      "category": "bigER"
   },
   // other commands...
]

Next, provide a handler for the command and register the command with its handler in the extension. The handler is responsible for executing the command on the server and handling its response (see generateSqlHandler for an example).

// File: generate.ts
export const sqlServerCommand = "erdiagram.generate.sql";

export const generateSqlHandler = async () => {
    sendToServer(sqlServerCommand);
};

Registration of the commands is done in the registerCommands() method of the extension (see erdiagram-lsp-extension.ts)

// File: erdiagram-lsp-extension.ts
override registerCommands() {
   this.context.subscriptions.push(
      vscode.commands.registerCommand("erdiagram.generate.sql.proxy", generateSqlHandler)
   );
}

Add to Webview

Finally, the command has to be made available for the webview. For this, simply add a new option to the existing GenerateButton in the toolbar (see button.ts).

export class GenerateButton implements ToolButtonDropdown {
    constructor(
        public readonly id = "btn_dropdown_generate",
        public readonly label = "Generate",
        public readonly icon = "file-code",
        public readonly options = new Map<string, string>([
            ["sql", "Generic SQL"],
            ["postgres", "PostgreSQL"],
            ["oracle", "Oracle SQL"],
            ["mysql", "MySQL"],
            ["mssql", "MS SQL"],
            ["db2", "Db2"],
            // Add new option here
        ])
    ) {}
}

After re-building all the packages the new option should appear in the dropdown of the toolbar.