Skip to content

Commit

Permalink
gormschema: supports Customize JoinTable for Standalone mode (#51)
Browse files Browse the repository at this point in the history
* feat: automatically detect join tables, then set them up

* tests: add test cases for join tables

* doc: update README for Customize Table

* chore: fix type

* tests: remove fks test for sqlite
  • Loading branch information
luantranminh authored Jun 10, 2024
1 parent 549f95f commit 0599721
Show file tree
Hide file tree
Showing 19 changed files with 221 additions and 31 deletions.
15 changes: 5 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,10 @@ The provider supports the following databases:

### Frequently Asked Questions

* **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 set it up using the `WithJoinTable` option.

for example if those are your models:
* **Foreign key constraints not generated correctly** - When setting up your [Go Program](#as-go-file) and using [Customize JoinTable](https://gorm.io/docs/many_to_many.html#Customize-JoinTable),
you may encounter issues with foreign key constraints. To avoid these issues, ensure that all models, including the join tables, are passed to the `Load` function.

For example if those are your models:
```go
type Person struct {
ID int
Expand All @@ -269,11 +268,7 @@ The provider supports the following databases:

you should use the following code:
```go
stmts, err := gormschema.New("mysql",
gormschema.WithJoinTable(
&Models.Person{}, "Addresses", &Models.PersonAddress{},
),
).Load(&Models.Address{}, &Models.Person{})
stmts, err := gormschema.New("mysql").Load(&Models.Address{}, &Models.Person{}, &Models.PersonAddress{})
```

### License
Expand Down
89 changes: 84 additions & 5 deletions gormschema/gorm.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,24 @@ func (l *Loader) Load(models ...any) (string, error) {
return "", err
}
}
if err = db.AutoMigrate(tables...); err != nil {
return "", err
}
db, err = gorm.Open(dialector{Dialector: di}, l.config)
cdb, err := gorm.Open(dialector{Dialector: di}, l.config)
if err != nil {
return "", err
}
cm, ok := db.Migrator().(*migrator)
cm, ok := cdb.Migrator().(*migrator)
if !ok {
return "", fmt.Errorf("unexpected migrator type: %T", db.Migrator())
}
if err = cm.setupJoinTables(tables...); err != nil {
return "", err
}
orderedTables, err := cm.orderModels(tables...)
if err != nil {
return "", err
}
if err = db.AutoMigrate(orderedTables...); err != nil {
return "", err
}
if err = cm.CreateViews(views); err != nil {
return "", err
}
Expand Down Expand Up @@ -193,6 +200,39 @@ func (m *migrator) CreateConstraints(models []any) error {
return nil
}

// setupJoinTables helps to determine custom join tables present in the model list and sets them up.
func (m *migrator) setupJoinTables(models ...any) error {
var dbNameModelMap = make(map[string]any)
for _, model := range models {
err := m.RunWithValue(model, func(stmt *gorm.Statement) error {
dbNameModelMap[stmt.Schema.Table] = model
return nil
})
if err != nil {
return err
}
}
for _, model := range m.ReorderModels(models, false) {
err := m.RunWithValue(model, func(stmt *gorm.Statement) error {
for _, rel := range stmt.Schema.Relationships.Relations {
if rel.Field.IgnoreMigration || rel.JoinTable == nil {
continue
}
if joinTable, ok := dbNameModelMap[rel.JoinTable.Name]; ok {
if err := m.DB.SetupJoinTable(model, rel.Field.Name, joinTable); err != nil {
return err
}
}
}
return nil
})
if err != nil {
return err
}
}
return nil
}

// CreateViews creates the given "view-based" models
func (m *migrator) CreateViews(views []ViewDefiner) error {
for _, view := range views {
Expand All @@ -217,6 +257,7 @@ func (m *migrator) CreateViews(views []ViewDefiner) error {
}

// WithJoinTable sets up a join table for the given model and field.
// Deprecated: put the join tables alongside the models in the Load call.
func WithJoinTable(model any, field string, jointable any) Option {
return func(l *Loader) {
l.beforeAutoMigrate = append(l.beforeAutoMigrate, func(db *gorm.DB) error {
Expand Down Expand Up @@ -269,3 +310,41 @@ func BuildStmt(fn func(db *gorm.DB) *gorm.DB) ViewOption {
b.createStmt = fmt.Sprintf("CREATE VIEW %s AS %s", b.viewName, vd)
}
}

// orderModels places join tables at the end of the list of models (if any),
// which helps GORM resolve m2m relationships correctly.
func (m *migrator) orderModels(models ...any) ([]any, error) {
var (
joinTableDBNames = make(map[string]bool)
otherTables []any
joinTables []any
)
for _, model := range models {
err := m.RunWithValue(model, func(stmt *gorm.Statement) error {
for _, rel := range stmt.Schema.Relationships.Relations {
if rel.JoinTable != nil {
joinTableDBNames[rel.JoinTable.Table] = true
return nil
}
}
return nil
})
if err != nil {
return nil, err
}
}
for _, model := range models {
err := m.RunWithValue(model, func(stmt *gorm.Statement) error {
if joinTableDBNames[stmt.Schema.Table] {
joinTables = append(joinTables, model)
} else {
otherTables = append(otherTables, model)
}
return nil
})
if err != nil {
return nil, err
}
}
return append(otherTables, joinTables...), nil
}
12 changes: 11 additions & 1 deletion gormschema/gorm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
func TestSQLiteConfig(t *testing.T) {
resetSession()
l := gormschema.New("sqlite")
sql, err := l.Load(models.WorkingAgedUsers{}, models.Pet{}, models.User{}, ckmodels.Event{}, ckmodels.Location{}, models.TopPetOwner{})
sql, err := l.Load(models.WorkingAgedUsers{}, models.Pet{}, ckmodels.Event{}, ckmodels.Location{}, models.TopPetOwner{})
require.NoError(t, err)
requireEqualContent(t, sql, "testdata/sqlite_default")
resetSession()
Expand Down Expand Up @@ -65,6 +65,16 @@ func TestMySQLConfig(t *testing.T) {
sql, err = l.Load(customjointable.Address{}, customjointable.Person{}, customjointable.TopCrowdedAddresses{})
require.NoError(t, err)
requireEqualContent(t, sql, "testdata/mysql_custom_join_table")
resetSession()
l = gormschema.New("mysql")
sql, err = l.Load(customjointable.PersonAddress{}, customjointable.Address{}, customjointable.Person{}, customjointable.TopCrowdedAddresses{})
require.NoError(t, err)
requireEqualContent(t, sql, "testdata/mysql_custom_join_table")
resetSession()
l = gormschema.New("mysql")
sql, err = l.Load(customjointable.Address{}, customjointable.PersonAddress{}, customjointable.Person{}, customjointable.TopCrowdedAddresses{})
require.NoError(t, err)
requireEqualContent(t, sql, "testdata/mysql_custom_join_table") // position of tables should not matter
}

func TestSQLServerConfig(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions gormschema/testdata/mysql_default
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
CREATE TABLE `events` (`eventId` varchar(191),`locationId` varchar(191),PRIMARY KEY (`eventId`),UNIQUE INDEX `idx_events_location_id` (`locationId`));
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,`age` bigint,PRIMARY KEY (`id`),INDEX `idx_users_deleted_at` (`deleted_at`));
CREATE TABLE `hobbies` (`id` bigint unsigned AUTO_INCREMENT,`name` longtext,PRIMARY KEY (`id`));
CREATE TABLE `user_hobbies` (`hobby_id` bigint unsigned,`user_id` bigint unsigned,PRIMARY KEY (`hobby_id`,`user_id`));
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`));
CREATE VIEW working_aged_users AS SELECT name, age FROM `users` WHERE age BETWEEN 18 AND 65;
CREATE VIEW top_pet_owners AS SELECT user_id, COUNT(id) AS pet_count FROM pets GROUP BY user_id ORDER BY pet_count DESC LIMIT 10;
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 `user_hobbies` ADD CONSTRAINT `fk_user_hobbies_hobby` FOREIGN KEY (`hobby_id`) REFERENCES `hobbies`(`id`);
ALTER TABLE `user_hobbies` ADD CONSTRAINT `fk_user_hobbies_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`);
ALTER TABLE `pets` ADD CONSTRAINT `fk_users_pets` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`);
9 changes: 9 additions & 0 deletions gormschema/testdata/mysql_deterministic_output
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CREATE TABLE `hobbies` (`id` bigint unsigned AUTO_INCREMENT,`name` longtext,PRIMARY KEY (`id`));
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,`age` bigint,PRIMARY KEY (`id`),INDEX `idx_users_deleted_at` (`deleted_at`));
CREATE TABLE `user_hobbies` (`user_id` bigint unsigned,`hobby_id` bigint unsigned,PRIMARY KEY (`user_id`,`hobby_id`));
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`));
CREATE VIEW top_pet_owners AS SELECT user_id, COUNT(id) AS pet_count FROM pets GROUP BY user_id ORDER BY pet_count DESC LIMIT 10;
CREATE VIEW working_aged_users AS SELECT name, age FROM `users` WHERE age BETWEEN 18 AND 65;
ALTER TABLE `user_hobbies` ADD CONSTRAINT `fk_user_hobbies_hobby` FOREIGN KEY (`hobby_id`) REFERENCES `hobbies`(`id`);
ALTER TABLE `user_hobbies` ADD CONSTRAINT `fk_user_hobbies_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`);
ALTER TABLE `pets` ADD CONSTRAINT `fk_users_pets` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`);
4 changes: 4 additions & 0 deletions gormschema/testdata/postgresql_default
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ CREATE TABLE "locations" ("locationId" varchar(191),"eventId" varchar(191),PRIMA
CREATE UNIQUE INDEX IF NOT EXISTS "idx_locations_event_id" ON "locations" ("eventId");
CREATE TABLE "users" ("id" bigserial,"created_at" timestamptz,"updated_at" timestamptz,"deleted_at" timestamptz,"name" text,"age" bigint,PRIMARY KEY ("id"));
CREATE INDEX IF NOT EXISTS "idx_users_deleted_at" ON "users" ("deleted_at");
CREATE TABLE "hobbies" ("id" bigserial,"name" text,PRIMARY KEY ("id"));
CREATE TABLE "user_hobbies" ("hobby_id" bigint,"user_id" bigint,PRIMARY KEY ("hobby_id","user_id"));
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");
CREATE VIEW working_aged_users AS SELECT name, age FROM "users" WHERE age BETWEEN 18 AND 65;
CREATE VIEW top_pet_owners AS SELECT user_id, COUNT(id) AS pet_count FROM pets GROUP BY user_id ORDER BY pet_count DESC LIMIT 10;
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 "user_hobbies" ADD CONSTRAINT "fk_user_hobbies_hobby" FOREIGN KEY ("hobby_id") REFERENCES "hobbies"("id");
ALTER TABLE "user_hobbies" ADD CONSTRAINT "fk_user_hobbies_user" FOREIGN KEY ("user_id") REFERENCES "users"("id");
ALTER TABLE "pets" ADD CONSTRAINT "fk_users_pets" FOREIGN KEY ("user_id") REFERENCES "users"("id");
2 changes: 2 additions & 0 deletions gormschema/testdata/sqlite_no_fk
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ CREATE TABLE `users` (`id` integer,`created_at` datetime,`updated_at` datetime,`
CREATE INDEX `idx_users_deleted_at` ON `users`(`deleted_at`);
CREATE TABLE `pets` (`id` integer,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`name` text,`user_id` integer,PRIMARY KEY (`id`));
CREATE INDEX `idx_pets_deleted_at` ON `pets`(`deleted_at`);
CREATE TABLE `hobbies` (`id` integer,`name` text,PRIMARY KEY (`id`));
CREATE TABLE `user_hobbies` (`hobby_id` integer,`user_id` integer,PRIMARY KEY (`hobby_id`,`user_id`));
4 changes: 4 additions & 0 deletions gormschema/testdata/sqlserver_default
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ CREATE TABLE "locations" ("locationId" nvarchar(191),"eventId" nvarchar(191),PRI
CREATE UNIQUE INDEX "idx_locations_event_id" ON "locations"("eventId");
CREATE TABLE "users" ("id" bigint IDENTITY(1,1),"created_at" datetimeoffset,"updated_at" datetimeoffset,"deleted_at" datetimeoffset,"name" nvarchar(MAX),"age" bigint,PRIMARY KEY ("id"));
CREATE INDEX "idx_users_deleted_at" ON "users"("deleted_at");
CREATE TABLE "hobbies" ("id" bigint IDENTITY(1,1),"name" nvarchar(MAX),PRIMARY KEY ("id"));
CREATE TABLE "user_hobbies" ("hobby_id" bigint,"user_id" bigint,PRIMARY KEY ("hobby_id","user_id"));
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");
CREATE VIEW working_aged_users AS SELECT name, age FROM "users" WHERE age BETWEEN 18 AND 65;
CREATE VIEW top_pet_owners AS SELECT user_id, COUNT(id) AS pet_count FROM pets GROUP BY user_id ORDER BY pet_count DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;
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 "user_hobbies" ADD CONSTRAINT "fk_user_hobbies_hobby" FOREIGN KEY ("hobby_id") REFERENCES "hobbies"("id");
ALTER TABLE "user_hobbies" ADD CONSTRAINT "fk_user_hobbies_user" FOREIGN KEY ("user_id") REFERENCES "users"("id");
ALTER TABLE "pets" ADD CONSTRAINT "fk_users_pets" FOREIGN KEY ("user_id") REFERENCES "users"("id");
2 changes: 1 addition & 1 deletion internal/testdata/customjointable/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Person struct {
}

type Address struct {
ID int
ID int `gorm:"primaryKey"`
Name string
}

Expand Down
15 changes: 15 additions & 0 deletions internal/testdata/migrations/mysql/20240601122756.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- Create "hobbies" table
CREATE TABLE `hobbies` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`name` longtext NULL,
PRIMARY KEY (`id`)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- Create "user_hobbies" table
CREATE TABLE `user_hobbies` (
`user_id` bigint unsigned NOT NULL,
`hobby_id` bigint unsigned NOT NULL,
PRIMARY KEY (`user_id`, `hobby_id`),
INDEX `fk_user_hobbies_hobby` (`hobby_id`),
CONSTRAINT `fk_user_hobbies_hobby` FOREIGN KEY (`hobby_id`) REFERENCES `hobbies` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT `fk_user_hobbies_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
3 changes: 2 additions & 1 deletion internal/testdata/migrations/mysql/atlas.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
h1:lKRYkpC/b7av3+2N9ZwAhoInac+KYoj12ZIPaAINpeI=
h1:4neLwABljo1WE/2TflQvcvZCa4xR025viAzNEa4Cp6s=
20230627123246.sql h1:+bgzC3WJyyIR6Rv/FUvaNXJ1gkbKJlYcEMgp69yORIY=
20240512024238.sql h1:2kQL4tE/tAhvXuozmRAJ3oXTo1KRz11QosVDw+0va14=
20240518091603.sql h1:xNClqqRaOjXwg0julpsiPYsmqUcEL/hJel1iqYzi3DM=
20240601122756.sql h1:5+N9UzKTw6qQvJLf8nGw4BdFuHG0fa2JHdHn++G8MuE=
14 changes: 14 additions & 0 deletions internal/testdata/migrations/postgres/20240601122813.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- Create "hobbies" table
CREATE TABLE "public"."hobbies" (
"id" bigserial NOT NULL,
"name" text NULL,
PRIMARY KEY ("id")
);
-- Create "user_hobbies" table
CREATE TABLE "public"."user_hobbies" (
"user_id" bigint NOT NULL,
"hobby_id" bigint NOT NULL,
PRIMARY KEY ("user_id", "hobby_id"),
CONSTRAINT "fk_user_hobbies_hobby" FOREIGN KEY ("hobby_id") REFERENCES "public"."hobbies" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT "fk_user_hobbies_user" FOREIGN KEY ("user_id") REFERENCES "public"."users" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION
);
3 changes: 2 additions & 1 deletion internal/testdata/migrations/postgres/atlas.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
h1:LR1ImLA5ZOcbBr9yHMReTtaRiM6dVScC6Xefy3kpxWI=
h1:a/bAYykD/mWdu/8WM16vbYqnwg5NsdX2iM3urGrBFUc=
20230627123049.sql h1:1jYJM2+VCr9152vg6gayCrcEvuT/FE7ufOyZ86VLaOE=
20240512024223.sql h1:RY4w148OJBBr5sXpfBq6B48p/1cFrTEpH4TlwD7mUps=
20240518091611.sql h1:3Kv6mYS8ML72H6HE5qr/a2gdVUrfWuHVufP/1wl70vE=
20240601122813.sql h1:ALbhVYVMyOvZSy5jmBVrsk4xjdkx6ro8OxKJcmW0n1U=
14 changes: 14 additions & 0 deletions internal/testdata/migrations/sqlite/20240601122746.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- Create "hobbies" table
CREATE TABLE `hobbies` (
`id` integer NULL,
`name` text NULL,
PRIMARY KEY (`id`)
);
-- Create "user_hobbies" table
CREATE TABLE `user_hobbies` (
`user_id` integer NULL,
`hobby_id` integer NULL,
PRIMARY KEY (`user_id`, `hobby_id`),
CONSTRAINT `fk_user_hobbies_hobby` FOREIGN KEY (`hobby_id`) REFERENCES `hobbies` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT `fk_user_hobbies_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
);
3 changes: 2 additions & 1 deletion internal/testdata/migrations/sqlite/atlas.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
h1:4HTi5BBlSSs2F/Rg17KQCcuEsVY/dDwyF2yzjThRcd0=
h1:n3NYZrFWODZNTYXEomQ/EtMuxc7EsQDZ7jaIgd9olYY=
20230627123228.sql h1:YfwJdN73sWz1G5/0tU2BtGLyzJCfRQr8blTSquUZ+qo=
20240511123637.sql h1:Kbk3wUzTfBbq8mDdTT08hP93ecNU0y5oTL+O8idEcdQ=
20240518091437.sql h1:svMANRZuZDvgzqO3iyNLUjrUrK8BTMEB2f0NV3d5sJo=
20240601122746.sql h1:Jpzp4UdG5EjO8uNtRWU8sZ9fKuP4mRod5ofyFVQwH1A=
15 changes: 15 additions & 0 deletions internal/testdata/migrations/sqlserver/20240601122612.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- Create "hobbies" table
CREATE TABLE [hobbies] (
[id] bigint IDENTITY (1, 1) NOT NULL,
[name] nvarchar(MAX) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_hobbies] PRIMARY KEY CLUSTERED ([id] ASC)
);
-- Create "user_hobbies" table
CREATE TABLE [user_hobbies] (
[user_id] bigint NOT NULL,
[hobby_id] bigint NOT NULL,
CONSTRAINT [PK_user_hobbies] PRIMARY KEY CLUSTERED ([user_id] ASC, [hobby_id] ASC),

CONSTRAINT [fk_user_hobbies_hobby] FOREIGN KEY ([hobby_id]) REFERENCES [hobbies] ([id]) ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT [fk_user_hobbies_user] FOREIGN KEY ([user_id]) REFERENCES [users] ([id]) ON UPDATE NO ACTION ON DELETE NO ACTION
);
3 changes: 2 additions & 1 deletion internal/testdata/migrations/sqlserver/atlas.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
h1:24mg+pUG3Z4l321YP5s1fRPPaAg6sJC8VR62qPXClTw=
h1:chvbQ1yysFYmq1K82/VfQeLxzMYrhjQ+8xv+2uoXdZw=
20240124151658.sql h1:KaWALlql7BBV3oPVRT4rn+dvZaolhDmgbTgUPxIhauU=
20240512024328.sql h1:IBON1V3jlts+AqxRhejN82SE7/BIXSUWM0SQ0pvw4wc=
20240518091510.sql h1:CCFQHjVI+5dLXCgoPSERCHhyGBZl7QistZlrs1I5170=
20240601122612.sql h1:sCf/0g9oPsaj0Z3l7WO2BjthUwsK9OfPWv80J/L1WCA=
13 changes: 10 additions & 3 deletions internal/testdata/models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@ import (

type User struct {
gorm.Model
Name string
Age int
Pets []Pet
Name string
Age int
Pets []Pet
Hobbies []Hobby `gorm:"many2many:user_hobbies;"`
}

type Hobby struct {
ID uint
Name string
Users []User `gorm:"many2many:user_hobbies;"`
}

type WorkingAgedUsers struct {
Expand Down
Loading

0 comments on commit 0599721

Please sign in to comment.