PHPackages                             vonbraunlabs/sql-ddl-generator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. vonbraunlabs/sql-ddl-generator

ActiveLibrary[Database &amp; ORM](/categories/database)

vonbraunlabs/sql-ddl-generator
==============================

0.1.10(4y ago)87431PHPPHP ^7.0|^8.0

Since Jan 16Pushed 4y ago1 watchersCompare

[ Source](https://github.com/vonbraunlabs/sql-ddl-generator)[ Packagist](https://packagist.org/packages/vonbraunlabs/sql-ddl-generator)[ RSS](/packages/vonbraunlabs-sql-ddl-generator/feed)WikiDiscussions master Synced 3d ago

READMEChangelogDependencies (2)Versions (12)Used By (0)

SQL To DDL Generator
====================

[](#sql-to-ddl-generator)

A tool to aid on generating DDL SQL. It was conceived to abstract away the boring part of writing the SQL tables and let developers/DBAs focus on the business logic. This tool assumes that every table have:

- an integer ID column that uniquely identifies the row and is named ID
- audit columns to specify created time and last updated time
- audit columns to specify the db user who created the row and the one who last updated the row
- `active` column that indicates wether that row is active or should be regarded as deleted/inactive

The file `user.json` contains the following JSON:

```
{
    "name": "mydatabase",
    "table": {
        "name": "user",
        "field_list": [
            {
                "name": "username",
                "type": "VARCHAR(30)",
                "not_null": true,
                "comment": "Login username"
            },
            {
                "name": "email",
                "type": "VARCHAR(64)",
                "not_null": true,
                "comment": "User email"
            },
            {
                "name": "password",
                "type": "VARCHAR(128)",
                "not_null": true,
                "comment": "User password"
            },
            {
                "name": "confirmed_at",
                "type": "DATETIME",
                "not_null": false,
                "comment": "User confirmation date"
            }
        ],
        "fk_list": [
            {
                "name": "inviter_id",
                "references": "user",
                "comment": "If user was invited by someone, contains the ID of that user account, NULL otherwise"
            }
        ],
        "unique_list": [
            ["username"],
            ["email"]
        ]
    }
}
```

The name of the schema/database is `mydatabase`. It is creating a table named `user`, with four columns: `username`, `email`, `password` and `confirmed_at`. Moreover, it declares a foreign key column `inviter_id` to itself. On its last part, the snippet declares UNIQUE constraints. The rows must have unique `username` and unique `email`. Executing `./sql-ddl-generator user.json` the following is printed to standard output:

```
-- Generated by VBL - sql-ddl-generator
-- -----------------------------------------------------
-- Database mydatabase
-- -----------------------------------------------------

CREATE SCHEMA IF NOT EXISTS `mydatabase` DEFAULT CHARACTER SET utf8 ;
USE `mydatabase`;

-- -----------------------------------------------------
-- Table `mydatabase`.`user`
-- -----------------------------------------------------

CREATE TABLE IF NOT EXISTS `mydatabase`.`user` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `username` VARCHAR(30) NOT NULL COMMENT 'Login username',
    `email` VARCHAR(64) NOT NULL COMMENT 'User email',
    `password` VARCHAR(128) NOT NULL COMMENT 'User password',
    `confirmed_at` DATETIME COMMENT 'User confirmation date',
    `active` BOOLEAN NOT NULL DEFAULT 1,
    `create_by` VARCHAR(32) NOT NULL,
    `create_time` TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
    `update_by` VARCHAR(32) NOT NULL,
    `update_time` TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
    `inviter_id` INT UNSIGNED COMMENT 'If user was invited by someone, contains the ID of that user account, NULL otherwise',
    PRIMARY KEY (`id`),
    CONSTRAINT `fk_user_inviter_id`
        FOREIGN KEY(`inviter_id`)
        REFERENCES `mydatabase`.`user` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION
) Engine=InnoDB;

CREATE UNIQUE INDEX `unique_user_username` ON `mydatabase`.`user` (`username`);
CREATE UNIQUE INDEX `unique_user_email` ON `mydatabase`.`user` (`email`);

CREATE TRIGGER `user_before_insert` BEFORE INSERT ON `mydatabase`.`user`
FOR EACH ROW
    SET NEW.`create_by` = CURRENT_USER(),
        NEW.`update_by` = CURRENT_USER();

CREATE TRIGGER `user_before_update` BEFORE UPDATE ON `mydatabase`.`user`
FOR EACH ROW
    SET NEW.`update_by` = CURRENT_USER(),
        NEW.`update_time` = CURRENT_TIMESTAMP(3);
```

Auditing Special Feature
------------------------

[](#auditing-special-feature)

For some application, it is necessary to keep track of all changes on table, usually for auditing porposes. The `audit` flag creates a clone of the table with the prefix `audit_` in its name and store all changes on the clonned table. If a row is updated N times, there will be N records of that specific row on the equivalent audit table.

```
{
    "name": "mydatabase",
    "table": {
        "name": "user",
        "field_list": [
            {
                "name": "username",
                "type": "VARCHAR(30)",
                "not_null": true,
                "comment": "Login username"
            },
            {
                "name": "email",
                "type": "VARCHAR(64)",
                "not_null": true,
                "comment": "User email"
            },
            {
                "name": "password",
                "type": "VARCHAR(128)",
                "not_null": true,
                "comment": "User password"
            },
            {
                "name": "confirmed_at",
                "type": "DATETIME",
                "not_null": false,
                "comment": "User confirmation date"
            }
        ],
        "fk_list": [
            {
                "name": "inviter_id",
                "references": "user",
                "comment": "If user was invited by someone, contains the ID of that user account, NULL otherwise"
            }
        ],
        "unique_list": [
            ["username"],
            ["email"]
        ],
        "audit": true
    }
}

```

Consider the JSON above. From this model, the sql-ddl-generator will produce SQL below. Mind how tedious it would be to write that that SQL by hand. Now imagine you have many tables that require that auditing feature.

```
-- Generated by VBL - sql-ddl-generator
-- -----------------------------------------------------
-- Database mydatabase
-- -----------------------------------------------------

CREATE SCHEMA IF NOT EXISTS `mydatabase` DEFAULT CHARACTER SET utf8 ;
USE `mydatabase`;

-- -----------------------------------------------------
-- Table `mydatabase`.`user`
-- -----------------------------------------------------

CREATE TABLE IF NOT EXISTS `mydatabase`.`user` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `username` VARCHAR(30) NOT NULL COMMENT 'Login username',
    `email` VARCHAR(64) NOT NULL COMMENT 'User email',
    `password` VARCHAR(128) NOT NULL COMMENT 'User password',
    `confirmed_at` DATETIME COMMENT 'User confirmation date',
    `active` BOOLEAN NOT NULL DEFAULT 1,
    `create_by` VARCHAR(32) NOT NULL,
    `create_time` TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
    `update_by` VARCHAR(32) NOT NULL,
    `update_time` TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
    `who_id` INT UNSIGNED NOT NULL,
    `inviter_id` INT UNSIGNED COMMENT 'If user was invited by someone, contains the ID of that user account, NULL otherwise',
    PRIMARY KEY (`id`),
    CONSTRAINT `fk_user_who_id`
        FOREIGN KEY(`who_id`)
        REFERENCES `mydatabase`.`user` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION,
    CONSTRAINT `fk_user_inviter_id`
        FOREIGN KEY(`inviter_id`)
        REFERENCES `mydatabase`.`user` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION
) Engine=InnoDB;

CREATE UNIQUE INDEX `unique_user_username` ON `mydatabase`.`user` (`username`);
CREATE UNIQUE INDEX `unique_user_email` ON `mydatabase`.`user` (`email`);

CREATE TRIGGER `user_before_insert` BEFORE INSERT ON `mydatabase`.`user`
FOR EACH ROW
    SET NEW.`create_by` = CURRENT_USER(),
        NEW.`update_by` = CURRENT_USER();

CREATE TRIGGER `user_before_update` BEFORE UPDATE ON `mydatabase`.`user`
FOR EACH ROW
    SET NEW.`update_by` = CURRENT_USER(),
        NEW.`update_time` = CURRENT_TIMESTAMP(3);

-- -----------------------------------------------------
-- Audit Table for user
-- -----------------------------------------------------

CREATE TABLE IF NOT EXISTS `mydatabase`.`audit_user` LIKE `mydatabase`.`user`;
ALTER TABLE `mydatabase`.`audit_user` ADD COLUMN `user_id` INT UNSIGNED NOT NULL AFTER `id`;
ALTER TABLE `mydatabase`.`audit_user` ADD     CONSTRAINT `fk_audit_user_user_id`
        FOREIGN KEY(`user_id`)
        REFERENCES `mydatabase`.`user` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION;

DROP INDEX `unique_user_username` ON `mydatabase`.`audit_user`;
DROP INDEX `unique_user_email` ON `mydatabase`.`audit_user`;

ALTER TABLE `mydatabase`.`audit_user` ADD     CONSTRAINT `fk_audit_user_who_id`
        FOREIGN KEY(`who_id`)
        REFERENCES `mydatabase`.`user` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION;
ALTER TABLE `mydatabase`.`audit_user` ADD     CONSTRAINT `fk_audit_user_inviter_id`
        FOREIGN KEY(`inviter_id`)
        REFERENCES `mydatabase`.`user` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION;
delimiter //
CREATE TRIGGER `audit_user_insert_trigger`
AFTER INSERT ON `mydatabase`.`user`
FOR EACH ROW
BEGIN
    INSERT INTO `mydatabase`.`audit_user` (
        `user_id`,
        `username`,
        `email`,
        `password`,
        `confirmed_at`,
        `active`,
        `create_by`,
        `update_by`,
        `who_id`,
        `inviter_id`
    ) VALUES (
        NEW.`id`,
        NEW.`username`,
        NEW.`email`,
        NEW.`password`,
        NEW.`confirmed_at`,
        NEW.`active`,
        NEW.`create_by`,
        NEW.`update_by`,
        NEW.`who_id`,
        NEW.`inviter_id`
    );
END;//
DELIMITER ;

delimiter //
CREATE TRIGGER `audit_user_update_trigger`
AFTER UPDATE ON `mydatabase`.`user`
FOR EACH ROW
BEGIN
    INSERT INTO `mydatabase`.`audit_user` (
        `user_id`,
        `username`,
        `email`,
        `password`,
        `confirmed_at`,
        `active`,
        `create_by`,
        `update_by`,
        `who_id`,
        `inviter_id`
    ) VALUES (
        NEW.`id`,
        NEW.`username`,
        NEW.`email`,
        NEW.`password`,
        NEW.`confirmed_at`,
        NEW.`active`,
        NEW.`create_by`,
        NEW.`update_by`,
        NEW.`who_id`,
        NEW.`inviter_id`
    );
END;//
DELIMITER ;
```

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity20

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~130 days

Recently: every ~193 days

Total

11

Last Release

1739d ago

PHP version history (2 changes)0.1.0PHP ^7.0

0.1.10PHP ^7.0|^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/05ab8aebb8755f73e27f31b70bc7b64536abec420fdcf30f3f7c6bc3c45ee639?d=identicon)[dmelo](/maintainers/dmelo)

---

Top Contributors

[![dmelo](https://avatars.githubusercontent.com/u/89710?v=4)](https://github.com/dmelo "dmelo (16 commits)")

###  Code Quality

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/vonbraunlabs-sql-ddl-generator/health.svg)

```
[![Health](https://phpackages.com/badges/vonbraunlabs-sql-ddl-generator/health.svg)](https://phpackages.com/packages/vonbraunlabs-sql-ddl-generator)
```

###  Alternatives

[doctrine/orm

Object-Relational-Mapper for PHP

10.2k285.3M6.2k](/packages/doctrine-orm)[jdorn/sql-formatter

a PHP SQL highlighting library

3.9k115.1M102](/packages/jdorn-sql-formatter)[illuminate/database

The Illuminate Database package.

2.8k52.4M9.4k](/packages/illuminate-database)[mongodb/mongodb

MongoDB driver library

1.6k64.0M546](/packages/mongodb-mongodb)[ramsey/uuid-doctrine

Use ramsey/uuid as a Doctrine field type.

90340.3M211](/packages/ramsey-uuid-doctrine)[reliese/laravel

Reliese Components for Laravel Framework code generation.

1.7k3.4M16](/packages/reliese-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
