SkillAgentSearch skills...

Goe

A type safe SQL like ORM for Go

Install / Use

/learn @go-goe/Goe
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

GOE

GO Entity or just "GOE" is a type safe ORM for Go

test status Go Report Card Go.Dev reference MIT license

GOE logo by Luanexs

Requirements

  • go v1.24 or above;

Real world examples

GOE has examples of queries and integrations, if you think in a nice example and wanted to see if GOE can handler, just try out.

Common examples are:

  • How to use GOE with other frameworks;
  • Where GOE key features can shine;

Features

Check out the Benchmarks section for a overview on GOE performance compared to other packages like, ent, GORM, sqlc, and others.

  • 🚫 Non-String Usage;
    • write queries with only Go code
  • 🔖 Type Safety;
    • get errors on compile time
  • 📦 Auto Migrations;
    • automatic generate tables from your structs
  • 📄 SQL Like queries;
    • use Go code to write queries with well known functions
  • 🗂️ Iterator
    • range over function to iterate over the rows
  • 📚 Pagination
    • paginate your large selects with just a function call
  • ♻️ Wrappers
    • wrappers for simple queries and builders for complex ones

Content

Install

go get github.com/go-goe/goe

As any database/sql support in go, you have to get a specific driver for your database, check Available Drivers

Available Drivers

PostgreSQL

go get github.com/go-goe/postgres

Usage

type Animal struct {
	// animal fields
}

type Database struct {
	Animal         *Animal
	*goe.DB
}

dns := "user=postgres password=postgres host=localhost port=5432 database=postgres"
db, err := goe.Open[Database](postgres.Open(dns, postgres.NewConfig(postgres.Config{})))

SQLite

go get github.com/go-goe/sqlite

Usage

type Animal struct {
	// animal fields
}

type Database struct {
	Animal         *Animal
	*goe.DB
}

db, err := goe.Open[Database](sqlite.Open("goe.db", sqlite.NewConfig(sqlite.Config{})))

Checkout the exclusive features of sqlite on goe-sqlite

Quick Start

package main

import (
	"fmt"

	"github.com/go-goe/goe"
	"github.com/go-goe/sqlite"
)

type Animal struct {
	ID    int
	Name  string
	Emoji string
}

type Database struct {
	Animal *Animal
	*goe.DB
}

func main() {
	db, err := goe.Open[Database](sqlite.Open("goe.db", sqlite.NewConfig(sqlite.Config{})))
	if err != nil {
		panic(err)
	}
	defer goe.Close(db)

	err = goe.Migrate(db).AutoMigrate()
	if err != nil {
		panic(err)
	}

	err = goe.Delete(db.Animal).All()
	if err != nil {
		panic(err)
	}

	animals := []Animal{
		{Name: "Cat", Emoji: "🐈"},
		{Name: "Dog", Emoji: "🐕"},
		{Name: "Rat", Emoji: "🐀"},
		{Name: "Pig", Emoji: "🐖"},
		{Name: "Whale", Emoji: "🐋"},
		{Name: "Fish", Emoji: "🐟"},
		{Name: "Bird", Emoji: "🐦"},
	}

	err = goe.Insert(db.Animal).All(animals)
	if err != nil {
		panic(err)
	}

	animals, err = goe.List(db.Animal).AsSlice()
	if err != nil {
		panic(err)
	}
	fmt.Println(animals)
}

To run the quick start follow this steps:

  1. Init the go.mod file

    go mod init quickstart
    
  2. Get the necessary packages:

    go mod tidy
    
  3. Run the example:

    go run main.go
    
  4. If everything was ok, you should see a output like this:

    [{1 Cat 🐈} {2 Dog 🐕} {3 Rat 🐀} {4 Pig 🐖} {5 Whale 🐋} {6 Fish 🐟} {7 Bird 🐦}]
    

Database

type Database struct {
	User    	*User
	Role    	*Role
	UserLog 	*UserLog
	*goe.DB
}

In goe, it's necessary to define a Database struct, this struct implements *goe.DB and a pointer to all the structs that's it's to be mappend.

It's through the Database struct that you will interact with your database.

Supported Types

GOE supports any type that implements the Scanner Interface. Most common are sql.Null types from database/sql package.

type Table struct {
	Price      decimal.Decimal     `goe:"type:decimal(10,4)"`
	NullID     sql.Null[uuid.UUID] `goe:"type:uuid"`
	NullString sql.NullString      `goe:"type:varchar(100)"`
}

Back to Contents

Struct mapping

type User struct {
	ID        	uint //this is primary key
	Login     	string
	Password  	string
}

[!NOTE] By default the field "ID" is primary key and all ids of integers are auto increment.

Back to Contents

Setting primary key

type User struct {
	Identifier	uint `goe:"pk"`
	Login     	string
	Password	string
}

In case you want to specify a primary key use the tag value "pk".

Back to Contents

Setting type

type User struct {
	ID       	string `goe:"pk;type:uuid"`
	Login    	string `goe:"type:varchar(10)"`
	Name     	string `goe:"type:varchar(150)"`
	Password 	string `goe:"type:varchar(60)"`
}

You can specify a type using the tag value "type"

Back to Contents

Setting null

type User struct {
	ID        int
	Name      string
	Email     *string // this will be a null column
	Phone     sql.NullString `goe:"type:varchar(20)"` // also null
}

[!IMPORTANT] A pointer is considered a null column in Database.

Back to Contents

Setting default

type User struct {
	ID        int
	Name      string
	Email     *string
	CreatedAt  time.Time `goe:"default:current_timestamp"`
}

A default value is used when the field is inserted with no value.

// CreatedAt will have the default value
err = goe.Insert(db.User).One(&User{Name: "Rose"})

if err != nil {
	// handler error
}

Back to Contents

Relationship

In GOE relational fields are created using the pattern TargetTable+TargetTableID, so if you want to have a foreign key to User, you will have to write a field like UserID or UserIDOrigin.

One To One

type User struct {
	ID       	uint
	Login    	string
	Name     	string
	Password 	string
}

type UserDetails struct {
	ID       	uint
	Email   	string
	Birthdate 	time.Time
	UserID   	uint  // one to one with User
}

Back to Contents

Many To One

For simplifications all relational slices should be the last fields on struct.

type User struct {
	ID       	uint
	Name     	string
	Password 	string
	UserLogs 	[]UserLog // one User has many UserLogs
}

type UserLog struct {
	ID       	uint
	Action   	string
	DateTime 	time.Time
	UserID   	uint // if remove the slice from user, will become a one to one
}

The difference from one to one and many to one it's a slice field on the "many" struct.

Back to Contents

Many to Many

For simplifications all relational slices should be the last fields on struct.

Using implicit many to many:

type Person struct {
	ID   int
	Name string
	Jobs []Job // Person has a slice to Jobs
}

// Person and Job are implicit relational
type PersonJob struct {
	PersonID   int `goe:"pk"`
	JobID      int `goe:"pk"`
	CreatedAt  time.Time
}

type Job struct {
	Name    string
	ID      int
	Persons []Person // Job has a slice to Person
}

[!IMPORTANT] It's used the tags "pk" for ensure that the foreign keys will be both primary key.

Using many to one pattern:

type User struct {
	ID       	uint
	Name     	string
	Password 	string
	UserRoles 	[]UserRole
}

type UserRole struct {
	UserID  	uint `goe:"pk"`
	RoleID  	uint `goe:"pk"`
}

type Role struct {
	ID        	uint
	Name      	string
	UserRoles 	[]UserRole
}

Is used a combination of two many to one to generate a many to many. In this example, User has many UserRole and Role has many UserRole.

[!IMPORTANT] It's used the tags "pk" for ensure that the foreign keys will be both primary key.

[Back to Contents](#conte

View on GitHub
GitHub Stars126
CategoryData
Updated8d ago
Forks4

Languages

Go

Security Score

95/100

Audited on Mar 26, 2026

No findings