🔖

Golang+SQLBoilerでNotionにデータベース仕様書を自動生成する

2023/10/01に公開

出来上がるもの

コードサンプル

以下にコードサンプルを配置しています。

https://github.com/ryohei-takagi/sqlboiler-notion-sample

依存ライブラリ

以下のライブラリを使用させていただきました。ありがとうございます!

https://github.com/dstotijn/go-notion

https://github.com/volatiletech/sqlboiler

コード解説

Notionライブラリの初期化

Notionライブラリのクライアントを保持しましょう。
シークレットは、以下の内容を元に取得できます。
https://www.notion.so/ja-jp/help/create-integrations-with-the-notion-api

import "github.com/dstotijn/go-notion"

type Notion struct {
	Client *notion.Client
	PageId string
}

func NewNotion(secret, pageId string) *Notion {
	return &Notion{
		Client: notion.NewClient(secret),
		PageId: pageId,
	}
}

SQLBoilerの初期化

MySQLの場合、以下のように設定できます。

Docker内にsqlboiler-mysqlがインストールされた状態が前提です。

RUN go install github.com/volatiletech/sqlboiler/v4@v4.15.0 && \
    go install github.com/volatiletech/sqlboiler/v4/drivers/sqlboiler-mysql@v4.15.0
import (
	"github.com/volatiletech/sqlboiler/v4/boilingcore"
	"github.com/volatiletech/sqlboiler/v4/drivers"
	"github.com/volatiletech/sqlboiler/v4/importers"
	"os"
)

func NewBoiler() (*boilingcore.State, error) {
	driver, _, err := drivers.RegisterBinaryFromCmdArg("mysql")
	if err != nil {
		return nil, err
	}

	state, err := boilingcore.New(&boilingcore.Config{
		DriverName: driver,
		DriverConfig: map[string]interface{}{
			"blacklist": []string{},
			"whitelist": []string{"users"}, // table name here
			"host":      os.Getenv("DB_HOST"),
			"port":      os.Getenv("DB_PORT"),
			"user":      os.Getenv("DB_USER"),
			"pass":      os.Getenv("DB_PASS"),
			"dbname":    os.Getenv("DB_NAME"),
			"sslmode":   "false",
		},
		Imports:   importers.NewDefaultImports(),
		OutFolder: "/workspace/tmp",
	})
	if err != nil {
		return nil, err
	}

	return state, nil
}

生成したいテーブル名をwhitelistに登録します。
今回は、usersテーブルを対象とします。

Notionページ作成処理

テーブルごとにNotionデータベースを作成し、カラムごとに一行ずつ追加します。

for _, table := range b.Tables {
	// Create Notion database page
	dbPage, err := n.Client.CreateDatabase(ctx, notion.CreateDatabaseParams{
		ParentPageID: n.PageId,
		Title: []notion.RichText{
			{
				Text: &notion.Text{
					Content: table.Name,
				},
			},
		},
		Description: []notion.RichText{
			{
				Text: &notion.Text{
					Content: "", // description here
				},
			},
		},
		Properties: notion.DatabaseProperties{
			"PK": notion.DatabaseProperty{
				Type:     notion.DBPropTypeCheckbox,
				Checkbox: &notion.EmptyMetadata{},
			},
			"Column": notion.DatabaseProperty{
				Type:  notion.DBPropTypeTitle,
				Title: &notion.EmptyMetadata{},
			},
			"DBType": notion.DatabaseProperty{
				Type:     notion.DBPropTypeRichText,
				RichText: &notion.EmptyMetadata{},
			},
			"Unique": notion.DatabaseProperty{
				Type:     notion.DBPropTypeCheckbox,
				Checkbox: &notion.EmptyMetadata{},
			},
			"Nullable": notion.DatabaseProperty{
				Type:     notion.DBPropTypeCheckbox,
				Checkbox: &notion.EmptyMetadata{},
			},
			"Default": notion.DatabaseProperty{
				Type:     notion.DBPropTypeRichText,
				RichText: &notion.EmptyMetadata{},
			},
			"Comment": notion.DatabaseProperty{
				Type:     notion.DBPropTypeRichText,
				RichText: &notion.EmptyMetadata{},
			},
		},
	})
	if err != nil {
		log.Fatal(err.Error())
	}

	// Update Notion database table row
	for i := range table.Columns {
		c := table.Columns[len(table.Columns)-1-i]
		column := NewColumn(c, table.PKey)

		_, err := n.Client.CreatePage(ctx, notion.CreatePageParams{
			ParentType: notion.ParentTypeDatabase,
			ParentID:   dbPage.ID,
			DatabasePageProperties: &notion.DatabasePageProperties{
				"Column": notion.DatabasePageProperty{
					Type: notion.DBPropTypeTitle,
					Title: []notion.RichText{
						{
							Text: &notion.Text{
								Content: column.Name,
							},
						},
					},
				},
				"DBType": notion.DatabasePageProperty{
					Type: notion.DBPropTypeRichText,
					RichText: []notion.RichText{
						{
							Text: &notion.Text{
								Content: column.DBType,
							},
						},
					},
				},
				"PK": notion.DatabasePageProperty{
					Type:     notion.DBPropTypeCheckbox,
					Checkbox: notion.BoolPtr(column.PK),
				},
				"Unique": notion.DatabasePageProperty{
					Type:     notion.DBPropTypeCheckbox,
					Checkbox: notion.BoolPtr(column.Unique),
				},
				"Nullable": notion.DatabasePageProperty{
					Type:     notion.DBPropTypeCheckbox,
					Checkbox: notion.BoolPtr(column.Nullable),
				},
				"Default": notion.DatabasePageProperty{
					Type: notion.DBPropTypeRichText,
					RichText: []notion.RichText{
						{
							Text: &notion.Text{
								Content: column.Default,
							},
						},
					},
				},
				"Comment": notion.DatabasePageProperty{
					Type: notion.DBPropTypeRichText,
					RichText: []notion.RichText{
						{
							Text: &notion.Text{
								Content: column.Comment,
							},
						},
					},
				},
			},
		})
		if err != nil {
			log.Fatal(err.Error())
		}
	}
}

なお、Notionは下から順番に行を追加していくので、以下の行で反転しています。

table.Columns[len(table.Columns)-1-i]

テーブル作成

サンプルのテーブルを作成します。

CREATE TABLE users (
	id INT UNSIGNED NOT NULL AUTO_INCREMENT,
	name VARCHAR(50) UNIQUE NOT NULL,
	updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
	created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
	PRIMARY KEY (id)
) DEFAULT CHARSET=utf8mb4;

実行

コマンドを実行し、Notionのページが更新されれば完了です!

$ docker compose run sqlboiler_notion_sample_go go run main.go

Discussion