Автоматически генерировать SQL-таблицу на основе Golang AST

Go SQL

Студенты, которые пишут бэкенд-бизнес, часто высмеивают, что их работа — это CRUD вокруг таблиц данных.Хотя реальная работа не так проста, в повседневной жизни действительно много похожей повторяющейся и нетворческой работы. И эту работу можно в определенной степени автоматизировать. Чтобы повысить эффективность развития персонала отдела исследований и разработок, мы некоторое время назад разработали инструмент рабочего процесса для серверной разработки, который в основном обеспечивает следующие функции:

  • Генерировать базовый код API сервера и комментарии к документации Swagger (поддерживается только фреймворк gin)
  • Сгенерировать клиентский код API сервера
  • go struct добавляет теги партиями
  • Сгенерировать структуру модели горма
  • структура модели генерирует sql

Поскольку эти функции связаны с нашей внутренней общедоступной библиотекой, исходный код всего инструмента может быть закрыт. Здесь мы беремmodel struct 生成 sqlВозьмем функцию в качестве примера, давайте поговорим о наших идеях и инструментах, использованных при создании этого инструмента.

Задача

Вот одноклассник дзинчжу, которого мы использовали в проекте.gormв виде библиотеки форм. Если вы используете другие orm-библиотеки golang, реализация должна быть аналогичной.

Наша задача определяется из этой структуры модели ниже:

Сгенерируйте оператор построения таблицы mysql (файл):

идеи

отmodel structгенерироватьsqlЯвляется将语言A翻译为语言BПроблема. Этот процесс в принципе ничем не отличается от компиляции исходного кода в бинарную исполняемую программу. Таким образом, эта проблема по существу является проблемой компиляции. Полная компиляция состоит из следующих шагов:

Для задач, которые необходимо выполнить в этой статье, в основном выполните лексический анализ, синтаксический анализ и генерацию целевого кода.

инструмент

Для лексического анализа и синтаксического анализа у нас есть древний артефактLexа такжеYacc, Yet Another Compiler-Compiler... И мы просто хотим выполнить задачу по созданию файла таблицы. Иногда пользователям приходится настраивать синтаксис двух инструментов, и им приходится писать свои собственные файлы lex и yacc. Мне это не нравится...

В Golang есть много инструментов, которым завидуют другие языки, например go pprof, go list, go vet и т. д. С точки зрения языкового метапрограммирования, в go 1.4 реализована начальная загрузка; лексический анализ и синтаксический анализ, используемые при компиляции, уже давно помещены в стандартную библиотеку.go/astсередина.ASTЭто аббревиатура от абстрактного синтаксического дерева, а дословный перевод — абстрактное синтаксическое дерево. С помощью AST мы можем написать программу для разбора исходного кода go. В зависимости от задачи, которую необходимо выполнить в этой статье, нам нужно написать программу, подобную этой, для анализа модели, определяющей таблицу данных. struct, а затем сгенерируйте оператор построения таблицы sql.

выполнить

Применительно к реализации нашей задачи ее можно разделить на следующие этапы:

  • Загрузить исходный код, сгенерировать дерево AST
  • Получить и проанализировать структуру модели AST
  • Создать create_definition, table_options на основе имени/тега поля структуры

Полная реализация кода, вы можете перейти на githubgorm2sql.

Осознайте эффект:

user_email.go:

type UserBase struct {
    UserId string `sql:"index:idx_ub"`
    Ip     string `sql:"unique_index:uniq_ip"`
}

type UserEmail struct {
    Id       int64    `gorm:"primary_key"`
    UserBase
    Email      string
    Sex        bool
    Age        int
    Score      float64
    UpdateTime time.Time `sql:"default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"`
    CreateTime time.Time `sql:"default:CURRENT_TIMESTAMP"`
}
gorm2sql sql -f user_email.go -s UserEmail -o db.sql

Result:

CREATE TABLE `user_email`
(
  `id` bigint AUTO_INCREMENT NOT NULL ,
  `user_id` varchar(128) NOT NULL ,
  `ip` varchar(128) NOT NULL ,
  `email` varchar(128) NOT NULL ,
  `sex` boolean NOT NULL ,
  `age` int NOT NULL ,
  `score` double NOT NULL ,
  `update_time` datetime NOT NULL  DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `create_time` datetime NOT NULL  DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_ub (`user_id`),
  UNIQUE INDEX uniq_ip (`ip`),
  PRIMARY KEY (`id`)
) engine=innodb DEFAULT charset=utf8mb4;

Расширенное чтение