goent

package module
v0.8.4-b1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 26, 2026 License: MIT Imports: 16 Imported by: 0

README

GoEnt

GO Entity or just "GoEnt" is an easy-to-use ORM for Go

test status Go Report Card Go.Dev reference MIT license

GoEnt Logo

Requirements

  • go v1.26 or above

Real world examples

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

Common examples are:

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

Features

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

  • 🔖 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/azhai/goent

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

Available Drivers

  • PostgreSQL
  • SQLite
go get github.com/azhai/goent
Usage
import (
	"github.com/azhai/goent"
	"github.com/azhai/goent/drivers/pgsql"
)

type Animal struct {
	// animal fields
}

type Database struct {
	Animal *goent.Table[Animal]
	*goent.DB
}

dsn := "postgres://dba:pass@127.0.0.1:5432/test?sslmode=disable"
db, err := goent.Open[Database](pgsql.Open(dsn), "stdout")
// db, err := goent.Open[Database](sqlite.Open("goent.db"), "stdout")

Quick Start

package main

import (
	"fmt"

	"github.com/azhai/goent"
	"github.com/azhai/goent/drivers/sqlite"
)

type Animal struct {
	ID    int
	Name  string
	Emoji string
}

type PublicSchema struct {
	Animal *goent.Table[Animal]
}

type Database struct {
	PublicSchema `goe:"public"`
	*goent.DB
}

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

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

	err = db.Animal.Delete().Exec()
	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: "🐦"},
	}

	// Insert all animals in a single transaction
	// retPK = false is 5 times faster than retPK = true
	err = db.Animal.Insert().All(false, animals)
	if err != nil {
		panic(err)
	}

	animals, err = db.Animal.Select().All()
	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    	*goent.Table[User]
	Role    	*goent.Table[Role]
	UserLog 	*goent.Table[UserLog]
	*goent.DB
}

In goe, it's necessary to define a Database struct, this struct implements *goent.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

GoEnt 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

Table Name Resolution

Table names are resolved in the following order:

  1. TableName() method - If the struct implements TableName() string, that value is used directly
  2. Struct name in snake_case with prefix - If no TableName() method, the struct name is converted to snake_case, with optional prefix: from schema tag prepended

The schema tag format is: goe:"schema_name;prefix:table_prefix"

// Method 1: TableName() method (returns exact table name, no prefix added)
type OrderDetail struct {
    OrderID   int64 `goe:"pk;not_incr"`
    ProductID int64 `goe:"pk;not_incr"`
}

func (*OrderDetail) TableName() string {
    return "t_order_detail"  // Exact table name, prefix is ignored
}

// Method 2: Auto-generated from struct name with prefix
type PublicSchema struct {
    User     *goent.Table[User]     // Table: t_user (with prefix t_)
    Category *goent.Table[Category] // Table: t_category
}

type Database struct {
    PublicSchema `goe:"public;prefix:t_"`  // schema=public, prefix=t_
    *goent.DB
}

// Without prefix
type AuthSchema struct {
    Role *goent.Table[Role]  // Table: role (no prefix)
}

type Database struct {
    AuthSchema `goe:"auth"`  // schema=auth, no prefix
    *goent.DB
}

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".

Composite Primary Key
type OrderDetail struct {
	OrderID   int `goe:"pk;not_incr"`
	ProductID int `goe:"pk;not_incr"`
	Quantity  int
}

Use multiple pk tags to create a composite primary key. Add not_incr to prevent auto-increment on primary key columns.

Non-Auto-Increment Primary Key
type User struct {
	ID   string `goe:"pk;not_incr;default:uuid_generate_v4()"`
	Name string
}

Use not_incr tag to prevent auto-increment behavior on primary key columns. This is useful for UUID or string primary keys.

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 = db.User.Insert().One(&User{Name: "Rose"})

if err != nil {
	// handler error
}
Primary Key with Default Value

For non-auto-increment primary keys, you can specify a default value:

type Default struct {
	ID   string `goe:"default:'Default'"` // Primary key with default value
	Name string
}

When inserting, the default value is automatically set on the struct:

// d := Default{Name: "Test"}
// err = db.Default.Insert().One(&d)

// recommend:
d := &Default{Name: "Test"}
err = db.Default.Insert().One(d)

// d.ID == "Default" (set from default value)

if err != nil {
	// handler error
}

[!NOTE] For primary keys with default values, the value is set on the struct before INSERT, and the column is included in the INSERT statement. This is different from auto-increment primary keys, where the column is excluded and the ID is retrieved using last_insert_rowid().

Back to Contents

Relationship

In GoEnt 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

Self-Referential

One to Many

type Person struct {
	ID       int
	Name     string
	PersonID *int
	Family   []Person
}

One to One

type Page struct {
	ID         int
	Number     int
	PageIDNext *int
	PageIDPrev *int
}

Back to Contents

Index
Unique Index
type User struct {
	ID       	uint
	Name     	string
	Email    	string  `goe:"unique"`
}

To create a unique index you need the "unique" goe tag

Back to Contents

Create Index
type User struct {
	ID       uint
	Name     string
	Email 	 string `goe:"index"`
}

To create a common index you need the "index" goe tag

Back to Contents

Two Columns Index
type User struct {
	ID       uint
	Name    string `goe:"index(n:idx_name_status)"`
	Email   string `goe:"index(n:idx_name_status);unique"`
}

Using the goe tag "index()", you can pass the index infos as a function call. "n:" is a parameter for name, to have a two column index just need two indexes with same name. You can use the semicolon ";" to create another single index for the field.

Back to Contents

Two Columns Unique Index
type User struct {
	ID       uint
	Name    string `goe:"index(unique n:idx_name_status)"`
	Email   string `goe:"index(unique n:idx_name_status);unique"`
}

Just as creating a Two Column Index but added the "unique" value inside the index function.

Back to Contents

Function Index
type User struct {
	Id        int
	Name      string `goe:"index(n:idx_name_lower f:lower)"`
	Email     string `goe:"unique"`
	UserRoles []UserRole
}

Use the f: parameter to pass a function in the index tag.

Back to Contents

Schemas

On GoEnt it's possible to create schemas by the database struct, all schemas should have the suffix Schema or a tag goe:"schema".

[!IMPORTANT] Tables must be nested under schema structs. The hierarchy is: Database -> Schema -> Table. SQLite ignores schema names (tables are created directly in the main database).

type User struct {
	...
}

type UserRole struct {
	...
}

type Role struct {
	...
}
// schema with suffix Schema
type UserSchema struct {
	User     *goent.Table[User]
	UserRole *goent.Table[UserRole]
	Role     *goent.Table[Role]
}
// schema with any name
type Authentication struct {
	User     *goent.Table[User]
	UserRole *goent.Table[UserRole]
	Role     *goent.Table[Role]
}

type Database struct {
	*UserSchema // all structs on UserSchema will be created inside user schema
	*Authentication `goe:"schema"` // will create Authentication schema
	*goent.DB
}

[!TIP] On SQLite any schema will be a new attached db file.

Back to Contents

Logging

GoEnt supports any logger that implements the Logger interface

type Logger interface {
	InfoContext(ctx context.Context, msg string, kv ...any)
	WarnContext(ctx context.Context, msg string, kv ...any)
	ErrorContext(ctx context.Context, msg string, kv ...any)
}

The logger is defined on database opening

	db, err := drivers.QuickOpen[Database]("sqlite", "goent.db", "stdout")

[!TIP] You can use slog as your standard logger or make a adapt over the Logger interface.

Back to Contents

Open

To open a database use goent.Open function, it's require a valid driver. Most of the drives will require a dsn/path connection and a config setup. On goent.Open needs to specify the struct database.

If you don't need the database connection anymore, call goent.Close to ensure that all the database resources will be removed from memory.

type Database struct {
	Animal         *goent.Table[Animal]
	AnimalFood     *goent.Table[AnimalFood]
	Food           *goent.Table[Food]
	*goent.DB
}

dsn := "user=postgres password=postgres host=localhost port=5432 database=postgres"
db, err := facade.QuickOpen[Database]("pgsql", dsn, "")

if err != nil {
	// handler error
}

Back to Contents

Migrate

Auto Migrate

To auto migrate the structs, use the goent.AutoMigrate(db) passing the database returned by goent.Open.

// migrate all database structs
err = goent.AutoMigrate(db)
if err != nil {
	// handler error
}

Back to Contents

Drop and Rename
type Select struct {
	ID   int
	Name string
}

type Database struct {
	Select         *goent.Table[Select]
	*goent.DB
}

err = goent.AutoMigrate(db).OnTable("Select").RenameColumn("Name", "NewName")
if err != nil {
	// handler error
}

err = goent.AutoMigrate(db).OnTable("Select").DropColumn("NewName")
if err != nil {
	// handler error
}

err = goent.AutoMigrate(db).OnTable("Select").RenameTable("NewSelect")
if err != nil {
	// handler error
}

err = goent.AutoMigrate(db).OnTable("NewSelect").DropTable()
if err != nil {
	// handler error
}

Back to Contents

Migrate to a SQL file

GoEnt drivers supports a output migrate path to specify a directory to store the generated SQL. In this way, calling the "AutoMigrate" function goe WILL NOT auto apply the migrations and output the result as a sql file in the specified path.

// open the database with the migrate path config setup
db, err := goent.Open[Database](sqlite.Open("goent.db", sqlite.Config{
	MigratePath: "migrate/",
}))
if err != nil {
	// handler error
}

// AutoMigrate will output the result as a sql file, and not auto apply the migration
err = goent.AutoMigrate(db)
if err != nil {
	// handler error
}

In this example the file will be output in the "migrate/" path, as follow:

📂 migrate
|   ├── SQLite_1760042267.sql
go.mod

[!TIP] Any other migration like "DropTable", "RenameColumn" and others... will have the same result as "AutoMigrate", and will generate the SQL file.

Back to Contents

Select

Find

Find is used when you want to return a single result.

// one primary key
animal, err := db.Animal.Select().Match(Animal{ID: 2}).One()

// two primary keys
animalFood, err := db.AnimalFood.Select().Match(AnimalFood{IDAnimal: 3, IDFood: 2}).One()

// find record by value, if have more than one it will returns the first
cat, err := db.Animal.Select().Match(Animal{Name: "Cat"}).One()

[!TIP] Use goent.SelectContext for specify a context.

Back to Contents

Select

Select has support for OrderBy, Pagination and Join.

// select all animals
animals, err = db.Animal.Select().All()

// select the animals with name "Cat", ID "3" and IDHabitat "4"
animals, err = db.Animal.Select().Filter(EqualsMap(db.Animal.Field("id"), map[string]any{"name": "Cat", "id": 3})).All()

// when using % on filter, goent makes a like operation
animals, err = db.Animal.Select().Match(Animal{Name: "%Cat%"}).All()

[!TIP] Use goent.SelectContext for specify a context.

Back to Contents

Select Iterator

Iterate over the rows

for row, err := range db.Animal.Select().IterRows() {
	// iterator rows
 }

Back to Contents

Select Specific Fields
var result []struct {
	User    string
	Role    *string
	EndTime *time.Time
}

// row is the generic struct
for row, err := range goent.Select[struct {
		User    string     // output row
		Role    *string    // output row
		EndTime *time.Time // output row
	}](db.User.Field("Name"), db.Role.Field("Name"), db.UserRole.Field("EndDate")).
	Join(goent.InnerJoin, db.UserRole.Table(), EqualsField(db.User.Field("id"), db.UserRole.Field("user_id"))).
	Join(goent.InnerJoin, db.Role.Table(), EqualsField(db.UserRole.Field("role_id"), db.Role.Field("id"))).
	OrderBy("id").IterRows() {

	if err != nil {
		//handler error
	}
	//handler rows
	result = append(result, row)
}

For specific field is used a new struct, each new field guards the reference for the database attribute.

Back to Contents

Where

Where conditions are created using goent functions like Equals, And, Or, In, Like, etc.

animals, err = db.Animal.Select().Where("id = %s", 2).All()

if err != nil {
	//handler error
}

It's possible to group a list of where operations inside Filter()

animals, err = db.Animal.Select().Filter(
		goent.And(
			goent.LessEquals(db.Animal.Field("ID"), 2), 
			goent.In(db.Animal.Field("Name"), []string{"Cat", "Dog"}),
		),
	).All()

if err != nil {
	//handler error
}

You can use a if to call a where operation only if it's match

selectQuery := db.Animal.Select().Filter(goent.LessEquals(db.Animal.Field("ID"), 30))

if filter.In {
	selectQuery = selectQuery.Filter(
		goent.And(
			goent.LessEquals(db.Animal.Field("ID"), 30), 
			goent.In(db.Animal.Field("Name"), []string{"Cat", "Dog"}),
		),
	)
}

animals, err = selectQuery.All()

if err != nil {
	//handler error
}

It's possible to use a query inside a goent.In

// use AsQuery() for get a result as a query
querySelect := goent.Select[any](db.Animal.Field("Name")).
					Join(goent.InnerJoin, db.AnimalFood.Table(), EqualsField(db.Animal.Field("id"), db.AnimalFood.Field("animal_id"))).
					Join(goent.InnerJoin, db.Food.Table(), EqualsField(db.AnimalFood.Field("food_id"), db.Food.Field("id"))).
					Filter(
						goent.In(db.Food.Field("Name"), []string{foods[0].Name, foods[1].Name})).
					AsQuery()

// where in with another query
a, err := db.Animal.Select().Filter(goent.In(db.Animal.Field("Name"), querySelect)).All()

if err != nil {
	//handler error
}

On where, GoEnt supports operations on two columns, all where operations that have Arg as suffix it's used for operation on columns.

In the example, the operator greater (>) on the columns Score and Minimum is used to return all exams that have a score greater than the minimum.

err = db.Exam.Select().
	Filter(goent.GreaterArg[float32](db.Exam.Field("Score"), db.Exam.Field("Minimum"))).All()

Back to Contents

Filter (Non-Zero Dynamic Where)

Filter creates where operations on non-zero values, so if you want a dynamic where to show up only if has values, filter is the call.

var s []string
a, err = db.Animal.Select().
	Filter(
		goent.And(goent.In(db.Animal.Field("Name"), s),
			goent.And(goent.Equals(db.Animal.Field("Id"), 0),
				goent.And(
					goent.Equals(db.Animal.Field("Name"), ""),
					goent.Like(db.Animal.Field("Name"), "%o%"), // valid filter
				),
			),
		),
	).
	OrderBy("id DESC").All()

if err != nil {
	//handler error
}

[!TIP] It's possible to call Filter and Where on the same query.

Back to Contents

Match (Non-Zero Dynamic Where)

Match creates where operations on non-zero values using the query model. Match uses a LIKE operator with the ToUpper function on all string values.

// SELECT * FROM "status" where UPPER("status"."name") LIKE '%A%'
result, err := db.Status.Select().Match(Status{Name: "a"}).All()
if err != nil {
	//handler error
}

It's possible to use Match on Select

// SELECT "animals"."name", "foods"."name" FROM "animals"
// JOIN "animal_foods" on ("animals"."id" = "animal_foods"."animal_id")
// JOIN "food_habitat_schema"."foods" on ("animal_foods"."food_id" = "foods"."id")
// WHERE UPPER("foods"."name") LIKE '%A%'
result, err := goent.Select[struct {
	AnimalName string
	FoodName   string
}](db.Animal.Field("Name"), db.Food.Field("Name")).Match(struct {
	AnimalName string
	FoodName   string
}{FoodName: "a"}).
	Join(goent.InnerJoin, db.AnimalFood.Table(), EqualsField(db.Animal.Field("id"), db.AnimalFood.Field("animal_id"))).
	Join(goent.InnerJoin, db.Food.Table(), EqualsField(db.AnimalFood.Field("food_id"), db.Food.Field("id"))).All()

if err != nil {
	//handler error
}

[!TIP] It's possible to call Match and Where on the same query.

Back to Contents

Join

Join operations use goent constants like InnerJoin, LeftJoin, RightJoin.

For the join operations, you need to specify the type, this make the joins operations more safe. So if you change a type from a field, the compiler will throw a error.

animals, err = db.Animal.Select().
				Join(goent.InnerJoin, db.AnimalFood.Table(), EqualsField(db.Animal.Field("id"), db.AnimalFood.Field("animal_id"))).
				Join(goent.InnerJoin, db.Food.Table(), EqualsField(db.AnimalFood.Field("food_id"), db.Food.Field("id"))).
			   All()

if err != nil {
	//handler error
}

Same as where, you can use a if to only make a join if the condition match.

LeftJoin Helper Method

The LeftJoin method is a convenient helper for LEFT JOIN operations with automatic column selection:

// LeftJoin automatically selects columns from the joined table
orderDetails, err := db.OrderDetail.Select().
    LeftJoin("product_id", db.Product.Field("id")).
    Filter(goent.Equals(db.OrderDetail.Field("order_id"), orderID)).
    All()

// The Product field will be populated for each OrderDetail
for _, detail := range orderDetails {
    if detail.Product != nil {
        fmt.Printf("Product: %s, Price: %.2f\n", detail.Product.Name, detail.Product.Price)
    }
}

The LeftJoin method:

  • Automatically adds the joined table's columns to the SELECT list
  • Creates the JOIN condition using the local foreign key field and the referenced field
  • Supports chaining multiple joins
// Multiple joins example
results, err := db.Person.Select().
    LeftJoin("id", db.PersonJobTitle.Field("person_id")).
    LeftJoin("job_title_id", db.JobTitle.Field("id")).
    Filter(goent.Equals(db.JobTitle.Field("name"), "Developer")).
    All()

[!NOTE] LeftJoin only populates non-slice foreign fields. For slice relationships (e.g., Jobs []JobTitle), use the standard Join method with manual column selection.

Back to Contents

Order By

For OrderBy you need to pass a reference to a mapped database field.

It's possible to OrderBy desc and asc. Select has support for OrderBy queries.

animals, err = db.Animal.Select().OrderBy("id DESC").All()

if err != nil {
	//handler error
}
Group By

For GroupBy you need to pass a reference to a mapped database field.

It's possible to GroupBy by a aggregate.

Select
habitatCount, err := goent.Select[struct {
	Name  string
	Count int64
}](db.Habitat.Field("Name"), aggregate.Count(db.Animal.Field("Id"))).Join(goent.InnerJoin, db.Habitat.Table(), EqualsField(db.Animal.Field("habitat_id"), db.Habitat.Field("id"))).
	OrderBy("count DESC").
	GroupBy("name").All()

if err != nil {
	//handler error
}

Back to Contents

Pagination

For pagination, it's possible to run on Select function

Select Pagination
// page 1 of size 10
page, err := db.Animal.Select().Pagination(1, 10)

if err != nil {
	//handler error
}

[!NOTE] Pagination default values for page and size are 1 and 10 respectively.

Back to Contents

Aggregates

Aggregate functions like Count, Sum, Avg are available as table methods.

count, err := db.Animal.Count("id") // (int64, error)

Back to Contents

Functions

SQL functions like ToUpper can be called as table methods.

names, err := db.Animal.ToUpper("name") // ([]string, error)

Functions can be used inside where.

animals, err = db.Animal.Select().
			   Filter(
					goent.Expr("ToUpper(name) LIKE '%CAT%'"),
			   ).All()

if err != nil {
	//handler error
}

[!NOTE] where like expected a second argument always as string.

animals, err = db.Animal.Select().
			   Filter(
					goent.Expr("ToUpper(name) LIKE ?", "%CAT%"),
			   ).All()

if err != nil {
	//handler error
}

[!IMPORTANT] to by pass the compiler type warning, use function.Argument. This way the compiler will check the argument value.

Back to Contents

Insert

On Insert if the primary key value is auto-increment, the new ID will be stored on the object after the insert.

[!NOTE] For auto-increment primary keys, the column is excluded from INSERT and the ID is retrieved using last_insert_rowid(). For primary keys with default values, the value is set before INSERT and the column is included in the statement.

Insert One
a := &Animal{Name: "Cat", Emoji: "🐘"}
err = db.Animal.Insert().One(a)

if err != nil {
	//handler error
}

// new generated id
a.ID

[!TIP] Use goent.InsertContext for specify a context.

Back to Contents

Insert Batch
foods := []*Food{
		{Name: "Meat", Emoji: "🥩"},
		{Name: "Hotdog", Emoji: "🌭"},
		{Name: "Cookie", Emoji: "🍪"},
	}
err = db.Food.Insert().All(true, foods)

if err != nil {
	//handler error
}

[!NOTE] The first parameter of All() is autoIncr. When true, it only applies to tables with auto-increment primary keys. For tables with non-auto-increment primary keys (like UUID or string with default), the primary key column is included in the INSERT statement.

[!TIP] Use goent.InsertContext for specify a context.

Back to Contents

Update

Save

Save is the basic function for updates a single record; only updates the non-zero values.

a := &Animal{ID: 2}
a.Name = "Update Cat"

// update animal of id 2
err = db.Animal.Save().One(a)
changes := map[string]any{
	"name": a.Name,
}
filter := goent.Equals(db.Animal.Field("id"), a.ID)
err = db.Animal.Save().Filter(filter).SetMap(changes).Exec()

if err != nil {
	//handler error
}

[!TIP] Use goent.SaveContext for specify a context.

Back to Contents

Update Set

Update with set uses Set method. This is used for more complex updates, like updating a field with zero/nil values or make a batch update.

a := Animal{ID: 2}

// a.IDHabitat is nil, so is ignored by Save
err = db.Animal.Update().
	  Set(goent.Pair{Key: "habitat_id", Value: a.IDHabitat}).
	  Filter(goent.Equals(db.Animal.Field("id"), a.ID)).Exec()

if err != nil {
	//handler error
}

Check out the Where section for more information about where operations.

[!CAUTION] The where call ensures that only the matched rows will be updated.

[!TIP] Use goent.UpdateContext for specify a context.

Back to Contents

Delete

Delete Batch

Delete all records from Animal

err = db.Animal.Delete().Exec()

if err != nil {
	//handler error
}

Delete one record by primary key

err = db.Animal.Delete().Match(Animal{ID: 2}).Exec()

if err != nil {
	//handler error
}

Delete all matched records

err = db.Animal.Delete().Filter(goent.Like(db.Animal.Field("name"), "%Cat%")).Exec()

if err != nil {
	//handler error
}

Check out the Where section for more information about where operations.

[!CAUTION] The filter call ensures that only the matched rows will be deleted.

[!TIP] Use goent.DeleteContext for specify a context.

Back to Contents

Transaction

Begin Transaction
	err = db.BeginTransaction(func(tx goent.Transaction) error {
		cat := &Animal{
			Name: "Cat",
		}
		if err = db.Animal.Insert().OnTransaction(tx).One(cat); err != nil {
			return err // try a rollback
		}

		dog := &Animal{
			Name: "Dog",
		}
		if err = db.Animal.Insert().OnTransaction(tx).One(dog); err != nil {
			return err // try a rollback
		}
		return nil // try a commit
	})

	if err != nil {
		//begin transaction error...
	}

Nested Transaction

err = db.BeginTransaction(func(tx goent.Transaction) error {
	cat := &Animal{
		Name: "Cat",
	}
	if err = db.Animal.Insert().OnTransaction(tx).One(cat); err != nil {
		return err // try a rollback
	}

	tx.BeginTransaction(func(tx2 goent.Transaction) error {
		meat := &Food{
			Name: "meat",
		}
		if err := db.Food.Insert().OnTransaction(tx2).One(meat); err != nil {
			return err // try a rollback in nested transaction
		}
		return nil // try a commit in nested transaction
	})

	dog := &Animal{
		Name: "Dog",
	}
	if err = db.Animal.Insert().OnTransaction(tx).One(dog); err != nil {
		return err // try a rollback
	}
	return nil // try a commit
})

if err != nil {
	//begin transaction error...
}

You need to call the OnTransaction() function to setup a transaction for Select, Insert, Update and Delete.

[!NOTE] Any select inside a transaction will be "FOR UPDATE".

[!TIP] Use goent.BeginTransactionContext for specify a context

Back to Contents

Manual Transaction

Setup the transaction with the database function db.NewTransaction()

tx, err = db.NewTransaction()
if err != nil {
	// handler error
}

defer func() {
	if r := recover(); r != nil {
		tx.Rollback()
	}
}()

You need to call the OnTransaction() function to setup a transaction for Select, Insert, Update and Delete.

[!NOTE] Any select inside a transaction will be "FOR UPDATE".

[!TIP] Use goent.NewTransactionContext for specify a context

Back to Contents

Commit and Rollback

To Commit a Transaction just call tx.Commit()

err = tx.Commit()

if err != nil {
	// handler the error
}

To Rollback a Transaction just call tx.Rollback()

err = tx.Rollback()

if err != nil {
	// handler the error
}

Back to Contents

Save Point
sv, err := tx.SavePoint()
if err != nil {
	// handler the error
}
defer func() {
	if r := recover(); r != nil {
		sv.Rollback() // rollback save point
	}
}()

...

sv.Commit() // commit save point

Back to Contents

Code Generation

GoEnt provides a code generator that creates type-safe scan methods for your structs, eliminating reflection overhead and improving performance by up to 27x.

Quick Start
git clone --depth=1 https://github.com/azhai/goent.git
cd goent && go mod tidy && make
./bin/goent-gen ./example/models
# view file ./example/models/goent_gen.go
Install
go install github.com/azhai/goent/cmd/goent-gen@latest
Usage
  1. Add //go:generate goent-gen . to your models package:
//go:generate goent-gen .

package models

type User struct {
    ID       int64  `goe:"pk"`
    Name     string `goe:"unique"`
    Email    string `goe:"unique"`
    StatusID int64  `goe:"m2o"`
}
  1. Run the generator:
go generate ./models
  1. This creates goent_gen.go with:
// Code generated by goent-gen. DO NOT EDIT.

package models

import "github.com/azhai/goent"

// ScanFields returns a slice of pointers to User fields for database scanning.
func (t *User) ScanFields() []any {
    return []any{
        &t.ID,
        &t.Name,
        &t.Email,
        &t.StatusID,
    }
}

// NewUser creates a new User with pre-allocated scan fields.
func NewUser() *User {
    return &User{}
}

// FetchUser creates a FetchFunc for User.
func FetchUser() goent.FetchFunc {
    return func(target any) []any {
        return target.(*User).ScanFields()
    }
}
Performance Comparison
Method Time Memory Allocations
Generated ScanFields 1.68 ns/op 0 B/op 0 allocs/op
Reflection-based 25.04 ns/op 24 B/op 1 allocs/op
Generated FetchFunc 1.68 ns/op 0 B/op 0 allocs/op
Reflection-based 45.29 ns/op 48 B/op 2 allocs/op

Generated code is 15-27x faster than reflection with zero memory allocations.

Using Generated Code
// Use generated FetchFunc with Select
users, err := db.User.Select().QueryRows(models.FetchUser())

// Or use ScanFields directly
user := models.NewUser()
rows.Scan(user.ScanFields()...)

Back to Contents

Benchmarks

Source code of benchmarks can be find on azhai/go-orm-benchmarks or lauro-santana/go-orm-benchmarks.

go run main.go -orm goe -operation all
go run main.go -orm goent -operation all
Benchmark on MacMini M4
Operation Package N Avg ns/op Avg B/op Avg allocs/op
insert goe 14922 79575 2644 31
goent 15036 80156 3014 58
insert-bulk goe 181 7576239 5202183 28013
goent 152 11665895 6859881 44068
update goe 15178 79464 2593 27
goent 15165 80511 3037 54
delete goe 46515 25235 1051 15
goent 1153 1204109 1076 26
select-one goe 41500 28608 3508 54
goent 39538 29913 3680 72
select-page goe 3598 331082 55400 870
goent 3494 337809 59899 1140

Back to Contents

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrUniqueValue = errors.New("goent: unique constraint violation")
	ErrForeignKey  = errors.New("goent: foreign key constraint violation")
	ErrBadRequest  = errors.New("goent: bad request")
	ErrNotFound    = errors.New("goent: not found any element on result set")

	ErrInvalidDatabase    = errors.New("goent: invalid database, the target needs to be a struct")
	ErrInvalidDBField     = errors.New("goent: invalid database, last struct field needs to be goent.DB")
	ErrDBNotFound         = errors.New("goent: db not found")
	ErrFieldNotFound      = errors.New("goent: field or table not found")
	ErrColumnNotFound     = errors.New("goent: column not found")
	ErrNoPrimaryKey       = errors.New("goent: struct does not have a primary key set")
	ErrSliceTypeMigration = errors.New("goent: cannot migrate slice type")
	ErrDuplicateIndex     = errors.New("goent: struct has two or more indexes with same name but different uniqueness/function")
	ErrForeignKeyNotFound = errors.New("goent: foreign key not found")
	ErrMiddleTableNotSet  = errors.New("goent: middle table not configured for M2M relation")
)

Functions

func AppendDestFields

func AppendDestFields(valueOf reflect.Value, fields []*Field, foreigns []*Foreign) []any

AppendDestFields returns a slice of pointers to the fields of a struct for database scanning. It handles both regular fields and wildcard (*) fields that expand to all table columns.

Example:

dest := AppendDestFields(valueOf, fields, nil)
rows.Scan(dest...) // scan into struct fields

func AppendDestTable

func AppendDestTable(info TableInfo, valueOf reflect.Value) []any

AppendDestTable returns a slice of pointers to the fields of a struct

func AutoMigrate

func AutoMigrate(ent any) error

AutoMigrate automatically migrates the database schema based on the entity struct definitions.

func AutoMigrateContext

func AutoMigrateContext(ctx context.Context, ent any) error

AutoMigrateContext automatically migrates the database schema with the given context.

func Close

func Close(ent any) error

Close closes the database connection and cleans up the table registry.

func CreateForeignDest

func CreateForeignDest(valueOf reflect.Value, foreign *Foreign) []any

CreateForeignDest creates destination pointers for foreign key relationship fields. It initializes the related struct field and returns pointers to its columns for scanning.

func FetchArrayResult

func FetchArrayResult[T, V any](query *StateSelect[T, ResultFunc[V]]) ([]V, error)

FetchArrayResult executes a multi-row query and returns the result array. Example: names, err := FetchArrayResult[string](query)

func FetchSingleResult

func FetchSingleResult[T, V any](query *StateSelect[T, ResultFunc[V]]) (V, error)

FetchSingleResult executes a single-row query and returns the result. Example: count, err := FetchSingleResult[int64](query)

func FlattenDest

func FlattenDest(valueOf reflect.Value) []any

FlattenDest returns a slice of pointers to the fields of a struct

func GetFieldName

func GetFieldName(addr uintptr, name string) (string, error)

GetFieldName returns the qualified field name (table.column) for a given table address and column name. If the address is 0, it returns just the column name.

func InitField

func InitField(db *DB, schema *string, tableId int, tables, modelOf reflect.Value) error

InitField initializes the fields of a model struct, setting up primary keys and attributes.

func NewColumnNotFoundError

func NewColumnNotFoundError(column string) error

NewColumnNotFoundError creates an error indicating that the specified column was not found.

func NewDuplicateIndexError

func NewDuplicateIndexError(tableName, indexName string) error

NewDuplicateIndexError creates an error indicating duplicate index definitions with conflicting settings.

func NewFieldNotFoundError

func NewFieldNotFoundError(field string) error

NewFieldNotFoundError creates an error indicating that the specified field or table was not found.

func NewForeignKeyNotFoundError

func NewForeignKeyNotFoundError(fk string) error

NewForeignKeyNotFoundError creates an error indicating that the specified foreign key was not found.

func NewNoPrimaryKeyError

func NewNoPrimaryKeyError(typeName string) error

NewNoPrimaryKeyError creates an error indicating that the struct does not have a primary key set.

func Open

func Open[T any](drv model.Driver, logFile string) (*T, error)

Open opens a database connection

Example

goent.Open[Database](pgsql.Open("user=postgres password=postgres host=localhost port=5432 database=postgres", pgsql.Config{}))

func PutBuilder

func PutBuilder(b *Builder)

PutBuilder resets and returns a Builder to the pool.

func QueryForeign

func QueryForeign[T, R any](table *Table[T], refer *Table[R]) error

QueryForeign queries and populates related records for a foreign key relationship. It automatically determines the relationship type and calls the appropriate query method. Returns nil if no foreign key relationship is found.

Example:

err := QueryForeign(orderTable, customerTable)
if err != nil {
	log.Fatal(err)
}
for _, order := range orderTable.Cache.Each() {
	fmt.Println(order.Customer) // populated Customer struct
}

func QueryMany2Many

func QueryMany2Many[T, R any](foreign *Foreign, table *Table[T], refer *Table[R]) (map[int64]*R, error)

QueryMany2Many queries and populates many-to-many relationships. It uses the middle table to establish the relationship between two tables. Returns a map of left-side IDs to right-side records.

Example:

results, err := QueryMany2Many(foreign, studentTable, courseTable)
for studentId, courses := range results {
	fmt.Printf("Student %d is enrolled in %d courses\n", studentId, len(courses))
}

func QueryMiddleTable

func QueryMiddleTable[T any](foreign *Foreign, table *Table[T], leftCol, rightCol string) (map[int64][]int64, error)

QueryMiddleTable queries the middle junction table for many-to-many relationships. It returns a map of left-side IDs to slices of right-side IDs.

Example:

mapping, err := QueryMiddleTable(foreign, studentTable, "student_id", "course_id")
for studentId, courseIds := range mapping {
	fmt.Printf("Student %d is in courses: %v\n", studentId, courseIds)
}

func QueryOne2Many

func QueryOne2Many[T, R any](foreign *Foreign, table *Table[T], refer *Table[R]) (map[int64][]*R, error)

QueryOne2Many queries and populates one-to-many relationships. It returns a map of parent IDs to slices of child records.

Example:

results, err := QueryOne2Many(foreign, categoryTable, productTable)
for catId, products := range results {
	fmt.Printf("Category %d has %d products\n", catId, len(products))
}

func QuerySome2One

func QuerySome2One[T, R any](foreign *Foreign, table *Table[T], refer *Table[R]) (map[int64]*R, error)

QuerySome2One queries and populates many-to-one or one-to-one relationships. It returns a map of foreign key IDs to referenced records.

Example:

results, err := QuerySome2One(foreign, orderTable, customerTable)
for id, customer := range results {
	fmt.Printf("Order %d: %s\n", id, customer.Name)
}

func ResetRegistry

func ResetRegistry()

ResetRegistry clears all registered schemas and tables. This is useful for testing purposes.

func SameTable

func SameTable(field, another *Field) bool

SameTable checks if two fields belong to the same table.

Types

type Builder

type Builder struct {
	Type  model.QueryType
	Table *model.Table
	Joins []*JoinTable

	Changes  map[*Field]any
	MoreRows [][]any
	Where    Condition
	Selects  []*Field

	Orders []*Order
	Groups []*Group
	Limit  int
	Offset int

	Returning string
	RollUp    string
	ForUpdate bool

	strings.Builder
	// contains filtered or unexported fields
}

Builder constructs SQL queries with support for SELECT, INSERT, UPDATE, and DELETE operations.

func GetBuilder

func GetBuilder() *Builder

GetBuilder retrieves a Builder from the pool.

func (*Builder) Build

func (b *Builder) Build(destroy bool) (sql string, args []any)

Build assembles the complete SQL query and returns it along with query arguments.

func (*Builder) BuildDoing

func (b *Builder) BuildDoing() []any

BuildDoing builds the SET clause for UPDATE or VALUES clause for INSERT.

func (*Builder) BuildHead

func (b *Builder) BuildHead() []any

BuildHead builds the SELECT, INSERT, UPDATE, or DELETE statement head (e.g., "SELECT * FROM table").

func (*Builder) BuildJoins

func (b *Builder) BuildJoins() []any

BuildJoins builds the JOIN clauses for the query.

func (*Builder) BuildTail

func (b *Builder) BuildTail() []any

BuildTail builds the tail part of the query (GROUP BY, ORDER BY, LIMIT, OFFSET, RETURNING).

func (*Builder) BuildWhere

func (b *Builder) BuildWhere() []any

BuildWhere builds the WHERE clause for the query.

func (*Builder) Reset

func (b *Builder) Reset()

Reset resets the Builder to its initial state.

func (*Builder) ResetForSave

func (b *Builder) ResetForSave()

ResetForSave resets the Builder for INSERT/UPDATE operations.

func (*Builder) SetTable

func (b *Builder) SetTable(table TableInfo, driver model.Driver) *Builder

SetTable sets the table for the query builder.

type Column

type Column struct {
	FieldName    string // Go struct field name
	FieldId      int    // Index of the field in the struct
	ColumnName   string // Database column name
	ColumnType   string // Database column type (e.g., "int", "varchar")
	AllowNull    bool   // Whether the column allows NULL values
	HasDefault   bool   // Whether the column has a default value
	DefaultValue string // The default value from struct tag
	// contains filtered or unexported fields
}

Column represents a database column with its metadata and field information.

func GetTableColumn

func GetTableColumn(addr uintptr, name string) *Column

GetTableColumn returns the column info for a given table address and column name.

func (*Column) GetInt64

func (c *Column) GetInt64(obj any) (int64, bool)

GetInt64 returns the int64 value of the column from the given object. Returns (0, false) if the column is not an int type.

func (*Column) GetString

func (c *Column) GetString(obj any) (string, bool)

GetString returns the string value of the column from the given object. Returns ("", false) if the column is not a string type.

type ColumnNotFoundError

type ColumnNotFoundError struct {
	Column string
}

ColumnNotFoundError is returned when a column cannot be found in a table.

func (*ColumnNotFoundError) Error

func (e *ColumnNotFoundError) Error() string

type Condition

type Condition struct {
	Template string
	Fields   []*Field
	Values   []*Value
}

Condition represents a SQL WHERE condition with a template and associated fields/values.

func And

func And(branches ...Condition) Condition

And Example

goent.And(
	goent.Equals(db.Animal.Field("status"), "Eating"),
	goent.Like(db.Animal.Field("name"), "%Cat%"),
	goent.GreaterThan(db.Animal.Field("age"), 3),
)

func Equals

func Equals(left *Field, value any) Condition

Equals creates a condition that checks if a field is equal to a value.

Example: using Table with field name
goent.Equals(db.OrderDetail.Field("order_id"), 1)

func EqualsField

func EqualsField(left, right *Field) Condition

func EqualsMap

func EqualsMap(left *Field, data map[string]any) Condition

EqualsMap creates a condition that checks if a field equals multiple values (from a map).

Example:

cond := goent.EqualsMap(db.User.Field("status"), map[string]any{"active": true, "pending": nil})

func Expr

func Expr(where string, args ...any) Condition

Expr creates a condition with a custom template and associated values.

Example:

cond := goent.Expr("age > ? AND status = ?", 18, "active")
users, _ := db.User.Filter(cond).Select().All()

func Greater

func Greater(left *Field, value any) Condition

Greater Example

// get all animals that was created after this year
thisYear, _ := time.Parse(time.RFC3339, "2026-01-01T00:00:00Z08:00")
Filter(goent.Greater(db.Animal.Field("create_at"), thisYear))

func GreaterEquals

func GreaterEquals(left *Field, value any) Condition

GreaterEquals Example

// get all animals that was created in or after this year
Filter(goent.GreaterEquals(db.Animal.Field("create_at"), time.Parse(time.DateOnly, "2026-01-01")))

func GreaterEqualsField

func GreaterEqualsField(left, right *Field) Condition

GreaterEqualsField creates a condition that checks if one field is greater than or equal to another.

func GreaterField

func GreaterField(left, right *Field) Condition

func ILike

func ILike(left *Field, value string) Condition

ILike creates a case-insensitive LIKE condition.

func In

func In(left *Field, value any) Condition

In creates a condition that checks if a field value is in a list of values.

func IsNotNull

func IsNotNull(left *Field) Condition

IsNotNull creates a condition that checks if a field is NOT NULL.

Example:

cond := goent.IsNotNull(db.User.Field("email"))

func IsNull

func IsNull(left *Field) Condition

IsNull creates a condition that checks if a field is NULL.

Example:

cond := goent.IsNull(db.User.Field("deleted_at"))

func Less

func Less(left *Field, value any) Condition

Less creates a condition that checks if a field is less than a value.

Example: get all animals that was updated before this year

Filter(goent.Less(db.Animal.Field("update_at"), time.Parse(time.DateOnly, "2026-01-01")))

func LessEquals

func LessEquals(left *Field, value any) Condition

LessEquals creates a condition that checks if a field is less than or equal to a value.

Example: get all animals that was updated in or before this year

Filter(goent.LessEquals(db.Animal.Field("update_at"), time.Parse(time.DateOnly, "2026-01-01")))

func LessEqualsField

func LessEqualsField(left, right *Field) Condition

LessEqualsField creates a condition that checks if one field is less than or equal to another.

func LessField

func LessField(left, right *Field) Condition

LessField creates a condition that checks if one field is less than another.

func Like

func Like(left *Field, value string) Condition

Like creates a condition that checks if a field matches a LIKE pattern.

Example: get all animals that has a "at" in his name

goent.Like(db.Animal.Field("name"), "%at%")

func Not

func Not(cond Condition) Condition

Not creates a condition that negates another condition.

Example:

cond := goent.Not(goent.Equals(field, "active"))

func NotEquals

func NotEquals(left *Field, value any) Condition

NotEquals creates a condition that checks if a field is not equal to a value.

Example:

cond := goent.NotEquals(db.User.Field("status"), "deleted")

func NotEqualsField

func NotEqualsField(left, right *Field) Condition

func NotILike

func NotILike(left *Field, value string) Condition

NotILike creates a case-insensitive NOT LIKE condition.

func NotIn

func NotIn(left *Field, value any) Condition

NotIn creates a condition that checks if a field value is not in a list of values.

func NotLike

func NotLike(left *Field, value string) Condition

NotLike creates a condition that checks if a field does not match a LIKE pattern.

func Or

func Or(branches ...Condition) Condition

Or Example

goent.Or(
	goent.Equals(db.Animal.Field("status"), "Eating"),
	goent.Like(db.Animal.Field("name"), "%Cat%"),
	goent.LessThan(db.Animal.Field("age"), 1),
)

func (Condition) IsEmpty

func (c Condition) IsEmpty() bool

IsEmpty returns true if the condition has no template (is empty).

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB represents a database connection with its driver.

func (*DB) BeginTransaction

func (db *DB) BeginTransaction(txFunc func(Transaction) error) error

BeginTransaction begins a Transaction with the database default level. Any panic or error will trigger a rollback.

BeginTransaction uses context.Background internally; to specify the context and the isolation level, use [BeginTransactionContext].

Example:

err = db.BeginTransaction(func(tx goent.Transaction) error {
	cat := &Animal{Name: "Cat"}
	if err = goent.Insert(db.Animal).OnTransaction(tx).One(cat); err != nil {
		return err // triggers rollback
	}

	dog := &Animal{Name: "Dog"}
	if err = goent.Insert(db.Animal).OnTransaction(tx).One(dog); err != nil {
		return err // triggers rollback
	}
	return nil // commits transaction
})

func (*DB) BeginTransactionContext

func (db *DB) BeginTransactionContext(ctx context.Context, isolation sql.IsolationLevel, txFunc func(Transaction) error) (err error)

BeginTransactionContext begins a Transaction with the specified context and isolation level. Any panic or error will trigger a rollback.

Example:

err = db.BeginTransactionContext(context.Background(), sql.LevelSerializable, func(tx goent.Transaction) error {
	cat := &Animal{Name: "Cat"}
	if err = goent.Insert(db.Animal).OnTransaction(tx).One(cat); err != nil {
		return err // triggers rollback
	}

	dog := &Animal{Name: "Dog"}
	if err = goent.Insert(db.Animal).OnTransaction(tx).One(dog); err != nil {
		return err // triggers rollback
	}
	return nil // commits transaction
})

func (*DB) DriverName added in v0.8.2

func (db *DB) DriverName() string

DriverName returns the database name (SQLite, PostgreSQL, etc.).

func (*DB) DropTables added in v0.8.2

func (db *DB) DropTables() error

func (*DB) NewTransaction

func (db *DB) NewTransaction() (model.Transaction, error)

NewTransaction creates a new Transaction on the database using the default level.

NewTransaction uses context.Background internally; to specify the context and the isolation level, use [NewTransactionContext].

func (*DB) NewTransactionContext

func (db *DB) NewTransactionContext(ctx context.Context, isolation sql.IsolationLevel) (model.Transaction, error)

NewTransactionContext creates a new Transaction with the specified context and isolation level.

func (*DB) RawExecContext

func (db *DB) RawExecContext(ctx context.Context, rawSql string, args ...any) error

RawExecContext executes a raw SQL statement without returning rows.

Example:

err := db.RawExecContext(ctx, "UPDATE users SET name = ? WHERE id = ?", "John", 1)

func (*DB) RawQueryContext

func (db *DB) RawQueryContext(ctx context.Context, rawSql string, args ...any) (model.Rows, error)

RawQueryContext executes a raw SQL query and returns rows.

Example:

rows, err := db.RawQueryContext(ctx, "SELECT * FROM users WHERE id = ?", 1)
if err != nil {
	return err
}
defer rows.Close()
for rows.Next() {
	// scan rows
}

func (*DB) SetDriver

func (db *DB) SetDriver(driver model.Driver)

SetDriver sets the database driver.

func (*DB) Stats

func (db *DB) Stats() sql.DBStats

Stats returns the database stats as sql.DBStats.

type Dict

type Dict = map[string]any

func CollectFields

func CollectFields[T any](builder *Builder, table *Table[T], valueOf reflect.Value, ignores []string) (Dict, int)

CollectFields collects primary key and non-primary key fields from a struct value. It sets the builder's returning information for auto-increment primary keys and returns a map of primary key column names to their values.

func MatchData

func MatchData[T any](table *Table[T], obj T) Dict

MatchData matches the non-zero fields of the given object to a dictionary of column names and values. Nil pointer fields are skipped (not included in the result).

type DuplicateIndexError

type DuplicateIndexError struct {
	TableName string
	IndexName string
}

DuplicateIndexError is returned when two or more indexes have the same name but different settings.

func (*DuplicateIndexError) Error

func (e *DuplicateIndexError) Error() string

type Entity

type Entity interface {
	GetID() int64
	SetID(int64)
}

Entity is the interface for entities that have an ID.

type FetchCreator

type FetchCreator func(TableInfo, []*Field, []*Foreign) FetchFunc

FetchCreator is a function type that creates a FetchFunc based on table info, fields, and foreign.

type FetchFunc

type FetchFunc func(target any) []any

FetchFunc is a function type that returns a slice of pointers to struct fields for scanning.

func CreateFetchFunc

func CreateFetchFunc(tblInfo TableInfo, fields []*Field, foreigns []*Foreign) FetchFunc

CreateFetchFunc creates a FetchFunc based on the specified fields and foreign relationships. It handles both aggregate function results and regular table field scanning.

func CreateFetchOne

func CreateFetchOne(tblInfo TableInfo, fields []*Field, foreigns []*Foreign) FetchFunc

CreateFetchOne creates a FetchFunc that scans a single row into the first field of the target struct. This is used for queries that return a single result.

type Fetcher

type Fetcher[R any] struct {
	NewTarget func() *R
	FetchTo   FetchFunc
	*Handler
}

Fetcher handles fetching query results into typed structs.

func NewFetcher

func NewFetcher[R any](hd *Handler, newTarget func() *R) *Fetcher[R]

NewFetcher creates a new Fetcher with the given handler and target constructor.

Example:

fetcher := NewFetcher(handler, func() *User { return &User{} })

func (*Fetcher[R]) FetchResult

func (f *Fetcher[R]) FetchResult(query model.Query) iter.Seq2[*R, error]

FetchResult returns an iterator that yields typed results from the query result set. This is memory-efficient for processing large result sets.

Example:

for user, err := range fetcher.FetchResult(query) {
	if err != nil {
		return err
	}
	fmt.Println(user.Name)
}

func (*Fetcher[R]) FetchRows

func (f *Fetcher[R]) FetchRows(rows model.Rows, err error, limit int) ([]*R, error)

FetchRows fetches all rows from the result set into a slice of typed pointers. It closes the rows and returns the slice of results.

Example:

users, err := fetcher.FetchRows(rows, err, 100)
if err != nil {
	return nil, err
}
fmt.Println(len(users)) // number of fetched records

type Field

type Field struct {
	TableAddr  uintptr
	FieldId    int
	ColumnName string
	AliasName  string
	Function   string
}

Field represents a database field with its table reference and column name.

func (*Field) Func

func (f *Field) Func(name string) *Field

Func applies a SQL function to the field (e.g., "UPPER", "LOWER", "COUNT").

Example:

field := goent.Expr("UPPER(name)").(*goent.Field)
users, _ := db.User.Filter(goent.Equals(field, "JOHN")).Select().All()

func (*Field) GetFid

func (f *Field) GetFid() int

GetFid returns the field ID, resolving it from the table metadata if needed.

func (*Field) Simple

func (f *Field) Simple() string

Simple returns the column name with any SQL function applied. It does not include the table name.

func (*Field) String

func (f *Field) String() string

String returns the qualified field name (table.column) with any SQL function applied.

type FieldNotFoundError

type FieldNotFoundError struct {
	Field string
}

FieldNotFoundError is returned when a field or table cannot be found.

func (*FieldNotFoundError) Error

func (e *FieldNotFoundError) Error() string

type Foreign

type Foreign struct {
	Type       ForeignType
	MountField string
	ForeignKey string
	Reference  *Field
	Middle     *ThirdParty
	Where      Condition
}

Foreign represents a foreign key relationship between two tables. It contains the relationship type, mounting field, foreign key column, reference field, and optional middle table for many-to-many relationships.

func GetForeign

func GetForeign[T, R any](table *Table[T], refer *Table[R]) *Foreign

GetForeign retrieves the foreign key relationship between two tables. It searches by table name first, then by table address. Returns nil if no foreign key relationship is found.

Example:

foreign := GetForeign(userTable, addressTable)
if foreign != nil {
	fmt.Println(foreign.Type) // prints O2O, O2M, M2O, or M2M
}

type ForeignKeyNotFoundError

type ForeignKeyNotFoundError struct {
	ForeignKey string
}

ForeignKeyNotFoundError is returned when a foreign key column cannot be found.

func (*ForeignKeyNotFoundError) Error

func (e *ForeignKeyNotFoundError) Error() string

type ForeignType

type ForeignType uint

ForeignType represents the type of foreign key relationship. Values: O2O (one-to-one), O2M (one-to-many), M2O (many-to-one), M2M (many-to-many).

const (
	O2O ForeignType // one-to-one
	O2M             // one-to-many
	M2O             // many-to-one
	M2M             // many-to-many
)

type GenScanFields added in v0.8.4

type GenScanFields interface {
	ScanFields() []any
}

GenScanFields is an interface for Model which is modifiable by goent-gen.

type Group

type Group struct {
	Having Condition
	*Field
}

Group represents a GROUP BY clause with a field and optional HAVING condition.

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler handles database query execution and result processing.

func NewHandler

func NewHandler(ctx context.Context, conn model.Connection, cfg *model.DatabaseConfig) *Handler

NewHandler creates a new Handler with the given context, connection, and database config.

func (*Handler) BatchReturning

func (h *Handler) BatchReturning(query model.Query, valueOf reflect.Value, returnFid int) error

BatchReturning executes a query with RETURNING clause for batch inserts. It scans multiple returned rows into successive elements of the slice.

Example:

err := hd.BatchReturning(query, valueOf, returnFid)
if err != nil {
	return err
}
fmt.Println(valueOf.Len()) // number of inserted records

func (*Handler) ErrHandler

func (h *Handler) ErrHandler(query model.Query) error

ErrHandler handles query errors using the configured error handler.

func (*Handler) ExecuteNoReturn

func (h *Handler) ExecuteNoReturn(query model.Query) error

ExecuteNoReturn executes a query that does not return any rows (INSERT, UPDATE, DELETE). It logs the query execution time and handles any errors.

Example:

err := hd.ExecuteNoReturn(query)
if err != nil {
	return err
}

func (*Handler) ExecuteReturning

func (h *Handler) ExecuteReturning(query model.Query, valueOf reflect.Value, returnFid int) error

ExecuteReturning executes a query with RETURNING clause and scans the result into the specified field. It is used for INSERT statements that return auto-generated values like IDs.

Example:

err := hd.ExecuteReturning(query, valueOf, returnFid)
if err != nil {
	return err
}
fmt.Println(valueOf.Field(returnFid).Int()) // printed generated ID

func (*Handler) InfoHandler

func (h *Handler) InfoHandler(query model.Query)

InfoHandler logs the query information using the configured info handler.

func (*Handler) QueryResult

func (h *Handler) QueryResult(query model.Query) (model.Rows, error)

QueryResult executes a query that returns rows (SELECT). It returns the rows iterator and any error encountered.

Example:

rows, err := hd.QueryResult(query)
if err != nil {
	return nil, err
}
defer rows.Close()
for rows.Next() {
	// scan rows
}

type Index

type Index struct {
	IsUnique   bool // Whether the index is unique
	IsAutoIncr bool // Whether the column is auto-increment
	*Column         // Embedded column information
}

Index represents a database index with uniqueness and auto-increment flags.

type JoinTable

type JoinTable struct {
	JoinType model.JoinType
	Table    *model.Table

	On Condition
	// contains filtered or unexported fields
}

JoinTable represents a JOIN clause with the join type, target table, and ON condition.

type ManyToSomeRelation

type ManyToSomeRelation struct {
	IsDefault bool
	// contains filtered or unexported fields
}

ManyToSomeRelation represents a many-to-one or many-to-many relationship between tables.

type Migration

type Migration struct {
	// contains filtered or unexported fields
}

Migration provides methods for database schema migrations.

func Migrate

func Migrate(db *DB) Migration

Migrate creates a new Migration instance for the given database.

func (Migration) KeywordHandler added in v0.8.4

func (m Migration) KeywordHandler(name string) string

func (Migration) OnSchema

func (m Migration) OnSchema(schema string) SchemaMigration

func (Migration) OnTable

func (m Migration) OnTable(table string) TableMigration

type NilMarker

type NilMarker struct{}

NilMarker is a special type to indicate a nil pointer field for IS NULL conditions.

type NoPrimaryKeyError

type NoPrimaryKeyError struct {
	TypeName string
}

NoPrimaryKeyError is returned when a struct does not have a primary key defined.

func (*NoPrimaryKeyError) Error

func (e *NoPrimaryKeyError) Error() string

type OneToSomeRelation

type OneToSomeRelation struct {
	IsOneToMany bool
	// contains filtered or unexported fields
}

OneToSomeRelation represents a one-to-one or one-to-many relationship between tables.

type Order

type Order struct {
	Desc bool
	*Field
}

Order represents an ORDER BY clause with a field and descending flag.

type Pagination

type Pagination[T, R any] struct {
	TotalValues int64 `json:"totalValues"` // TotalValues is the total number of values in the query result.
	TotalPages  int   `json:"totalPages"`  // TotalPages is the total number of pages in the pagination.

	PageValues int `json:"pageValues"` // PageValues is the number of values on the current page.
	PageSize   int `json:"pageSize"`   // PageSize is the maximum number of values per page.

	CurrentPage     int  `json:"currentPage"`     // CurrentPage is the current page number.
	HasPreviousPage bool `json:"hasPreviousPage"` // HasPreviousPage is true if there is a previous page.
	PreviousPage    int  `json:"previousPage"`    // PreviousPage is the number of the previous page.
	HasNextPage     bool `json:"hasNextPage"`     // HasNextPage is true if there is a next page.
	NextPage        int  `json:"nextPage"`        // NextPage is the number of the next page.

	StartIndex int  `json:"startIndex"` // StartIndex is the index of the first value on the current page.
	EndIndex   int  `json:"endIndex"`   // EndIndex is the index of the last value on the current page.
	Values     []*R `json:"values"`     // Values is the slice of values on the current page.
}

Pagination holds paginated query results with metadata.

type Pair

type Pair struct {
	Key   string
	Value any
}

Pair represents a key-value pair.

type RelationFunc

type RelationFunc func(b body, typeOf reflect.Type) any

RelationFunc is a function type that defines how to handle a relation field. It takes a body struct and the type of the relation field as parameters. The function returns the value of the relation field.

type ResultFloat

type ResultFloat = ResultFunc[float64] // Float64 result type

type ResultFunc

type ResultFunc[T any] struct {
	Value T // The result value
}

ResultFunc holds the result of a function query. Example: ResultStr = ResultFunc[string]

type ResultInt

type ResultInt = ResultFunc[int] // Int result type

type ResultLong

type ResultLong = ResultFunc[int64] // Int64 result type

type ResultStr

type ResultStr = ResultFunc[string] // String result type

type SchemaMigration

type SchemaMigration struct {
	Migration
	// contains filtered or unexported fields
}

SchemaMigration provides migration methods scoped to a specific schema.

func (SchemaMigration) OnTable

func (m SchemaMigration) OnTable(table string) TableMigration

type StateDelete

type StateDelete[T any] struct {
	*StateWhere
	// contains filtered or unexported fields
}

StateDelete represents a DELETE query state for removing records from a table.

func (*StateDelete[T]) Exec

func (s *StateDelete[T]) Exec() error

Exec executes the DELETE query.

func (*StateDelete[T]) Filter

func (s *StateDelete[T]) Filter(args ...Condition) *StateDelete[T]

Filter adds filter conditions to the DELETE query.

func (*StateDelete[T]) Match

func (s *StateDelete[T]) Match(obj T) *StateDelete[T]

Match sets the WHERE conditions based on the non-zero fields of the given object.

func (*StateDelete[T]) OnTransaction

func (s *StateDelete[T]) OnTransaction(tx model.Transaction) *StateDelete[T]

func (*StateDelete[T]) Where

func (s *StateDelete[T]) Where(where string, args ...any) *StateDelete[T]

Where adds a WHERE clause to the DELETE query.

type StateInsert

type StateInsert[T any] struct {
	*StateWhere
	// contains filtered or unexported fields
}

StateInsert represents an INSERT query state for inserting new records into a table.

func (*StateInsert[T]) All

func (s *StateInsert[T]) All(retPK bool, data []*T) error

All inserts multiple records into the table.

func (*StateInsert[T]) OnTransaction

func (s *StateInsert[T]) OnTransaction(tx model.Transaction) *StateInsert[T]

OnTransaction sets the transaction for the insert operation.

func (*StateInsert[T]) One

func (s *StateInsert[T]) One(obj *T) error

One inserts a single record into the table.

type StateSave

type StateSave[T any] struct {
	*StateWhere
	// contains filtered or unexported fields
}

StateSave represents a save state that intelligently inserts or updates records based on primary key presence.

func (*StateSave[T]) Map

func (s *StateSave[T]) Map(value Dict) error

Map saves records from a map, inserting or updating based on primary key presence.

func (*StateSave[T]) Match

func (s *StateSave[T]) Match(obj T) *StateSave[T]

Match sets the WHERE conditions based on the non-zero fields of the given object.

func (*StateSave[T]) OnTransaction

func (s *StateSave[T]) OnTransaction(tx model.Transaction) *StateSave[T]

OnTransaction sets the transaction for the save operation.

func (*StateSave[T]) One

func (s *StateSave[T]) One(obj *T) error

One saves a record to the table, inserting if no primary key exists or updating if it does.

func (*StateSave[T]) Take

func (s *StateSave[T]) Take(i int) *StateSave[T]

Take takes i elements

type StateSelect

type StateSelect[T, R any] struct {
	*StateWhere
	// contains filtered or unexported fields
}

StateSelect represents a SELECT query state with type parameters for table and result types.

func NewSelectFunc

func NewSelectFunc[T, R any](state *StateWhere, table *Table[T], col, fun string) *StateSelect[T, R]

NewSelectFunc creates a new StateSelect with a function applied to the specified column. T is the model type, R is the result type.

func NewStateSelect

func NewStateSelect[T, R any](ctx context.Context, table *Table[T]) *StateSelect[T, R]

NewStateSelect creates a new StateSelect for querying data from a table.

func NewStateSelectFrom

func NewStateSelectFrom[T, R any](state *StateWhere, table *Table[T]) *StateSelect[T, R]

NewStateSelectFrom creates a new StateSelect for querying data from a table

func (*StateSelect[T, R]) All

func (s *StateSelect[T, R]) All() ([]*R, error)

All executes the query and returns all rows as a slice.

func (*StateSelect[T, R]) Avg

func (s *StateSelect[T, R]) Avg(col string) (int64, error)

Avg returns the average value of the specified column. Example: avg, err := db.Animal.Select().Avg("price")

func (*StateSelect[T, R]) AvgFloat

func (s *StateSelect[T, R]) AvgFloat(col string) (float64, error)

AvgFloat returns the average value of the specified column as float64. Example: avg, err := db.Animal.Select().AvgFloat("price")

func (*StateSelect[T, R]) CopyFrom

func (s *StateSelect[T, R]) CopyFrom(ob *Builder, conn model.Connection) *StateSelect[T, R]

CopyFrom copies the query builder state from another builder and connection.

func (*StateSelect[T, R]) Count

func (s *StateSelect[T, R]) Count(col string) (int64, error)

Count returns the count of rows matching the query. Example: count, err := db.Animal.Count("id")

func (*StateSelect[T, R]) Filter

func (s *StateSelect[T, R]) Filter(args ...Condition) *StateSelect[T, R]

Filter adds filter conditions to the select query.

func (*StateSelect[T, R]) GetJoinForeign

func (s *StateSelect[T, R]) GetJoinForeign() *Foreign

GetJoinForeign returns the foreign key relationship for the joined table.

func (*StateSelect[T, R]) GetJoinForeigns

func (s *StateSelect[T, R]) GetJoinForeigns() []*Foreign

GetJoinForeigns returns all foreign key relationships for the joined tables.

func (*StateSelect[T, R]) GroupBy

func (s *StateSelect[T, R]) GroupBy(args ...string) *StateSelect[T, R]

GroupBy makes a group by args query

func (*StateSelect[T, R]) IterRows

func (s *StateSelect[T, R]) IterRows() iter.Seq2[*R, error]

IterRows return a iterator on rows.

func (*StateSelect[T, R]) Join

func (s *StateSelect[T, R]) Join(joinType model.JoinType, info TableInfo, on Condition) *StateSelect[T, R]

Join joins another table with a condition

func (*StateSelect[T, R]) LeftJoin

func (s *StateSelect[T, R]) LeftJoin(fkey string, refer *Field) *StateSelect[T, R]

LeftJoin joins another table with a condition on left table

func (*StateSelect[T, R]) Map

func (s *StateSelect[T, R]) Map(key string) (map[int64]*R, error)

Map executes the query and returns results as a map keyed by the specified column.

func (*StateSelect[T, R]) Match

func (s *StateSelect[T, R]) Match(obj T) *StateSelect[T, R]

Match sets the WHERE conditions based on the non-zero fields of the given object.

func (*StateSelect[T, R]) Max

func (s *StateSelect[T, R]) Max(col string) (int64, error)

Max returns the maximum value of the specified column. Example: max, err := db.Animal.Select().Max("id")

func (*StateSelect[T, R]) MaxFloat

func (s *StateSelect[T, R]) MaxFloat(col string) (float64, error)

MaxFloat returns the maximum value of the specified column as float64. Example: max, err := db.Animal.Select().MaxFloat("price")

func (*StateSelect[T, R]) Min

func (s *StateSelect[T, R]) Min(col string) (int64, error)

Min returns the minimum value of the specified column. Example: min, err := db.Animal.Select().Min("id")

func (*StateSelect[T, R]) MinFloat

func (s *StateSelect[T, R]) MinFloat(col string) (float64, error)

MinFloat returns the minimum value of the specified column as float64. Example: min, err := db.Animal.Select().MinFloat("price")

func (*StateSelect[T, R]) OnTransaction

func (s *StateSelect[T, R]) OnTransaction(tx model.Transaction) *StateSelect[T, R]

OnTransaction sets a transaction for the select query and enables FOR UPDATE lock.

func (*StateSelect[T, R]) One

func (s *StateSelect[T, R]) One() (*R, error)

One executes the query and returns the first row as a single result.

func (*StateSelect[T, R]) OrderBy

func (s *StateSelect[T, R]) OrderBy(args ...string) *StateSelect[T, R]

OrderBy makes a ordained by args query

func (*StateSelect[T, R]) Pagination

func (s *StateSelect[T, R]) Pagination(page, size int) (*Pagination[T, R], error)

Pagination return a paginated query as Pagination.

Default values for page and size are 1 and 10 respectively.

func (*StateSelect[T, R]) Query

func (s *StateSelect[T, R]) Query(creator FetchCreator) (*Fetcher[R], model.Query)

Query returns a Fetcher and a Query.

func (*StateSelect[T, R]) QueryFetch

func (s *StateSelect[T, R]) QueryFetch(to FetchFunc) (*Fetcher[R], model.Query)

QueryFetch returns a Fetcher and a Query.

func (*StateSelect[T, R]) QueryRows

func (s *StateSelect[T, R]) QueryRows(to FetchFunc) (data []*R, err error)

QueryRows executes the query and returns all rows as a slice.

func (*StateSelect[T, R]) Rank

func (s *StateSelect[T, R]) Rank(key string) (map[int64][]*R, error)

Rank executes the query and returns results as a map keyed by the specified column, with each key mapping to a slice of results.

func (*StateSelect[T, R]) RollUP

func (s *StateSelect[T, R]) RollUP() *StateSelect[T, R]

RollUP enables rollup for aggregation queries.

Example:

results, _ := db.Order.Select("status", "total").GroupBy("status").RollUP().All()

func (*StateSelect[T, R]) Select

func (s *StateSelect[T, R]) Select(fields ...any) *StateSelect[T, R]

Select specifies the fields to select from the table.

func (*StateSelect[T, R]) Skip

func (s *StateSelect[T, R]) Skip(i int) *StateSelect[T, R]

Skip skips i elements

func (*StateSelect[T, R]) Sum

func (s *StateSelect[T, R]) Sum(col string) (int64, error)

Sum returns the sum of values in the specified column. Example: sum, err := db.Animal.Select().Sum("price")

func (*StateSelect[T, R]) SumFloat

func (s *StateSelect[T, R]) SumFloat(col string) (float64, error)

SumFloat returns the sum of values in the specified column as float64. Example: sum, err := db.Animal.Select().SumFloat("price")

func (*StateSelect[T, R]) Take

func (s *StateSelect[T, R]) Take(i int) *StateSelect[T, R]

Take takes i elements

func (*StateSelect[T, R]) ToLower

func (s *StateSelect[T, R]) ToLower(col string) ([]string, error)

ToLower returns the lowercase version of the specified column values. Example: names, err := db.Animal.Select().ToLower("name")

func (*StateSelect[T, R]) ToUpper

func (s *StateSelect[T, R]) ToUpper(col string) ([]string, error)

ToUpper returns the uppercase version of the specified column values. Example: names, err := db.Animal.Select().ToUpper("name")

func (*StateSelect[T, R]) Where

func (s *StateSelect[T, R]) Where(where string, args ...any) *StateSelect[T, R]

Where adds a WHERE clause to the select query.

type StateUpdate

type StateUpdate[T any] struct {
	*StateWhere
	// contains filtered or unexported fields
}

StateUpdate represents an UPDATE query state for modifying records in a table.

func (*StateUpdate[T]) Exec

func (s *StateUpdate[T]) Exec() error

Exec executes the UPDATE query and returns any error.

Example:

change := Pair{Key:"name", Value:"John"}
err := db.User.Where("id = ?", 1).Update().Set(change).Exec()

func (*StateUpdate[T]) Filter

func (s *StateUpdate[T]) Filter(args ...Condition) *StateUpdate[T]

Filter adds filter conditions to the UPDATE query.

func (*StateUpdate[T]) Join

func (s *StateUpdate[T]) Join(joinType model.JoinType, info TableInfo, on Condition) *StateUpdate[T]

Join joins another table with a condition for UPDATE operations.

Example:

info := GetTableInfo(referAddr)
err := db.User.Update().Join(model.InnerJoin, *info, EqualsField(...)).Set(...).Exec()

func (*StateUpdate[T]) LeftJoin

func (s *StateUpdate[T]) LeftJoin(fkey string, refer *Field) *StateUpdate[T]

LeftJoin performs a LEFT JOIN with another table using a foreign key relationship.

Example:

refer := userTable.Field("role_id")
change := Pair{Key:"role_name", Value:"admin"}
err := db.User.Update().LeftJoin("role_id", refer).Set(change).Exec()

func (*StateUpdate[T]) Match

func (s *StateUpdate[T]) Match(obj T) *StateUpdate[T]

Match sets the WHERE conditions based on the primary key and unique indexes of the given object.

func (*StateUpdate[T]) OnTransaction

func (s *StateUpdate[T]) OnTransaction(tx model.Transaction) *StateUpdate[T]

OnTransaction executes the UPDATE query within a transaction.

func (*StateUpdate[T]) Set

func (s *StateUpdate[T]) Set(pairs ...Pair) *StateUpdate[T]

Set sets the column values to update. Each pair is a key-value map.

Example:

 changes := []Pair{
		{Key:"name", Value:"John"},
		{Key:"email", Value:"john@example.com"},
	}
	err := db.User.Where("id = ?", 1).Update().Set(changes...).Exec()

func (*StateUpdate[T]) SetMap

func (s *StateUpdate[T]) SetMap(changes Dict) *StateUpdate[T]

SetMap sets multiple column values using a map.

Example:

changes := map[string]any{"name": "John", "email": "john@example.com"}
err := db.User.Where("id = ?", 1).Update().SetMap(changes).Exec()

func (*StateUpdate[T]) Take

func (s *StateUpdate[T]) Take(i int) *StateUpdate[T]

Take limits the number of records to update.

Example:

change := Pair{Key:"status", Value:"archived"}
err := db.User.Update().Set(change).Take(100).Exec() // updates only 100 records

func (*StateUpdate[T]) Where

func (s *StateUpdate[T]) Where(where string, args ...any) *StateUpdate[T]

Where adds a WHERE clause to the UPDATE query.

type StateWhere

type StateWhere struct {
	// contains filtered or unexported fields
}

StateWhere represents a query state with WHERE clause building capabilities.

func MatchWhere

func MatchWhere[T any](s *StateWhere, table *Table[T], obj T) *StateWhere

MatchWhere creates a StateWhere with conditions matching the non-zero fields of the given object.

func NewStateWhere

func NewStateWhere(ctx context.Context) *StateWhere

NewStateWhere creates a new StateWhere with the given context.

func (*StateWhere) Filter

func (s *StateWhere) Filter(conds ...Condition) *StateWhere

func (*StateWhere) OnTransaction

func (s *StateWhere) OnTransaction(tx model.Transaction) *StateWhere

func (*StateWhere) Prepare

func (s *StateWhere) Prepare(drv model.Driver) *Handler

func (*StateWhere) Where

func (s *StateWhere) Where(where string, args ...any) *StateWhere

type Table

type Table[T any] struct {
	Model *T
	Cache *utils.CoMap[int64, T]
	State *StateWhere

	TableInfo
	// contains filtered or unexported fields
}

Table represents a database table with its model and metadata. It provides methods for querying, inserting, updating, and deleting records.

func SimpleTable

func SimpleTable[T any](db *DB, tableName, SchemaName string) *Table[T]

SimpleTable creates a new Table instance for a simple table without foreign keys. It is useful for tables that do not have complex relationships with other tables.

Example:

type SimpleRecord struct {
	ID   int64
	Name string
}
table := SimpleTable[SimpleRecord](db, "simple_record", "")

func (*Table[T]) Avg

func (t *Table[T]) Avg(col string) (int64, error)

Avg returns the average value of the specified column across all rows. Example: avg, err := db.Animal.Avg("price")

func (*Table[T]) AvgFloat

func (t *Table[T]) AvgFloat(col string) (float64, error)

AvgFloat returns the average value of the specified column across all rows as float64. Example: avg, err := db.Animal.AvgFloat("price")

func (*Table[T]) CacheOne

func (t *Table[T]) CacheOne(row any)

CacheOne caches a single row in the table's cache using its ID as the key.

func (*Table[T]) Count

func (t *Table[T]) Count(col string) (int64, error)

Count returns the count of all rows in the table. Example: count, err := db.Animal.Count("id")

func (*Table[T]) Delete

func (t *Table[T]) Delete() *StateDelete[T]

Delete creates a new StateDelete for deleting records from the table.

Example:

err := db.User.Filter(goent.Equals("status", "deleted")).Delete().Exec()

func (*Table[T]) DeleteContext

func (t *Table[T]) DeleteContext(ctx context.Context) *StateDelete[T]

DeleteContext creates a new StateDelete with a specific context.

func (*Table[T]) Dest

func (t *Table[T]) Dest() (*T, []any)

Dest returns a new instance of T and a slice of destination pointers for scanning. The destination slice is sized to hold all columns.

func (*Table[T]) Drop

func (t *Table[T]) Drop() error

Drop drops (deletes) the table from the database.

Example:

err := db.User.Drop()
if err != nil {
	log.Fatal(err)
}

func (*Table[T]) Filter

func (t *Table[T]) Filter(args ...Condition) *Table[T]

Filter adds filter conditions to the table's query using the default context.

Example:

users, err := db.User.Filter(goent.Equals("status", "active")).Select().All()

func (*Table[T]) FilterContext

func (t *Table[T]) FilterContext(ctx context.Context, args ...Condition) *Table[T]

FilterContext adds filter conditions to the table's query with a specific context.

func (*Table[T]) Insert

func (t *Table[T]) Insert() *StateInsert[T]

Insert creates a new StateInsert for inserting records into the table.

Example:

user := &User{Name: "John", Email: "john@example.com"}
err := db.User.Insert().One(user)

func (*Table[T]) InsertContext

func (t *Table[T]) InsertContext(ctx context.Context) *StateInsert[T]

InsertContext creates a new StateInsert with a specific context.

func (*Table[T]) Max

func (t *Table[T]) Max(col string) (int64, error)

Max returns the maximum value of the specified column across all rows. Example: max, err := db.Animal.Max("id")

func (*Table[T]) MaxFloat

func (t *Table[T]) MaxFloat(col string) (float64, error)

MaxFloat returns the maximum value of the specified column across all rows as float64. Example: max, err := db.Animal.MaxFloat("price")

func (*Table[T]) Min

func (t *Table[T]) Min(col string) (int64, error)

Min returns the minimum value of the specified column across all rows. Example: min, err := db.Animal.Min("id")

func (*Table[T]) MinFloat

func (t *Table[T]) MinFloat(col string) (float64, error)

MinFloat returns the minimum value of the specified column across all rows as float64. Example: min, err := db.Animal.MinFloat("price")

func (*Table[T]) Save

func (t *Table[T]) Save() *StateSave[T]

Save creates a new StateSave for saving (insert or update) records to the table.

Example:

user := &User{ID: 1, Name: "John"} // ID > 0 means update
err := db.User.Save().One(user)

func (*Table[T]) SaveContext

func (t *Table[T]) SaveContext(ctx context.Context) *StateSave[T]

SaveContext creates a new StateSave with a specific context.

func (*Table[T]) Select

func (t *Table[T]) Select(fields ...any) *StateSelect[T, T]

Select creates a new StateSelect for querying records from the table.

Example:

users, err := db.User.Select("id", "name", "email").All()

func (*Table[T]) SelectContext

func (t *Table[T]) SelectContext(ctx context.Context, fields ...any) *StateSelect[T, T]

SelectContext creates a new StateSelect with a specific context.

func (*Table[T]) SetDB

func (t *Table[T]) SetDB(db *DB)

SetDB sets the database connection for the table.

func (*Table[T]) Sum

func (t *Table[T]) Sum(col string) (int64, error)

Sum returns the sum of values in the specified column across all rows. Example: sum, err := db.Animal.Sum("price")

func (*Table[T]) SumFloat

func (t *Table[T]) SumFloat(col string) (float64, error)

SumFloat returns the sum of values in the specified column across all rows as float64. Example: sum, err := db.Animal.SumFloat("price")

func (*Table[T]) ToLower

func (t *Table[T]) ToLower(col string) ([]string, error)

ToLower returns the lowercase version of the specified column values across all rows. Example: names, err := db.Animal.ToLower("name")

func (*Table[T]) ToUpper

func (t *Table[T]) ToUpper(col string) ([]string, error)

ToUpper returns the uppercase version of the specified column values across all rows. Example: names, err := db.Animal.ToUpper("name")

func (*Table[T]) Update

func (t *Table[T]) Update() *StateUpdate[T]

Update creates a new StateUpdate for updating records in the table.

Example:

change := goent.Pair{Key: "name", Value: "John"}
err := db.User.Filter(goent.Equals("status", "active")).Update().Set(change).Exec()

func (*Table[T]) UpdateContext

func (t *Table[T]) UpdateContext(ctx context.Context) *StateUpdate[T]

UpdateContext creates a new StateUpdate with a specific context.

func (*Table[T]) Where

func (t *Table[T]) Where(where string, args ...any) *Table[T]

Where adds a WHERE clause to the table's query using the default context.

Example:

users, err := db.User.Where("age > ?", 18).Select().All()

func (*Table[T]) WhereContext

func (t *Table[T]) WhereContext(ctx context.Context, where string, args ...any) *Table[T]

WhereContext adds a WHERE clause to the table's query with a specific context.

type TableInfo

type TableInfo struct {
	TableAddr   uintptr             // TableAddr is the unique address of the table type.
	FieldName   string              // FieldName is the name of the field in the entity struct.
	TableId     int                 // TableId is the unique identifier for the table.
	TableName   string              // TableName is the name of the table in the database schema.
	SchemaId    int                 // SchemaId is the unique identifier for the schema.
	SchemaName  string              // SchemaName is the name of the schema in the database.
	PrimaryKeys []*Index            // PrimaryKeys is a list of primary key indexes.
	Indexes     []*Index            // Indexes is a list of non-primary key indexes.
	Columns     map[string]*Column  // Columns is a map of column names to Column metadata.
	Foreigns    map[string]*Foreign // Foreigns is a map of foreign key column names to Foreign metadata.
	Ignores     []string            // Ignores is a list of column names to ignore.
	// contains filtered or unexported fields
}

TableInfo contains metadata about a database table including columns, primary keys, and indexes. It is automatically populated when creating a Table using reflection.

func GetTableInfo

func GetTableInfo(addr uintptr) *TableInfo

GetTableInfo returns the table info for a given table address.

func NewTableReflect

func NewTableReflect(db *DB, typeOf reflect.Type, addr uintptr, fieldName, schema string,
	schemaId, tableId int) (reflect.Value, TableInfo)

NewTableReflect creates a new Table instance using reflection. It analyzes the struct type to extract table metadata including columns, primary keys, and indexes.

Example:

value, info := NewTableReflect(db, reflect.TypeFor[User](), addr, "User", "", 0, 0)
fmt.Println(info.TableName) // prints "user"

func (TableInfo) Check

func (info TableInfo) Check(col string) (int, bool)

Check returns the field ID and whether the column exists in the table. It returns (-1, true) for wildcard (*) or simple tables.

func (TableInfo) ColumnInfo

func (info TableInfo) ColumnInfo(name string) *Column

ColumnInfo returns the Column metadata for a given column name. It performs case-insensitive lookup.

func (TableInfo) Field

func (info TableInfo) Field(col string) *Field

Field returns a Field pointer for the specified column name. It panics if the column is not found in the table.

func (TableInfo) GetPrimaryInfo

func (info TableInfo) GetPrimaryInfo() (int, string, []string)

GetPrimaryInfo returns the primary key field ID, column name, and all primary key column names. It only returns valid field ID and column name for single-column primary keys.

func (TableInfo) GetSortedFields

func (info TableInfo) GetSortedFields() []*Field

GetSortedFields returns the table's columns sorted by FieldId for SELECT queries. This ensures consistent column ordering between queries and struct fields. Example:

fields := table.GetSortedFields()
for _, field := range fields {
	fmt.Println(field.ColumnName)
}

func (TableInfo) String

func (info TableInfo) String() string

String returns the table name as a string representation.

func (TableInfo) Table

func (info TableInfo) Table() *model.Table

Table returns a model.Table representation with schema and table name.

type TableMigration

type TableMigration struct {
	SchemaMigration
	// contains filtered or unexported fields
}

TableMigration provides migration methods scoped to a specific table.

func (TableMigration) DropColumn

func (m TableMigration) DropColumn(column string) error

func (TableMigration) DropTable

func (m TableMigration) DropTable() error

func (TableMigration) RenameColumn

func (m TableMigration) RenameColumn(column, newName string) error

func (TableMigration) RenameTable

func (m TableMigration) RenameTable(newName string) error

func (TableMigration) SchemaTable added in v0.8.4

func (m TableMigration) SchemaTable() (schema, table string)

type ThirdParty

type ThirdParty struct {
	Table       string
	Left, Right string
	Where       Condition
}

ThirdParty represents an intermediate junction table for many-to-many relationships. It contains the table name and the left/right column mappings.

type Transaction

type Transaction struct {
	model.Transaction
}

Transaction wraps a database transaction and provides additional functionality.

func (Transaction) BeginTransaction

func (t Transaction) BeginTransaction(txFunc func(Transaction) error) (err error)

BeginTransaction starts a nested transaction using a savepoint. Any panic or error will trigger a rollback of the savepoint.

Example:

err := tx.BeginTransaction(func(tx goent.Transaction) error {
	user := &User{Name: "John"}
	return goent.Insert(db.User).OnTransaction(tx).One(user)
})

type Value

type Value struct {
	Type   reflect.Kind
	Args   []any
	Length int
}

Value represents a value or list of values for use in query conditions.

func NewValue

func NewValue(value any) *Value

NewValue creates a new Value from a Go value. It handles both single values and slices.

Example:

value := NewValue([]int{1, 2, 3}) // creates IN (1, 2, 3)
value := NewValue(42)              // creates single value

Directories

Path Synopsis
cmd
goent-gen command
drivers

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL