{"id":13412072,"url":"https://github.com/sunary/sqlize","last_synced_at":"2026-03-01T05:14:08.443Z","repository":{"id":41265677,"uuid":"293954100","full_name":"sunary/sqlize","owner":"sunary","description":"generate SQL migration schema from golang models and the current SQL schema.","archived":false,"fork":false,"pushed_at":"2024-06-20T04:23:57.000Z","size":242,"stargazers_count":93,"open_issues_count":3,"forks_count":11,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-07-31T20:49:44.740Z","etag":null,"topics":["arvo-schema","migration","mysql","postgresql","sql-migration","sqlite"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sunary.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-08T23:51:14.000Z","updated_at":"2024-07-23T11:29:00.000Z","dependencies_parsed_at":"2024-01-30T04:07:26.189Z","dependency_job_id":"8f125496-7f37-4a48-aae1-ae3494af109f","html_url":"https://github.com/sunary/sqlize","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunary%2Fsqlize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunary%2Fsqlize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunary%2Fsqlize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunary%2Fsqlize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sunary","download_url":"https://codeload.github.com/sunary/sqlize/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235388545,"owners_count":18981945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arvo-schema","migration","mysql","postgresql","sql-migration","sqlite"],"created_at":"2024-07-30T20:01:20.734Z","updated_at":"2026-03-01T05:14:08.425Z","avatar_url":"https://github.com/sunary.png","language":"Go","readme":"# SQLize\n\n![github action](https://github.com/sunary/sqlize/actions/workflows/go.yml/badge.svg)\n\nEnglish | [中文](README_zh.md)\n\n## Purpose\n\n**SQLize** generates database migrations by comparing two schema sources: your **Go structs** (desired state) and your **existing migrations** (current state). Instead of writing migration SQL by hand, you define models in Go and SQLize produces the `ALTER TABLE`, `CREATE TABLE`, and related statements needed to bring your database up to date.\n\n### What problem does it solve?\n\n- **Manual migrations are error-prone** — Easy to forget columns, indexes, or foreign keys when writing `ALTER TABLE` by hand\n- **Schema drift** — Go models and the database can get out of sync over time\n- **Boilerplate** — Repetitive work creating up/down migrations for every schema change\n\n### How it works\n\n1. **Desired state** — Load schema from your Go structs (via `FromObjects`)\n2. **Current state** — Load schema from your migration folder (via `FromMigrationFolder`)\n3. **Diff** — SQLize compares them and computes the changes\n4. **Output** — Get migration SQL (`StringUp` / `StringDown`) or write files directly (`WriteFilesWithVersion`)\n\n```\nGo structs (desired)  ──┐\n                       ├──► Diff ──► Migration SQL (up/down)\nMigration files (current) ─┘\n```\n\n## Features\n\n- **Multi-database**: MySQL, PostgreSQL, SQLite, SQL Server\n- **ORM-friendly**: Works with struct tags (`sql`, `gorm`), compatible with `golang-migrate/migrate`\n- **Schema export**: Avro Schema (MySQL), ERD diagrams (MermaidJS)\n\n## Installation\n\n```bash\ngo get github.com/sunary/sqlize\n```\n\n## Quick Start\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/sunary/sqlize\"\n)\n\nfunc main() {\n\tmigrationFolder := \"migrations/\"\n\tsqlLatest := sqlize.NewSqlize(\n\t\tsqlize.WithSqlTag(\"sql\"),\n\t\tsqlize.WithMigrationFolder(migrationFolder),\n\t\tsqlize.WithCommentGenerate(),\n\t)\n\n\tms := YourModels() // Return your Go models\n\terr := sqlLatest.FromObjects(ms...)\n\tif err != nil {\n\t\tlog.Fatal(\"sqlize FromObjects\", err)\n\t}\n\tsqlVersion := sqlLatest.HashValue()\n\n\tsqlMigrated := sqlize.NewSqlize(sqlize.WithMigrationFolder(migrationFolder))\n\terr = sqlMigrated.FromMigrationFolder()\n\tif err != nil {\n\t\tlog.Fatal(\"sqlize FromMigrationFolder\", err)\n\t}\n\n\tsqlLatest.Diff(*sqlMigrated)\n\n\tfmt.Println(\"sql version\", sqlVersion)\n\tfmt.Println(\"\\n### migration up\")\n\tfmt.Println(sqlLatest.StringUp())\n\tfmt.Println(\"\\n### migration down\")\n\tfmt.Println(sqlLatest.StringDown())\n\n\tif len(os.Args) \u003e 1 {\n\t\terr = sqlLatest.WriteFilesWithVersion(os.Args[1], sqlVersion, false)\n\t\tif err != nil {\n\t\t\tlog.Fatal(\"sqlize WriteFilesWithVersion\", err)\n\t\t}\n\t}\n}\n```\n\n## Conventions\n\n### Default Behaviors\n\n- Database: `mysql` (use `sqlize.WithPostgresql()`, `sqlize.WithSqlite()`, etc.)\n- SQL syntax: Uppercase (use `sqlize.WithSqlLowercase()` for lowercase)\n- Table naming: Singular (use `sqlize.WithPluralTableName()` for plural)\n- Comment generation: `sqlize.WithCommentGenerate()`\n\n### SQL Tag Options\n\n- Format: Supports both `snake_case` and `camelCase` (e.g., `sql:\"primary_key\"` equals `sql:\"primaryKey\"`)\n- Custom column: `sql:\"column:column_name\"`\n- Primary key: `sql:\"primary_key\"`\n- Foreign key: `sql:\"foreign_key:user_id;references:user_id\"`\n- Auto increment: `sql:\"auto_increment\"`\n- Default value: `sql:\"default:CURRENT_TIMESTAMP\"`\n- Override datatype: `sql:\"type:VARCHAR(64)\"`\n- Ignore field: `sql:\"-\"`\n\n### Indexing\n\n- Basic index: `sql:\"index\"`\n- Custom index name: `sql:\"index:idx_col_name\"`\n- Unique index: `sql:\"unique\"`\n- Custom unique index: `sql:\"unique:idx_name\"`\n- Composite index: `sql:\"index_columns:col1,col2\"` (includes unique index and primary key)\n- Index type: `sql:\"index_type:btree\"`\n\n### Embedded Structs\n\n- Use `sql:\"embedded\"` or `sql:\"squash\"`\n- Cannot be a pointer\n- Supports prefix: `sql:\"embedded_prefix:base_\"`\n- Fields have lowest order, except for primary key (always first)\n\n### Data Types\n\n- MySQL data types are implicitly changed:\n\n```sql\nTINYINT =\u003e tinyint(4)\nINT     =\u003e int(11)\nBIGINT  =\u003e bigint(20)\n```\n\n- Pointer values must be declared in the struct or predefined data types:\n\n```golang\n// your struct\ntype Record struct {\n\tID        int\n\tDeletedAt *time.Time\n}\n\n// =\u003e\n// the struct is declared with a value\nnow := time.Now()\nRecord{DeletedAt: \u0026now}\n\n// or predefined data type\ntype Record struct {\n\tID        int\n\tDeletedAt *time.Time `sql:\"type:DATETIME\"`\n}\n\n// or using struct supported by \"database/sql\"\ntype Record struct {\n\tID        int\n\tDeletedAt sql.NullTime\n}\n```\n","funding_links":[],"categories":["Database","Data Integration Frameworks","Uncategorized","数据库","Generators"],"sub_categories":["Database Schema Migration","Advanced Console UIs","数据库模式迁移"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunary%2Fsqlize","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsunary%2Fsqlize","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunary%2Fsqlize/lists"}