Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gormschema: support customize JoinTable #40

Merged
merged 9 commits into from
Apr 25, 2024
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,8 @@ The provider supports the following databases:

* **Foreign key constraints not generated correctly** -
If a [Customize JoinTable](https://gorm.io/docs/many_to_many.html#Customize-JoinTable) is defined in the schema,
you need to use the provider as a [Go Program](#as-go-file) and pass to the `Load` method the tables in their dependency order. i.e.,
Join tables after their parent tables.

you need to use the provider as a [Go Program](#as-go-file) and set it up using the `BeforeAutoMigrate` option.

for example if those are your models:
```go
type Person struct {
Expand All @@ -210,7 +209,11 @@ The provider supports the following databases:

you should use the following code:
```go
stmts, err := gormschema.New("mysql").Load(&models.Person{}, &models.Address{}, &models.PersonAddress{})
stmts, err := gormschema.New("mysql")
.BeforeAutoMigrate( func(db *gorm.DB) {
db.SetupJoinTable(&customjointable.Person{}, "Addresses", &customjointable.PersonAddress{})
})
.Load(&models.Person{}, &models.Address{})
```

### License
Expand Down
18 changes: 13 additions & 5 deletions gormschema/gorm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"database/sql/driver"
"errors"
"fmt"
"slices"

"ariga.io/atlas-go-sdk/recordriver"
"gorm.io/driver/mysql"
Expand All @@ -28,8 +27,9 @@ func New(dialect string, opts ...Option) *Loader {
type (
// Loader is a Loader for gorm schema.
Loader struct {
dialect string
config *gorm.Config
dialect string
config *gorm.Config
beforeAutoMigrate func(*gorm.DB)
}
// Option configures the Loader.
Option func(*Loader)
Expand Down Expand Up @@ -85,6 +85,11 @@ func (l *Loader) Load(models ...any) (string, error) {
if l.dialect != "sqlite" {
db.Config.DisableForeignKeyConstraintWhenMigrating = true
}

if l.beforeAutoMigrate != nil {
l.beforeAutoMigrate(db)
}

if err = db.AutoMigrate(models...); err != nil {
return "", err
}
Expand Down Expand Up @@ -140,8 +145,6 @@ func (m *migrator) HasTable(dst any) bool {

// CreateConstraints detects constraints on the given model and creates them using `m.dialectMigrator`.
func (m *migrator) CreateConstraints(models []any) error {
// Reverse the order of models to ensure many 2 many tables constraints are created first, assuming they are at the end.
slices.Reverse(models)
for _, model := range m.ReorderModels(models, true) {
err := m.Migrator.RunWithValue(model, func(stmt *gorm.Statement) error {
for _, rel := range stmt.Schema.Relationships.Relations {
Expand All @@ -163,3 +166,8 @@ func (m *migrator) CreateConstraints(models []any) error {
}
return nil
}

func (l *Loader) BeforeAutoMigrate(cb func(*gorm.DB)) *Loader {
l.beforeAutoMigrate = cb
return l
}
luantranminh marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion gormschema/gorm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func TestMySQLConfig(t *testing.T) {
requireEqualContent(t, sql, "testdata/mysql_no_fk")
resetSession()
l = New("mysql")
sql, err = l.Load(customjointable.Address{}, customjointable.Person{}, customjointable.PersonAddress{})
sql, err = l.Load(customjointable.Address{}, customjointable.Person{})
require.NoError(t, err)
requireEqualContent(t, sql, "testdata/mysql_custom_join_table")
}
Expand Down
4 changes: 2 additions & 2 deletions gormschema/testdata/mysql_default
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ CREATE TABLE `events` (`eventId` varchar(191),`locationId` varchar(191),PRIMARY
CREATE TABLE `locations` (`locationId` varchar(191),`eventId` varchar(191),PRIMARY KEY (`locationId`),UNIQUE INDEX `idx_locations_event_id` (`eventId`));
CREATE TABLE `users` (`id` bigint unsigned AUTO_INCREMENT,`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL,`deleted_at` datetime(3) NULL,`name` longtext,PRIMARY KEY (`id`),INDEX `idx_users_deleted_at` (`deleted_at`));
CREATE TABLE `pets` (`id` bigint unsigned AUTO_INCREMENT,`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL,`deleted_at` datetime(3) NULL,`name` longtext,`user_id` bigint unsigned,PRIMARY KEY (`id`),INDEX `idx_pets_deleted_at` (`deleted_at`));
ALTER TABLE `pets` ADD CONSTRAINT `fk_users_pets` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`);
ALTER TABLE `locations` ADD CONSTRAINT `fk_events_location` FOREIGN KEY (`eventId`) REFERENCES `events`(`eventId`);
ALTER TABLE `events` ADD CONSTRAINT `fk_locations_event` FOREIGN KEY (`locationId`) REFERENCES `locations`(`locationId`);
ALTER TABLE `locations` ADD CONSTRAINT `fk_events_location` FOREIGN KEY (`eventId`) REFERENCES `events`(`eventId`);
ALTER TABLE `pets` ADD CONSTRAINT `fk_users_pets` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`);
4 changes: 2 additions & 2 deletions gormschema/testdata/postgresql_default
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ CREATE TABLE "users" ("id" bigserial,"created_at" timestamptz,"updated_at" times
CREATE INDEX IF NOT EXISTS "idx_users_deleted_at" ON "users" ("deleted_at");
CREATE TABLE "pets" ("id" bigserial,"created_at" timestamptz,"updated_at" timestamptz,"deleted_at" timestamptz,"name" text,"user_id" bigint,PRIMARY KEY ("id"));
CREATE INDEX IF NOT EXISTS "idx_pets_deleted_at" ON "pets" ("deleted_at");
ALTER TABLE "pets" ADD CONSTRAINT "fk_users_pets" FOREIGN KEY ("user_id") REFERENCES "users"("id");
ALTER TABLE "locations" ADD CONSTRAINT "fk_events_location" FOREIGN KEY ("eventId") REFERENCES "events"("eventId");
ALTER TABLE "events" ADD CONSTRAINT "fk_locations_event" FOREIGN KEY ("locationId") REFERENCES "locations"("locationId");
ALTER TABLE "locations" ADD CONSTRAINT "fk_events_location" FOREIGN KEY ("eventId") REFERENCES "events"("eventId");
ALTER TABLE "pets" ADD CONSTRAINT "fk_users_pets" FOREIGN KEY ("user_id") REFERENCES "users"("id");
4 changes: 2 additions & 2 deletions gormschema/testdata/sqlserver_default
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ CREATE TABLE "users" ("id" bigint IDENTITY(1,1),"created_at" datetimeoffset,"upd
CREATE INDEX "idx_users_deleted_at" ON "users"("deleted_at");
CREATE TABLE "pets" ("id" bigint IDENTITY(1,1),"created_at" datetimeoffset,"updated_at" datetimeoffset,"deleted_at" datetimeoffset,"name" nvarchar(MAX),"user_id" bigint,PRIMARY KEY ("id"));
CREATE INDEX "idx_pets_deleted_at" ON "pets"("deleted_at");
ALTER TABLE "pets" ADD CONSTRAINT "fk_users_pets" FOREIGN KEY ("user_id") REFERENCES "users"("id");
ALTER TABLE "locations" ADD CONSTRAINT "fk_events_location" FOREIGN KEY ("eventId") REFERENCES "events"("eventId");
ALTER TABLE "events" ADD CONSTRAINT "fk_locations_event" FOREIGN KEY ("locationId") REFERENCES "locations"("locationId");
ALTER TABLE "locations" ADD CONSTRAINT "fk_events_location" FOREIGN KEY ("eventId") REFERENCES "events"("eventId");
ALTER TABLE "pets" ADD CONSTRAINT "fk_users_pets" FOREIGN KEY ("user_id") REFERENCES "users"("id");