Repository files navigation

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Warning

This project is experimental. It is operational in the author's environment, but it is not known if it can be operated in other environments without trouble.

licensepkggoreportcardworkflowworkflowworkflowcodecovsourcegraph

Demo

ddlctl_demo

Overview

ddlctl can do the following:

  • Output all RDBMS DDLs
  • Generate DDL from tagged Golang source code
  • Output differences between the RDBMS and your DDL
  • Automated Migration

TODO

  • generate subcommand
    • source language
      • Support go (beta)
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • show subcommand
    • dialect
      • Support mysql (beta)
      • Support postgres (alpha)
      • Support cockroachdb (beta)
      • Support spanner (alpha)
      • Support sqlite3
  • diff subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • apply subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3

Example: ddlctl generate

1. Prepare your annotated model source code

For example, prepare the following Go code:

package sample
// User is a user model struct.////pgddl:table public.users//pgddl:constraint UNIQUE ("username")//pgddl:index "index_users_username" ON public.users ("username")typeUserstruct {
UserIDstring`db:"user_id" pgddl:"TEXT NOT NULL" pk:"true"`Usernamestring`db:"username" pgddl:"TEXT NOT NULL"`Ageint`db:"age" pgddl:"INT NOT NULL"`
}
// Group is a group model struct.////pgddl:table CREATE TABLE IF NOT EXISTS public.groups//pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")typeGroupstruct {
GroupIDstring`db:"group_id" pgddl:"TEXT NOT NULL" pk:"true"`GroupNamestring`db:"group_name" pgddl:"TEXT NOT NULL"`Descriptionstring`db:"description" pgddl:"TEXT NOT NULL"`
}

2. Generate DDL

Please execute the ddlctl command as follows:

$ ddlctl generate --dialect postgres --go-column-tag db --go-ddl-tag pgddl --go-pk-tag pk sample.go sample.sqlINFO: 2023/11/16 16:10:39 ddlctl.go:44: source: sample.goINFO: 2023/11/16 16:10:39 ddlctl.go:73: destination: sample.sql

3. Check generated DDL file

Please check the contents of the outputted DDL:

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

Example: ddlctl diff and ddlctl apply

1. Prepare your DDL

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

2. Check diff from local DDL file to DSN

Please check the differences between the local DDL file and the destination database:

$ ddlctl diff --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sqlCREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");

3. Apply DDL

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< --CREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

4. (Optional) Edit DDL and apply

 -- pgddl:table public.users
-- pgddl:constraint UNIQUE ("username")
CREATE TABLE public.users (
"user_id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"age" INT NOT NULL,
+ "description" TEXT NOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);

apply:

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< ---- --- +"description" TEXT NOT NULLALTER TABLE public.users ADD COLUMN "description" TEXT NOT NULL;-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

Installation

pre-built binary

LATEST_VERSION=$(curl -ISs https://github.com/hakadoriya/ddlctl/releases/latest | tr -d '\r'| awk -F/ '/location:/{print $NF}')
OS=$(uname | tr '[:upper:]''[:lower:]')
ARCH=$(uname -m)
URL="https://github.com/hakadoriya/ddlctl/releases/download/${LATEST_VERSION}/ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip"# Check URLecho"${URL}"# Download
curl -fLROSs "${URL}"# Unzip
unzip -j ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip '*/ddlctl'

go install

go install github.com/hakadoriya/ddlctl/cmd/ddlctl@latest

Usage

ddlctl

$ ddlctl --helpUsage: ddlctl [options]Description: ddlctl is a tool for control RDBMS DDL.sub commands: version: show version generate: generate DDL from source (file or directory) to destination (file or directory). show: show DDL from DSN like `SHOW CREATE TABLE`. diff: diff DDL from <before DDL source> to <after DDL source>. apply: apply DDL from <DDL source> to <DSN to apply>.options: --trace (env: DDLCTL_TRACE, default: false) trace mode enabled --debug (env: DDLCTL_DEBUG, default: false) debug mode --help (default: false) show usage

ddlctl generate

$ ddlctl generate --helpUsage: ddlctl generate [options] --dialect <DDL dialect> <source> <destination>Description: generate DDL from source (file or directory) to destination (file or directory).options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl show

$ ddlctl show --helpUsage: ddlctl show --dialect <DDL dialect> <DSN>Description: show DDL from DSN like `SHOW CREATE TABLE`.options: --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --help (default: false) show usage

ddlctl diff

$ ddlctl diff --helpUsage: ddlctl diff [options] --dialect <DDL dialect> <before DDL source> <after DDL source>Description: diff DDL from <before DDL source> to <after DDL source>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl apply

$ ddlctl apply --helpUsage: ddlctl apply [options] --dialect <DDL dialect> <DSN to apply> <DDL source>Description: apply DDL from <DDL source> to <DSN to apply>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --auto-approve (env: DDLCTL_AUTO_APPROVE, default: false) auto approve --help (default: false) show usage

About

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Warning

This project is experimental. It is operational in the author's environment, but it is not known if it can be operated in other environments without trouble.

licensepkggoreportcardworkflowworkflowworkflowcodecovsourcegraph

Demo

ddlctl_demo

Overview

ddlctl can do the following:

  • Output all RDBMS DDLs
  • Generate DDL from tagged Golang source code
  • Output differences between the RDBMS and your DDL
  • Automated Migration

TODO

  • generate subcommand
    • source language
      • Support go (beta)
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • show subcommand
    • dialect
      • Support mysql (beta)
      • Support postgres (alpha)
      • Support cockroachdb (beta)
      • Support spanner (alpha)
      • Support sqlite3
  • diff subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • apply subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3

Example: ddlctl generate

1. Prepare your annotated model source code

For example, prepare the following Go code:

package sample
// User is a user model struct.////pgddl:table public.users//pgddl:constraint UNIQUE ("username")//pgddl:index "index_users_username" ON public.users ("username")typeUserstruct {
UserIDstring`db:"user_id" pgddl:"TEXT NOT NULL" pk:"true"`Usernamestring`db:"username" pgddl:"TEXT NOT NULL"`Ageint`db:"age" pgddl:"INT NOT NULL"`
}
// Group is a group model struct.////pgddl:table CREATE TABLE IF NOT EXISTS public.groups//pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")typeGroupstruct {
GroupIDstring`db:"group_id" pgddl:"TEXT NOT NULL" pk:"true"`GroupNamestring`db:"group_name" pgddl:"TEXT NOT NULL"`Descriptionstring`db:"description" pgddl:"TEXT NOT NULL"`
}

2. Generate DDL

Please execute the ddlctl command as follows:

$ ddlctl generate --dialect postgres --go-column-tag db --go-ddl-tag pgddl --go-pk-tag pk sample.go sample.sqlINFO: 2023/11/16 16:10:39 ddlctl.go:44: source: sample.goINFO: 2023/11/16 16:10:39 ddlctl.go:73: destination: sample.sql

3. Check generated DDL file

Please check the contents of the outputted DDL:

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

Example: ddlctl diff and ddlctl apply

1. Prepare your DDL

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

2. Check diff from local DDL file to DSN

Please check the differences between the local DDL file and the destination database:

$ ddlctl diff --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sqlCREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");

3. Apply DDL

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< --CREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

4. (Optional) Edit DDL and apply

 -- pgddl:table public.users
-- pgddl:constraint UNIQUE ("username")
CREATE TABLE public.users (
"user_id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"age" INT NOT NULL,
+ "description" TEXT NOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);

apply:

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< ---- --- +"description" TEXT NOT NULLALTER TABLE public.users ADD COLUMN "description" TEXT NOT NULL;-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

Installation

pre-built binary

LATEST_VERSION=$(curl -ISs https://github.com/hakadoriya/ddlctl/releases/latest | tr -d '\r'| awk -F/ '/location:/{print $NF}')
OS=$(uname | tr '[:upper:]''[:lower:]')
ARCH=$(uname -m)
URL="https://github.com/hakadoriya/ddlctl/releases/download/${LATEST_VERSION}/ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip"# Check URLecho"${URL}"# Download
curl -fLROSs "${URL}"# Unzip
unzip -j ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip '*/ddlctl'

go install

go install github.com/hakadoriya/ddlctl/cmd/ddlctl@latest

Usage

ddlctl

$ ddlctl --helpUsage: ddlctl [options]Description: ddlctl is a tool for control RDBMS DDL.sub commands: version: show version generate: generate DDL from source (file or directory) to destination (file or directory). show: show DDL from DSN like `SHOW CREATE TABLE`. diff: diff DDL from <before DDL source> to <after DDL source>. apply: apply DDL from <DDL source> to <DSN to apply>.options: --trace (env: DDLCTL_TRACE, default: false) trace mode enabled --debug (env: DDLCTL_DEBUG, default: false) debug mode --help (default: false) show usage

ddlctl generate

$ ddlctl generate --helpUsage: ddlctl generate [options] --dialect <DDL dialect> <source> <destination>Description: generate DDL from source (file or directory) to destination (file or directory).options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl show

$ ddlctl show --helpUsage: ddlctl show --dialect <DDL dialect> <DSN>Description: show DDL from DSN like `SHOW CREATE TABLE`.options: --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --help (default: false) show usage

ddlctl diff

$ ddlctl diff --helpUsage: ddlctl diff [options] --dialect <DDL dialect> <before DDL source> <after DDL source>Description: diff DDL from <before DDL source> to <after DDL source>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl apply

$ ddlctl apply --helpUsage: ddlctl apply [options] --dialect <DDL dialect> <DSN to apply> <DDL source>Description: apply DDL from <DDL source> to <DSN to apply>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --auto-approve (env: DDLCTL_AUTO_APPROVE, default: false) auto approve --help (default: false) show usage

About

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Warning

This project is experimental. It is operational in the author's environment, but it is not known if it can be operated in other environments without trouble.

licensepkggoreportcardworkflowworkflowworkflowcodecovsourcegraph

Demo

ddlctl_demo

Overview

ddlctl can do the following:

  • Output all RDBMS DDLs
  • Generate DDL from tagged Golang source code
  • Output differences between the RDBMS and your DDL
  • Automated Migration

TODO

  • generate subcommand
    • source language
      • Support go (beta)
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • show subcommand
    • dialect
      • Support mysql (beta)
      • Support postgres (alpha)
      • Support cockroachdb (beta)
      • Support spanner (alpha)
      • Support sqlite3
  • diff subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • apply subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3

Example: ddlctl generate

1. Prepare your annotated model source code

For example, prepare the following Go code:

package sample
// User is a user model struct.////pgddl:table public.users//pgddl:constraint UNIQUE ("username")//pgddl:index "index_users_username" ON public.users ("username")typeUserstruct {
UserIDstring`db:"user_id" pgddl:"TEXT NOT NULL" pk:"true"`Usernamestring`db:"username" pgddl:"TEXT NOT NULL"`Ageint`db:"age" pgddl:"INT NOT NULL"`
}
// Group is a group model struct.////pgddl:table CREATE TABLE IF NOT EXISTS public.groups//pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")typeGroupstruct {
GroupIDstring`db:"group_id" pgddl:"TEXT NOT NULL" pk:"true"`GroupNamestring`db:"group_name" pgddl:"TEXT NOT NULL"`Descriptionstring`db:"description" pgddl:"TEXT NOT NULL"`
}

2. Generate DDL

Please execute the ddlctl command as follows:

$ ddlctl generate --dialect postgres --go-column-tag db --go-ddl-tag pgddl --go-pk-tag pk sample.go sample.sqlINFO: 2023/11/16 16:10:39 ddlctl.go:44: source: sample.goINFO: 2023/11/16 16:10:39 ddlctl.go:73: destination: sample.sql

3. Check generated DDL file

Please check the contents of the outputted DDL:

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

Example: ddlctl diff and ddlctl apply

1. Prepare your DDL

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

2. Check diff from local DDL file to DSN

Please check the differences between the local DDL file and the destination database:

$ ddlctl diff --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sqlCREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");

3. Apply DDL

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< --CREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

4. (Optional) Edit DDL and apply

 -- pgddl:table public.users
-- pgddl:constraint UNIQUE ("username")
CREATE TABLE public.users (
"user_id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"age" INT NOT NULL,
+ "description" TEXT NOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);

apply:

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< ---- --- +"description" TEXT NOT NULLALTER TABLE public.users ADD COLUMN "description" TEXT NOT NULL;-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

Installation

pre-built binary

LATEST_VERSION=$(curl -ISs https://github.com/hakadoriya/ddlctl/releases/latest | tr -d '\r'| awk -F/ '/location:/{print $NF}')
OS=$(uname | tr '[:upper:]''[:lower:]')
ARCH=$(uname -m)
URL="https://github.com/hakadoriya/ddlctl/releases/download/${LATEST_VERSION}/ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip"# Check URLecho"${URL}"# Download
curl -fLROSs "${URL}"# Unzip
unzip -j ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip '*/ddlctl'

go install

go install github.com/hakadoriya/ddlctl/cmd/ddlctl@latest

Usage

ddlctl

$ ddlctl --helpUsage: ddlctl [options]Description: ddlctl is a tool for control RDBMS DDL.sub commands: version: show version generate: generate DDL from source (file or directory) to destination (file or directory). show: show DDL from DSN like `SHOW CREATE TABLE`. diff: diff DDL from <before DDL source> to <after DDL source>. apply: apply DDL from <DDL source> to <DSN to apply>.options: --trace (env: DDLCTL_TRACE, default: false) trace mode enabled --debug (env: DDLCTL_DEBUG, default: false) debug mode --help (default: false) show usage

ddlctl generate

$ ddlctl generate --helpUsage: ddlctl generate [options] --dialect <DDL dialect> <source> <destination>Description: generate DDL from source (file or directory) to destination (file or directory).options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl show

$ ddlctl show --helpUsage: ddlctl show --dialect <DDL dialect> <DSN>Description: show DDL from DSN like `SHOW CREATE TABLE`.options: --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --help (default: false) show usage

ddlctl diff

$ ddlctl diff --helpUsage: ddlctl diff [options] --dialect <DDL dialect> <before DDL source> <after DDL source>Description: diff DDL from <before DDL source> to <after DDL source>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl apply

$ ddlctl apply --helpUsage: ddlctl apply [options] --dialect <DDL dialect> <DSN to apply> <DDL source>Description: apply DDL from <DDL source> to <DSN to apply>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --auto-approve (env: DDLCTL_AUTO_APPROVE, default: false) auto approve --help (default: false) show usage

About

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Warning

This project is experimental. It is operational in the author's environment, but it is not known if it can be operated in other environments without trouble.

licensepkggoreportcardworkflowworkflowworkflowcodecovsourcegraph

Demo

ddlctl_demo

Overview

ddlctl can do the following:

  • Output all RDBMS DDLs
  • Generate DDL from tagged Golang source code
  • Output differences between the RDBMS and your DDL
  • Automated Migration

TODO

  • generate subcommand
    • source language
      • Support go (beta)
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • show subcommand
    • dialect
      • Support mysql (beta)
      • Support postgres (alpha)
      • Support cockroachdb (beta)
      • Support spanner (alpha)
      • Support sqlite3
  • diff subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • apply subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3

Example: ddlctl generate

1. Prepare your annotated model source code

For example, prepare the following Go code:

package sample
// User is a user model struct.////pgddl:table public.users//pgddl:constraint UNIQUE ("username")//pgddl:index "index_users_username" ON public.users ("username")typeUserstruct {
UserIDstring`db:"user_id" pgddl:"TEXT NOT NULL" pk:"true"`Usernamestring`db:"username" pgddl:"TEXT NOT NULL"`Ageint`db:"age" pgddl:"INT NOT NULL"`
}
// Group is a group model struct.////pgddl:table CREATE TABLE IF NOT EXISTS public.groups//pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")typeGroupstruct {
GroupIDstring`db:"group_id" pgddl:"TEXT NOT NULL" pk:"true"`GroupNamestring`db:"group_name" pgddl:"TEXT NOT NULL"`Descriptionstring`db:"description" pgddl:"TEXT NOT NULL"`
}

2. Generate DDL

Please execute the ddlctl command as follows:

$ ddlctl generate --dialect postgres --go-column-tag db --go-ddl-tag pgddl --go-pk-tag pk sample.go sample.sqlINFO: 2023/11/16 16:10:39 ddlctl.go:44: source: sample.goINFO: 2023/11/16 16:10:39 ddlctl.go:73: destination: sample.sql

3. Check generated DDL file

Please check the contents of the outputted DDL:

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

Example: ddlctl diff and ddlctl apply

1. Prepare your DDL

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

2. Check diff from local DDL file to DSN

Please check the differences between the local DDL file and the destination database:

$ ddlctl diff --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sqlCREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");

3. Apply DDL

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< --CREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

4. (Optional) Edit DDL and apply

 -- pgddl:table public.users
-- pgddl:constraint UNIQUE ("username")
CREATE TABLE public.users (
"user_id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"age" INT NOT NULL,
+ "description" TEXT NOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);

apply:

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< ---- --- +"description" TEXT NOT NULLALTER TABLE public.users ADD COLUMN "description" TEXT NOT NULL;-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

Installation

pre-built binary

LATEST_VERSION=$(curl -ISs https://github.com/hakadoriya/ddlctl/releases/latest | tr -d '\r'| awk -F/ '/location:/{print $NF}')
OS=$(uname | tr '[:upper:]''[:lower:]')
ARCH=$(uname -m)
URL="https://github.com/hakadoriya/ddlctl/releases/download/${LATEST_VERSION}/ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip"# Check URLecho"${URL}"# Download
curl -fLROSs "${URL}"# Unzip
unzip -j ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip '*/ddlctl'

go install

go install github.com/hakadoriya/ddlctl/cmd/ddlctl@latest

Usage

ddlctl

$ ddlctl --helpUsage: ddlctl [options]Description: ddlctl is a tool for control RDBMS DDL.sub commands: version: show version generate: generate DDL from source (file or directory) to destination (file or directory). show: show DDL from DSN like `SHOW CREATE TABLE`. diff: diff DDL from <before DDL source> to <after DDL source>. apply: apply DDL from <DDL source> to <DSN to apply>.options: --trace (env: DDLCTL_TRACE, default: false) trace mode enabled --debug (env: DDLCTL_DEBUG, default: false) debug mode --help (default: false) show usage

ddlctl generate

$ ddlctl generate --helpUsage: ddlctl generate [options] --dialect <DDL dialect> <source> <destination>Description: generate DDL from source (file or directory) to destination (file or directory).options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl show

$ ddlctl show --helpUsage: ddlctl show --dialect <DDL dialect> <DSN>Description: show DDL from DSN like `SHOW CREATE TABLE`.options: --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --help (default: false) show usage

ddlctl diff

$ ddlctl diff --helpUsage: ddlctl diff [options] --dialect <DDL dialect> <before DDL source> <after DDL source>Description: diff DDL from <before DDL source> to <after DDL source>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl apply

$ ddlctl apply --helpUsage: ddlctl apply [options] --dialect <DDL dialect> <DSN to apply> <DDL source>Description: apply DDL from <DDL source> to <DSN to apply>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --auto-approve (env: DDLCTL_AUTO_APPROVE, default: false) auto approve --help (default: false) show usage

About

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Warning

This project is experimental. It is operational in the author's environment, but it is not known if it can be operated in other environments without trouble.

licensepkggoreportcardworkflowworkflowworkflowcodecovsourcegraph

Demo

ddlctl_demo

Overview

ddlctl can do the following:

  • Output all RDBMS DDLs
  • Generate DDL from tagged Golang source code
  • Output differences between the RDBMS and your DDL
  • Automated Migration

TODO

  • generate subcommand
    • source language
      • Support go (beta)
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • show subcommand
    • dialect
      • Support mysql (beta)
      • Support postgres (alpha)
      • Support cockroachdb (beta)
      • Support spanner (alpha)
      • Support sqlite3
  • diff subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • apply subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3

Example: ddlctl generate

1. Prepare your annotated model source code

For example, prepare the following Go code:

package sample
// User is a user model struct.////pgddl:table public.users//pgddl:constraint UNIQUE ("username")//pgddl:index "index_users_username" ON public.users ("username")typeUserstruct {
UserIDstring`db:"user_id" pgddl:"TEXT NOT NULL" pk:"true"`Usernamestring`db:"username" pgddl:"TEXT NOT NULL"`Ageint`db:"age" pgddl:"INT NOT NULL"`
}
// Group is a group model struct.////pgddl:table CREATE TABLE IF NOT EXISTS public.groups//pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")typeGroupstruct {
GroupIDstring`db:"group_id" pgddl:"TEXT NOT NULL" pk:"true"`GroupNamestring`db:"group_name" pgddl:"TEXT NOT NULL"`Descriptionstring`db:"description" pgddl:"TEXT NOT NULL"`
}

2. Generate DDL

Please execute the ddlctl command as follows:

$ ddlctl generate --dialect postgres --go-column-tag db --go-ddl-tag pgddl --go-pk-tag pk sample.go sample.sqlINFO: 2023/11/16 16:10:39 ddlctl.go:44: source: sample.goINFO: 2023/11/16 16:10:39 ddlctl.go:73: destination: sample.sql

3. Check generated DDL file

Please check the contents of the outputted DDL:

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

Example: ddlctl diff and ddlctl apply

1. Prepare your DDL

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

2. Check diff from local DDL file to DSN

Please check the differences between the local DDL file and the destination database:

$ ddlctl diff --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sqlCREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");

3. Apply DDL

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< --CREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

4. (Optional) Edit DDL and apply

 -- pgddl:table public.users
-- pgddl:constraint UNIQUE ("username")
CREATE TABLE public.users (
"user_id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"age" INT NOT NULL,
+ "description" TEXT NOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);

apply:

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< ---- --- +"description" TEXT NOT NULLALTER TABLE public.users ADD COLUMN "description" TEXT NOT NULL;-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

Installation

pre-built binary

LATEST_VERSION=$(curl -ISs https://github.com/hakadoriya/ddlctl/releases/latest | tr -d '\r'| awk -F/ '/location:/{print $NF}')
OS=$(uname | tr '[:upper:]''[:lower:]')
ARCH=$(uname -m)
URL="https://github.com/hakadoriya/ddlctl/releases/download/${LATEST_VERSION}/ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip"# Check URLecho"${URL}"# Download
curl -fLROSs "${URL}"# Unzip
unzip -j ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip '*/ddlctl'

go install

go install github.com/hakadoriya/ddlctl/cmd/ddlctl@latest

Usage

ddlctl

$ ddlctl --helpUsage: ddlctl [options]Description: ddlctl is a tool for control RDBMS DDL.sub commands: version: show version generate: generate DDL from source (file or directory) to destination (file or directory). show: show DDL from DSN like `SHOW CREATE TABLE`. diff: diff DDL from <before DDL source> to <after DDL source>. apply: apply DDL from <DDL source> to <DSN to apply>.options: --trace (env: DDLCTL_TRACE, default: false) trace mode enabled --debug (env: DDLCTL_DEBUG, default: false) debug mode --help (default: false) show usage

ddlctl generate

$ ddlctl generate --helpUsage: ddlctl generate [options] --dialect <DDL dialect> <source> <destination>Description: generate DDL from source (file or directory) to destination (file or directory).options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl show

$ ddlctl show --helpUsage: ddlctl show --dialect <DDL dialect> <DSN>Description: show DDL from DSN like `SHOW CREATE TABLE`.options: --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --help (default: false) show usage

ddlctl diff

$ ddlctl diff --helpUsage: ddlctl diff [options] --dialect <DDL dialect> <before DDL source> <after DDL source>Description: diff DDL from <before DDL source> to <after DDL source>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl apply

$ ddlctl apply --helpUsage: ddlctl apply [options] --dialect <DDL dialect> <DSN to apply> <DDL source>Description: apply DDL from <DDL source> to <DSN to apply>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --auto-approve (env: DDLCTL_AUTO_APPROVE, default: false) auto approve --help (default: false) show usage

About

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Warning

This project is experimental. It is operational in the author's environment, but it is not known if it can be operated in other environments without trouble.

licensepkggoreportcardworkflowworkflowworkflowcodecovsourcegraph

Demo

ddlctl_demo

Overview

ddlctl can do the following:

  • Output all RDBMS DDLs
  • Generate DDL from tagged Golang source code
  • Output differences between the RDBMS and your DDL
  • Automated Migration

TODO

  • generate subcommand
    • source language
      • Support go (beta)
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • show subcommand
    • dialect
      • Support mysql (beta)
      • Support postgres (alpha)
      • Support cockroachdb (beta)
      • Support spanner (alpha)
      • Support sqlite3
  • diff subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • apply subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3

Example: ddlctl generate

1. Prepare your annotated model source code

For example, prepare the following Go code:

package sample
// User is a user model struct.////pgddl:table public.users//pgddl:constraint UNIQUE ("username")//pgddl:index "index_users_username" ON public.users ("username")typeUserstruct {
UserIDstring`db:"user_id" pgddl:"TEXT NOT NULL" pk:"true"`Usernamestring`db:"username" pgddl:"TEXT NOT NULL"`Ageint`db:"age" pgddl:"INT NOT NULL"`
}
// Group is a group model struct.////pgddl:table CREATE TABLE IF NOT EXISTS public.groups//pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")typeGroupstruct {
GroupIDstring`db:"group_id" pgddl:"TEXT NOT NULL" pk:"true"`GroupNamestring`db:"group_name" pgddl:"TEXT NOT NULL"`Descriptionstring`db:"description" pgddl:"TEXT NOT NULL"`
}

2. Generate DDL

Please execute the ddlctl command as follows:

$ ddlctl generate --dialect postgres --go-column-tag db --go-ddl-tag pgddl --go-pk-tag pk sample.go sample.sqlINFO: 2023/11/16 16:10:39 ddlctl.go:44: source: sample.goINFO: 2023/11/16 16:10:39 ddlctl.go:73: destination: sample.sql

3. Check generated DDL file

Please check the contents of the outputted DDL:

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

Example: ddlctl diff and ddlctl apply

1. Prepare your DDL

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

2. Check diff from local DDL file to DSN

Please check the differences between the local DDL file and the destination database:

$ ddlctl diff --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sqlCREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");

3. Apply DDL

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< --CREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

4. (Optional) Edit DDL and apply

 -- pgddl:table public.users
-- pgddl:constraint UNIQUE ("username")
CREATE TABLE public.users (
"user_id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"age" INT NOT NULL,
+ "description" TEXT NOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);

apply:

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< ---- --- +"description" TEXT NOT NULLALTER TABLE public.users ADD COLUMN "description" TEXT NOT NULL;-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

Installation

pre-built binary

LATEST_VERSION=$(curl -ISs https://github.com/hakadoriya/ddlctl/releases/latest | tr -d '\r'| awk -F/ '/location:/{print $NF}')
OS=$(uname | tr '[:upper:]''[:lower:]')
ARCH=$(uname -m)
URL="https://github.com/hakadoriya/ddlctl/releases/download/${LATEST_VERSION}/ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip"# Check URLecho"${URL}"# Download
curl -fLROSs "${URL}"# Unzip
unzip -j ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip '*/ddlctl'

go install

go install github.com/hakadoriya/ddlctl/cmd/ddlctl@latest

Usage

ddlctl

$ ddlctl --helpUsage: ddlctl [options]Description: ddlctl is a tool for control RDBMS DDL.sub commands: version: show version generate: generate DDL from source (file or directory) to destination (file or directory). show: show DDL from DSN like `SHOW CREATE TABLE`. diff: diff DDL from <before DDL source> to <after DDL source>. apply: apply DDL from <DDL source> to <DSN to apply>.options: --trace (env: DDLCTL_TRACE, default: false) trace mode enabled --debug (env: DDLCTL_DEBUG, default: false) debug mode --help (default: false) show usage

ddlctl generate

$ ddlctl generate --helpUsage: ddlctl generate [options] --dialect <DDL dialect> <source> <destination>Description: generate DDL from source (file or directory) to destination (file or directory).options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl show

$ ddlctl show --helpUsage: ddlctl show --dialect <DDL dialect> <DSN>Description: show DDL from DSN like `SHOW CREATE TABLE`.options: --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --help (default: false) show usage

ddlctl diff

$ ddlctl diff --helpUsage: ddlctl diff [options] --dialect <DDL dialect> <before DDL source> <after DDL source>Description: diff DDL from <before DDL source> to <after DDL source>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl apply

$ ddlctl apply --helpUsage: ddlctl apply [options] --dialect <DDL dialect> <DSN to apply> <DDL source>Description: apply DDL from <DDL source> to <DSN to apply>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --auto-approve (env: DDLCTL_AUTO_APPROVE, default: false) auto approve --help (default: false) show usage

About

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Warning

This project is experimental. It is operational in the author's environment, but it is not known if it can be operated in other environments without trouble.

licensepkggoreportcardworkflowworkflowworkflowcodecovsourcegraph

Demo

ddlctl_demo

Overview

ddlctl can do the following:

  • Output all RDBMS DDLs
  • Generate DDL from tagged Golang source code
  • Output differences between the RDBMS and your DDL
  • Automated Migration

TODO

  • generate subcommand
    • source language
      • Support go (beta)
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • show subcommand
    • dialect
      • Support mysql (beta)
      • Support postgres (alpha)
      • Support cockroachdb (beta)
      • Support spanner (alpha)
      • Support sqlite3
  • diff subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • apply subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3

Example: ddlctl generate

1. Prepare your annotated model source code

For example, prepare the following Go code:

package sample
// User is a user model struct.////pgddl:table public.users//pgddl:constraint UNIQUE ("username")//pgddl:index "index_users_username" ON public.users ("username")typeUserstruct {
UserIDstring`db:"user_id" pgddl:"TEXT NOT NULL" pk:"true"`Usernamestring`db:"username" pgddl:"TEXT NOT NULL"`Ageint`db:"age" pgddl:"INT NOT NULL"`
}
// Group is a group model struct.////pgddl:table CREATE TABLE IF NOT EXISTS public.groups//pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")typeGroupstruct {
GroupIDstring`db:"group_id" pgddl:"TEXT NOT NULL" pk:"true"`GroupNamestring`db:"group_name" pgddl:"TEXT NOT NULL"`Descriptionstring`db:"description" pgddl:"TEXT NOT NULL"`
}

2. Generate DDL

Please execute the ddlctl command as follows:

$ ddlctl generate --dialect postgres --go-column-tag db --go-ddl-tag pgddl --go-pk-tag pk sample.go sample.sqlINFO: 2023/11/16 16:10:39 ddlctl.go:44: source: sample.goINFO: 2023/11/16 16:10:39 ddlctl.go:73: destination: sample.sql

3. Check generated DDL file

Please check the contents of the outputted DDL:

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

Example: ddlctl diff and ddlctl apply

1. Prepare your DDL

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

2. Check diff from local DDL file to DSN

Please check the differences between the local DDL file and the destination database:

$ ddlctl diff --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sqlCREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");

3. Apply DDL

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< --CREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

4. (Optional) Edit DDL and apply

 -- pgddl:table public.users
-- pgddl:constraint UNIQUE ("username")
CREATE TABLE public.users (
"user_id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"age" INT NOT NULL,
+ "description" TEXT NOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);

apply:

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< ---- --- +"description" TEXT NOT NULLALTER TABLE public.users ADD COLUMN "description" TEXT NOT NULL;-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

Installation

pre-built binary

LATEST_VERSION=$(curl -ISs https://github.com/hakadoriya/ddlctl/releases/latest | tr -d '\r'| awk -F/ '/location:/{print $NF}')
OS=$(uname | tr '[:upper:]''[:lower:]')
ARCH=$(uname -m)
URL="https://github.com/hakadoriya/ddlctl/releases/download/${LATEST_VERSION}/ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip"# Check URLecho"${URL}"# Download
curl -fLROSs "${URL}"# Unzip
unzip -j ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip '*/ddlctl'

go install

go install github.com/hakadoriya/ddlctl/cmd/ddlctl@latest

Usage

ddlctl

$ ddlctl --helpUsage: ddlctl [options]Description: ddlctl is a tool for control RDBMS DDL.sub commands: version: show version generate: generate DDL from source (file or directory) to destination (file or directory). show: show DDL from DSN like `SHOW CREATE TABLE`. diff: diff DDL from <before DDL source> to <after DDL source>. apply: apply DDL from <DDL source> to <DSN to apply>.options: --trace (env: DDLCTL_TRACE, default: false) trace mode enabled --debug (env: DDLCTL_DEBUG, default: false) debug mode --help (default: false) show usage

ddlctl generate

$ ddlctl generate --helpUsage: ddlctl generate [options] --dialect <DDL dialect> <source> <destination>Description: generate DDL from source (file or directory) to destination (file or directory).options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl show

$ ddlctl show --helpUsage: ddlctl show --dialect <DDL dialect> <DSN>Description: show DDL from DSN like `SHOW CREATE TABLE`.options: --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --help (default: false) show usage

ddlctl diff

$ ddlctl diff --helpUsage: ddlctl diff [options] --dialect <DDL dialect> <before DDL source> <after DDL source>Description: diff DDL from <before DDL source> to <after DDL source>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl apply

$ ddlctl apply --helpUsage: ddlctl apply [options] --dialect <DDL dialect> <DSN to apply> <DDL source>Description: apply DDL from <DDL source> to <DSN to apply>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --auto-approve (env: DDLCTL_AUTO_APPROVE, default: false) auto approve --help (default: false) show usage

About

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Warning

This project is experimental. It is operational in the author's environment, but it is not known if it can be operated in other environments without trouble.

licensepkggoreportcardworkflowworkflowworkflowcodecovsourcegraph

Demo

ddlctl_demo

Overview

ddlctl can do the following:

  • Output all RDBMS DDLs
  • Generate DDL from tagged Golang source code
  • Output differences between the RDBMS and your DDL
  • Automated Migration

TODO

  • generate subcommand
    • source language
      • Support go (beta)
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • show subcommand
    • dialect
      • Support mysql (beta)
      • Support postgres (alpha)
      • Support cockroachdb (beta)
      • Support spanner (alpha)
      • Support sqlite3
  • diff subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3
  • apply subcommand
    • dialect
      • Support mysql (alpha)
      • Support postgres (alpha)
      • Support cockroachdb (alpha)
      • Support spanner (alpha)
      • Support sqlite3

Example: ddlctl generate

1. Prepare your annotated model source code

For example, prepare the following Go code:

package sample
// User is a user model struct.////pgddl:table public.users//pgddl:constraint UNIQUE ("username")//pgddl:index "index_users_username" ON public.users ("username")typeUserstruct {
UserIDstring`db:"user_id" pgddl:"TEXT NOT NULL" pk:"true"`Usernamestring`db:"username" pgddl:"TEXT NOT NULL"`Ageint`db:"age" pgddl:"INT NOT NULL"`
}
// Group is a group model struct.////pgddl:table CREATE TABLE IF NOT EXISTS public.groups//pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")typeGroupstruct {
GroupIDstring`db:"group_id" pgddl:"TEXT NOT NULL" pk:"true"`GroupNamestring`db:"group_name" pgddl:"TEXT NOT NULL"`Descriptionstring`db:"description" pgddl:"TEXT NOT NULL"`
}

2. Generate DDL

Please execute the ddlctl command as follows:

$ ddlctl generate --dialect postgres --go-column-tag db --go-ddl-tag pgddl --go-pk-tag pk sample.go sample.sqlINFO: 2023/11/16 16:10:39 ddlctl.go:44: source: sample.goINFO: 2023/11/16 16:10:39 ddlctl.go:73: destination: sample.sql

3. Check generated DDL file

Please check the contents of the outputted DDL:

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

Example: ddlctl diff and ddlctl apply

1. Prepare your DDL

cat sample.sql

content:

-- Code generated by ddlctl. DO NOT EDIT.---- source: docs/sample.go:5-- User is a user model struct.---- pgddl:table public.users-- pgddl:constraint UNIQUE ("username")CREATETABLEpublic.users (
"user_id"TEXTNOT NULL,
"username"TEXTNOT NULL,
"age"INTNOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);
-- source: docs/sample.go:7-- pgddl:index "index_users_username" ON public.users ("username")CREATEINDEX "index_users_username" ONpublic.users ("username");
-- source: docs/sample.go:16-- Group is a group model struct.---- pgddl:table CREATE TABLE IF NOT EXISTS public.groupsCREATETABLEIF NOT EXISTS public.groups (
"group_id"TEXTNOT NULL,
"group_name"TEXTNOT NULL,
"description"TEXTNOT NULL,
PRIMARY KEY ("group_id")
);
-- source: docs/sample.go:17-- pgddl:index CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name")CREATEUNIQUE INDEX "index_groups_group_name" ONpublic.groups ("group_name");

2. Check diff from local DDL file to DSN

Please check the differences between the local DDL file and the destination database:

$ ddlctl diff --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sqlCREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");

3. Apply DDL

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< --CREATE TABLE public.users ( "user_id" TEXT NOT NULL, "username" TEXT NOT NULL, "age" INT NOT NULL, CONSTRAINT users_pkey PRIMARY KEY ("user_id"), CONSTRAINT users_unique_username UNIQUE ("username"));CREATE INDEX "index_users_username" ON public.users ("username");CREATE TABLE IF NOT EXISTS public.groups ( "group_id" TEXT NOT NULL, "group_name" TEXT NOT NULL, "description" TEXT NOT NULL, CONSTRAINT groups_pkey PRIMARY KEY ("group_id"));CREATE UNIQUE INDEX "index_groups_group_name" ON public.groups ("group_name");-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

4. (Optional) Edit DDL and apply

 -- pgddl:table public.users
-- pgddl:constraint UNIQUE ("username")
CREATE TABLE public.users (
"user_id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"age" INT NOT NULL,
+ "description" TEXT NOT NULL,
PRIMARY KEY ("user_id"),
UNIQUE ("username")
);

apply:

$ ddlctl apply --dialect postgres "postgres://postgres:password@localhost/testdb?sslmode=disable" sample.sql --auto-approveddlctl will exec the following DDL queries:-- 8< ---- --- +"description" TEXT NOT NULLALTER TABLE public.users ADD COLUMN "description" TEXT NOT NULL;-- >8 --Do you want to apply these DDL queries? ddlctl will exec the DDL queries described above. Only 'yes' will be accepted to approve.Enter a value: yes (via --auto-approve option)executing...done

Installation

pre-built binary

LATEST_VERSION=$(curl -ISs https://github.com/hakadoriya/ddlctl/releases/latest | tr -d '\r'| awk -F/ '/location:/{print $NF}')
OS=$(uname | tr '[:upper:]''[:lower:]')
ARCH=$(uname -m)
URL="https://github.com/hakadoriya/ddlctl/releases/download/${LATEST_VERSION}/ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip"# Check URLecho"${URL}"# Download
curl -fLROSs "${URL}"# Unzip
unzip -j ddlctl_${LATEST_VERSION}_${OS}_${ARCH}.zip '*/ddlctl'

go install

go install github.com/hakadoriya/ddlctl/cmd/ddlctl@latest

Usage

ddlctl

$ ddlctl --helpUsage: ddlctl [options]Description: ddlctl is a tool for control RDBMS DDL.sub commands: version: show version generate: generate DDL from source (file or directory) to destination (file or directory). show: show DDL from DSN like `SHOW CREATE TABLE`. diff: diff DDL from <before DDL source> to <after DDL source>. apply: apply DDL from <DDL source> to <DSN to apply>.options: --trace (env: DDLCTL_TRACE, default: false) trace mode enabled --debug (env: DDLCTL_DEBUG, default: false) debug mode --help (default: false) show usage

ddlctl generate

$ ddlctl generate --helpUsage: ddlctl generate [options] --dialect <DDL dialect> <source> <destination>Description: generate DDL from source (file or directory) to destination (file or directory).options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl show

$ ddlctl show --helpUsage: ddlctl show --dialect <DDL dialect> <DSN>Description: show DDL from DSN like `SHOW CREATE TABLE`.options: --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --help (default: false) show usage

ddlctl diff

$ ddlctl diff --helpUsage: ddlctl diff [options] --dialect <DDL dialect> <before DDL source> <after DDL source>Description: diff DDL from <before DDL source> to <after DDL source>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --help (default: false) show usage

ddlctl apply

$ ddlctl apply --helpUsage: ddlctl apply [options] --dialect <DDL dialect> <DSN to apply> <DDL source>Description: apply DDL from <DDL source> to <DSN to apply>.options: --lang (env: DDLCTL_LANGUAGE, default: go) programming language to generate DDL --dialect (env: DDLCTL_DIALECT, default: ) SQL dialect to generate DDL --go-column-tag (env: DDLCTL_GO_COLUMN_TAG, default: db) column annotation key for Go struct tag --go-ddl-tag (env: DDLCTL_GO_DDL_TAG, default: ddlctl) DDL annotation key for Go struct tag --go-pk-tag (env: DDLCTL_GO_PK_TAG, default: pk) primary key annotation key for Go struct tag --auto-approve (env: DDLCTL_AUTO_APPROVE, default: false) auto approve --help (default: false) show usage

About

ddlctl is a tool to control RDBMS DDLs: output all RDBMS DDLs, generate DDLs from tagged Golang source code, view differences between RDBMS and your DDL, and automate migrations.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages