Bun vs GORM

1

Migrator

2

ORM

3

Choose winner

4

Let's GO

# MIGRATOR

Migrator

  • Configure migrations schema

  • Apply all unapplied migrations

  • Write plain SQL in migrations

🍩 Bun 

migrator := migrate.NewMigrator(db, migrations.Migrations,
	migrate.WithTableName("bar.migrations"),
	migrate.WithLocksTableName("bar.migration_locks"),
)
# MIGRATOR

⭐️ GORM

// option 1
if err := db.AutoMigrate(&Article{}); err != nil {
	log.Fatal(err)
}

// option 2
if !db.Migrator().HasTable("articles") {
	db.Migrator().CreateTable(&Article{})
}
# MIGRATOR

⭐️ GORM

SELECT count(*) FROM information_schema.tables WHERE table_schema = CURRENT_SCHEMA() AND table_name = 'articles' AND table_type = 'BASE TABLE'

SELECT CURRENT_DATABASE()

SELECT c.column_name, c.is_nullable = 'YES', c.udt_name, c.character_maximum_length, c.numeric_precision, c.numeric_precision_radix, c.numeric_scale, c.datetime_precision, 8 * typlen, c.column_default, pd.description, c.identity_increment FROM information_schema.columns AS c JOIN pg_type AS pgt ON c.udt_name = pgt.typname LEFT JOIN pg_catalog.pg_description as pd ON pd.objsubid = c.ordinal_position AND pd.objoid = (SELECT oid FROM pg_catalog.pg_class WHERE relname = c.table_name AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = c.table_schema)) where table_catalog = 'poc' AND table_schema = CURRENT_SCHEMA() AND table_name = 'articles'

SELECT constraint_name FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name) JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema AND tc.table_name = c.table_name AND ccu.column_name = c.column_name WHERE constraint_type IN ('PRIMARY KEY', 'UNIQUE') AND c.table_catalog = 'poc' AND c.table_schema = CURRENT_SCHEMA() AND c.table_name = 'articles' AND constraint_type = 'UNIQUE'

SELECT c.column_name, constraint_name, constraint_type FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name) JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema AND tc.table_name = c.table_name AND ccu.column_name = c.column_name WHERE constraint_type IN ('PRIMARY KEY', 'UNIQUE') AND c.table_catalog = 'poc' AND c.table_schema = CURRENT_SCHEMA() AND c.table_name = 'articles'

SELECT a.attname as column_name, format_type(a.atttypid, a.atttypmod) AS data_type
                FROM pg_attribute a JOIN pg_class b ON a.attrelid = b.oid AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = CURRENT_SCHEMA())
                WHERE a.attnum > 0 -- hide internal columns
                AND NOT a.attisdropped -- hide deleted columns
                AND b.relname = 'articles'

SELECT description FROM pg_catalog.pg_description WHERE objsubid = (SELECT ordinal_position FROM information_schema.columns WHERE table_schema = CURRENT_SCHEMA() AND table_name = 'articles' AND column_name = 'id') AND objoid = (SELECT oid FROM pg_catalog.pg_class WHERE relname = 'articles' AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = CURRENT_SCHEMA()))

SELECT description FROM pg_catalog.pg_description WHERE objsubid = (SELECT ordinal_position FROM information_schema.columns WHERE table_schema = CURRENT_SCHEMA() AND table_name = 'articles' AND column_name = 'name') AND objoid = (SELECT oid FROM pg_catalog.pg_class WHERE relname = 'articles' AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = CURRENT_SCHEMA()))

-- ...
# MIGRATOR

ORM

  • Read...

  • Save...

   ...aggregates using repository

 

# ORM

🍩 Bun: read

# ORM

Supported 🎉

🍩 Bun: save

Not supported

# ORM

⭐️ GORM: read

# ORM

Supported 🎉

⭐️ GORM: save

Supported, but...

# ORM

⭐️ GORM

a := &Article{}
db.Model(a).Preload("Comments").First(a)

a.Name = "Upd"

db.Save(a)
INSERT INTO "comments" ("article_id","body","id")
VALUES (1,'Bar',2),(1,'Foo',1)
ON CONFLICT ("id") DO UPDATE SET "article_id"="excluded"."article_id" RETURNING "id"

UPDATE "articles" SET "name"='Upd' WHERE "id" = 1
# ORM

⭐️ GORM

a := &Article{}
db.Model(a).Preload("Comments").First(a)

// remove last comment
a.Comments = a.Comments[:2]

db.Save(a)
INSERT INTO "comments" ("article_id","body","id")
VALUES (1,'Baz',3),(1,'Bar',2)
ON CONFLICT ("id") DO UPDATE SET "article_id"="excluded"."article_id" RETURNING "id"

UPDATE "articles" SET "name"='Upd' WHERE "id" = 1
# ORM

⭐️ GORM

db.Model(&a).Association("Comments").Replace(&Comment{
	Id:   4,
	Body: "Replaced",
})
INSERT INTO "comments" ("article_id","body","id")
VALUES (1,'Replaced',4)
ON CONFLICT ("id") DO UPDATE SET "article_id"="excluded"."article_id" RETURNING "id"

UPDATE "comments" SET "article_id"=NULL
WHERE "comments"."id" <> 4 AND "comments"."article_id" = 1
# ORM
# ADVANTAGES

🍩 Bun advantages

  • One of the most popular ORMs

  • Already integrated in DWH module

  • go-pg migration doc

  • Fixtures support

  • Fast response from maintainers

Bun vs GORM

By Volodymyr Kupriienko

Bun vs GORM

  • 312