goent

package module
v0.8.4 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2026 License: MIT Imports: 15 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 have a nice example and want to see if GoEnt can handle it, 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 an overview of GoEnt performance compared to other packages like ent, GORM, sqlc, and others.

  • 🔖 Type Safety;
    • Get errors at compile time
  • 📦 Auto Migrations;
    • Automatically 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 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 with 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:[email protected]: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 GoEnt, it's necessary to define a Database struct, this struct implements *goent.DB and pointers to all the structs that are to be mapped.

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 the primary key and all integer IDs are auto-incrementing.

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
}

If 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-incrementing 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 the not_incr tag to prevent auto-incrementing 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 without a value.

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

if err != nil {
	// Handle 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 {
	// Handle 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 {
	// Handle 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 {
	// Handle 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 {
	// Handle error
}

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

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

err = goent.AutoMigrate(db).OnTable("NewSelect").DropTable()
if err != nil {
	// Handle 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 {
	// Handle error
}

// AutoMigrate will output the result as a sql file, and not auto apply the migration
err = goent.AutoMigrate(db)
if err != nil {
	// Handle 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(nil) {
	// 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(nil) {

	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 {
	// Handle 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

GoEnt automatically uses generated ScanFields() methods when available, providing significant performance improvements without requiring manual changes to your code.

// Automatic usage - no changes needed!
users, err := db.User.Select().All()

// Manual usage with FetchFunc
query := db.User.Select()
for user, err := range query.IterRows(models.FetchUser()) {
	if err != nil {
		// Handle error
	}
	fmt.Printf("%+v\n", user)
}

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

Back to Contents

Benchmarks

Insprire from lauro-santana/go-orm-benchmarks.

cd tests/benchmark/run/
go run main.go -operation all --format both
Benchmark on MacMini M4
Operation Package N Avg ns/op Avg B/op Avg allocs/op percent
insert raw 13765 88704 624 12 =
goent 17432 76612 3127 55 -13.7%
goe 13497 101881 2643 31 14.8%
insert-bulk raw 136 9350581 6054818 39833 =
goent 100 10389264 6809070 44052 11.1%
goe 123 9511185 5202196 28013 1.7%
update raw 13556 89232 696 14 =
goent 13425 91718 3075 49 2.7%
goe 13413 103288 2594 27 15.7%
delete raw 13658 85000 256 8 =
goent 406078 3435 3301 23 -96.0%
goe 3054 697383 1066 17 720.4%
select-one raw 48766 24801 1760 49 =
goent 42130 27807 2366 43 12.1%
goe 41710 28711 3508 54 15.7%
select-page raw 3020 389815 57840 1350 =
goent 3565 333716 59001 1080 -14.4%
goe 2089 556273 55399 870 42.7%

Back to Contents

Documentation

Index

Constants

View Source
const TakeNoLimit = -1

TakeNoLimit is a constant indicating no limit on query results

Variables

This section is empty.

Functions

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 It closes the underlying driver connection and resets the 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 It fetches multiple values from the query result 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 It fetches a single value from the query result Example: count, err := FetchSingleResult[int64](query)

func FetchValue added in v0.8.4

func FetchValue(target any) []any

FetchValue returns a slice of pointers to the first field of the target struct.

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 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 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 It compares the TableAddr of both fields

Types

type Builder

type Builder struct {
	Type  model.QueryType // The type of query (SELECT, INSERT, UPDATE, DELETE)
	Joins []*JoinTable    // JOIN clauses for the query

	InsertValues [][]any        // Values for batch INSERT operations
	VisitFields  []*Field       // Fields to select or insert
	Changes      map[*Field]any // Changes for UPDATE operations

	Orders []*Order // ORDER BY clauses
	Groups []*Group // GROUP BY clauses
	Offset int      // OFFSET clause value

	Returning string // RETURNING clause for INSERT/UPDATE operations
	RollUp    string // ROLL UP clause for GROUP BY operations
	ForUpdate bool   // FOR UPDATE clause for transactional operations

	DeleteBuilder // Embedded DeleteBuilder for DELETE operations
}

Builder builds SQL statements for SELECT, INSERT, UPDATE, and DELETE operations It handles complex query construction including joins, conditions, and pagination

func NewBuilder added in v0.8.4

func NewBuilder() *Builder

NewBuilder creates a new Builder instance It initializes the builder with default values and an empty changes map

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 It builds all parts of the query including head, doing, joins, where, and tail

func (*Builder) BuildDoing

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

BuildDoing builds the SET clause for UPDATE or VALUES clause for INSERT operations It processes the changes or values and returns the query arguments

func (*Builder) BuildHead

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

BuildHead builds the SQL statement head for SELECT, INSERT, UPDATE, or DELETE operations It handles different query types and returns the initial query arguments

func (*Builder) BuildJoins

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

BuildJoins builds the JOIN clauses for the query It processes all join tables and returns the query arguments

func (*Builder) BuildTail

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

BuildTail builds the tail part of the query (GROUP BY, ORDER BY, LIMIT, OFFSET, RETURNING) It handles the trailing clauses for different query types

func (*Builder) IsInsertQuery added in v0.8.4

func (b *Builder) IsInsertQuery() bool

IsInsertQuery checks if the query is an insert query

func (*Builder) IsJoinQuery added in v0.8.4

func (b *Builder) IsJoinQuery() bool

IsJoinQuery checks if the query is a join query

func (*Builder) ResetForSave

func (b *Builder) ResetForSave()

ResetForSave resets the Builder for INSERT/UPDATE operations It clears changes, insert values, visit fields, and other operation-specific settings

func (*Builder) SetTable

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

SetTable sets the table for the query builder It delegates to the embedded DeleteBuilder to set the table

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 It contains information about the column's properties and mapping to Go struct fields

func GetTableColumn

func GetTableColumn(addr uintptr, name string) *Column

GetTableColumn returns the column info for a given table address and column name It looks up the column information from the table registry

func (*Column) GetInt64

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

GetInt64 returns the int64 value of the column from the given object It checks if the column is an int type before retrieving the value 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 It checks if the column is a string type before retrieving the value Returns ("", false) if the column is not a string type

type Condition

type Condition struct {
	Template string   // SQL template with placeholders
	Fields   []*Field // Fields referenced in the condition
	Values   []*Value // Values to bind to the placeholders
}

Condition represents a SQL WHERE condition with a template and associated fields/values It is used to build WHERE clauses in queries

func And

func And(branches ...Condition) Condition

And combines multiple conditions with AND logic It creates a compound condition where all branches must be true

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 It generates an equality check, handling NULL values appropriately

Example: using Table with field name

goent.Equals(db.OrderDetail.Field("order_id"), 1)

func EqualsField

func EqualsField(left, right *Field) Condition

EqualsField creates a condition that checks if one field is equal to another It generates an equality check between two fields

func EqualsMap

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

EqualsMap creates a condition that checks if multiple fields equal specified values It generates AND conditions for each key-value pair in the 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 It allows for raw SQL conditions with placeholders

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 creates a condition that checks if a field is greater than a value It generates a greater than comparison

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 creates a condition that checks if a field is greater than or equal to a value It generates a greater than or equal comparison

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 It generates a greater than or equal comparison between two fields

func GreaterField

func GreaterField(left, right *Field) Condition

GreaterField creates a condition that checks if one field is greater than another It generates a greater than comparison between two fields

func ILike

func ILike(left *Field, value string) Condition

ILike creates a case-insensitive LIKE condition It generates an ILIKE clause for case-insensitive pattern matching

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 It generates an IN clause for the field

func IsNotNull

func IsNotNull(left *Field) Condition

IsNotNull creates a condition that checks if a field is NOT NULL It generates an IS NOT NULL clause for the field

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 It generates an IS NULL clause for the field

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 It generates a less than comparison

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 It generates a less than or equal comparison

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 It generates a less than or equal comparison between two fields

func LessField

func LessField(left, right *Field) Condition

LessField creates a condition that checks if one field is less than another It generates a less than comparison between two fields

func Like

func Like(left *Field, value string) Condition

Like creates a condition that checks if a field matches a LIKE pattern It generates a LIKE clause for pattern matching

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

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

func MatchFilter added in v0.8.4

func MatchFilter[T any](table *Table[T], obj T) Condition

MatchFilter generates a condition based on the non-zero fields of the given object It creates an EqualsMap condition from the object's non-zero fields

func Not

func Not(cond Condition) Condition

Not creates a condition that negates another condition It wraps the condition in a NOT clause

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 It generates an inequality check, handling NULL values appropriately

Example:

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

func NotEqualsField

func NotEqualsField(left, right *Field) Condition

NotEqualsField creates a condition that checks if one field is not equal to another It generates an inequality check between two fields

func NotILike

func NotILike(left *Field, value string) Condition

NotILike creates a case-insensitive NOT LIKE condition It generates a NOT ILIKE clause for case-insensitive pattern matching

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 It generates a NOT IN clause for the field

func NotLike

func NotLike(left *Field, value string) Condition

NotLike creates a condition that checks if a field does not match a LIKE pattern It generates a NOT LIKE clause for pattern matching

func Or

func Or(branches ...Condition) Condition

Or combines multiple conditions with OR logic It creates a compound condition where at least one branch must be true

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) It checks if the condition is effectively empty

type DB

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

DB represents a database connection with its driver It provides methods for executing queries and managing transactions

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 It 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.) It returns the name of the underlying driver

func (*DB) DropTables added in v0.8.2

func (db *DB) DropTables() error

DropTables drops all registered tables from the database It generates and executes DROP TABLE statements for all registered tables For PostgreSQL, it adds CASCADE to the DROP TABLE statement

func (*DB) NewTransaction

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

NewTransaction creates a new Transaction on the database using the default level It 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 It returns a transaction object that can be used for atomic operations

func (*DB) RawExecContext

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

RawExecContext executes a raw SQL statement without returning rows It executes the provided SQL with the given arguments

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 It executes the provided SQL with the given arguments and returns the result set

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 It replaces the current driver with the provided one

func (*DB) Stats

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

Stats returns the database stats as sql.DBStats It returns statistics about the underlying database connection

type DeleteBuilder added in v0.8.4

type DeleteBuilder struct {
	Table *model.Table // The target table for the DELETE operation
	Where Condition    // The WHERE clause conditions
	Limit int          // The LIMIT clause value (only supported by SQLite)
	// contains filtered or unexported fields
}

DeleteBuilder builds DELETE SQL statements It handles WHERE conditions and LIMIT clause for delete operations

func CreateDeleteBuilder added in v0.8.4

func CreateDeleteBuilder() DeleteBuilder

CreateDeleteBuilder creates a new DeleteBuilder instance It initializes the builder with no limit and a buffer from the pool

func NewDeleteBuilder added in v0.8.4

func NewDeleteBuilder() *DeleteBuilder

NewDeleteBuilder creates a new DeleteBuilder pointer It initializes the builder with default values

func (*DeleteBuilder) Build added in v0.8.4

func (b *DeleteBuilder) Build() (sql string, args []any)

Build assembles the complete DELETE SQL statement It builds the head, WHERE clause, and tail, then returns the SQL and arguments

func (*DeleteBuilder) BuildHead added in v0.8.4

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

BuildHead builds the DELETE statement head It writes "DELETE FROM table_name" to the buffer

func (*DeleteBuilder) BuildTail added in v0.8.4

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

BuildTail builds the DELETE statement tail It adds the LIMIT clause if specified

func (*DeleteBuilder) BuildWhere added in v0.8.4

func (b *DeleteBuilder) BuildWhere(full bool) []any

BuildWhere builds the WHERE clause for the DELETE statement It processes the conditions and returns the query arguments

func (*DeleteBuilder) SetTable added in v0.8.4

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

SetTable sets the table for the DeleteBuilder It formats the full table name including schema using the driver

type Dict

type Dict = map[string]any

Dict is a type alias for a map of string keys to any values

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

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)
}

type Field

type Field struct {
	TableAddr  uintptr // Table address for table identification
	FieldId    int     // Field ID for quick lookup
	ColumnName string  // Database column name
	AliasName  string  // Alias name for the field
	Function   string  // SQL function to apply to the field
}

Field represents a database field with its table reference and column name It is used to reference columns in queries and conditions

func (*Field) Func

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

Func applies a SQL function to the field (e.g., "UPPER", "LOWER", "COUNT") It sets the function to be applied when the field is used in queries

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 It looks up the field ID from the table registry if not already set

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 It includes the table name for unambiguous reference

type Foreign

type Foreign struct {
	Type       ForeignType // Type of foreign key relationship
	MountField string      // Field name where the related object is mounted
	ForeignKey string      // Foreign key column name
	Reference  *Field      // Reference field in the related table
	Middle     *ThirdParty // Intermediate table for many-to-many relationships
	Where      Condition   // WHERE clause for filtering
}

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 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) 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

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 It extends Column with index-specific properties

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 // Whether the relationship is the default one
	// contains filtered or unexported fields
}

ManyToSomeRelation represents a many-to-one or many-to-many relationship between tables It extends attributeStrings with relationship-specific information

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 It is used to generate IS NULL conditions in WHERE clauses

type OneToSomeRelation

type OneToSomeRelation struct {
	IsOneToMany bool // Whether the relationship is one-to-many
	// contains filtered or unexported fields
}

OneToSomeRelation represents a one-to-one or one-to-many relationship between tables It extends attributeStrings with relationship-specific information

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"` // Total number of values in the query result
	TotalPages  int   `json:"totalPages"`  // Total number of pages in the pagination

	PageValues int `json:"pageValues"` // Number of values on the current page
	PageSize   int `json:"pageSize"`   // Maximum number of values per page

	CurrentPage     int  `json:"currentPage"`     // Current page number
	HasPreviousPage bool `json:"hasPreviousPage"` // Whether there is a previous page
	PreviousPage    int  `json:"previousPage"`    // Previous page number
	HasNextPage     bool `json:"hasNextPage"`     // Whether there is a next page
	NextPage        int  `json:"nextPage"`        // Next page number

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

Pagination holds paginated query results with metadata It provides information about total values, pages, and current page details

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 It is used to return single values from aggregate functions or scalar queries 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 {
	*StateDeleteWhere // Embedded StateDeleteWhere for WHERE clause construction
	// contains filtered or unexported fields
}

StateDelete represents a DELETE query state for removing records from a table It provides methods for building and executing DELETE queries with various options

func (*StateDelete[T]) Exec

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

Exec executes the DELETE query It builds and runs the DELETE statement with the specified conditions

func (*StateDelete[T]) Filter

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

Filter adds filter conditions to the DELETE query It appends the specified conditions to the WHERE clause

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 It automatically generates conditions for fields with non-zero values

func (*StateDelete[T]) OnTransaction

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

OnTransaction sets the transaction for the DELETE operation It ensures the delete runs within the specified transaction

func (*StateDelete[T]) Take added in v0.8.4

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

Take limits the number of records to delete Note: PostgreSQL does not support LIMIT in DELETE statements

Example:

change := Pair{Key:"status", Value:"archived"}
err := db.Book.Delete().Take(1).Exec() // deletes only 1 record

func (*StateDelete[T]) Where

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

Where adds a WHERE clause to the DELETE query It accepts a raw SQL WHERE clause with optional arguments

type StateDeleteWhere added in v0.8.4

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

StateDeleteWhere represents a query state with WHERE clause building capabilities for DELETE queries It provides methods for constructing WHERE clauses specifically for DELETE operations

func MatchDeleteWhere added in v0.8.4

func MatchDeleteWhere[T any](s *StateDeleteWhere, table *Table[T], obj T) *StateDeleteWhere

MatchDeleteWhere creates a StateDeleteWhere with conditions matching the non-zero fields of the given object It generates conditions based on the object's non-zero fields

func NewStateDeleteWhere added in v0.8.4

func NewStateDeleteWhere(ctx context.Context) *StateDeleteWhere

NewStateDeleteWhere creates a new StateDeleteWhere with the given context It initializes the delete query builder and sets up the context

func (*StateDeleteWhere) Filter added in v0.8.4

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

func (*StateDeleteWhere) OnTransaction added in v0.8.4

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

func (*StateDeleteWhere) Prepare added in v0.8.4

func (*StateDeleteWhere) Where added in v0.8.4

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

type StateInsert

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

StateInsert represents an INSERT query state for inserting new records into a table It provides methods for inserting single and multiple records

func (*StateInsert[T]) All

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

All inserts multiple records into the table It handles batch insertion and optionally returns auto-increment primary keys

func (*StateInsert[T]) OnTransaction

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

OnTransaction sets the transaction for the insert operation It ensures the insert runs within the specified transaction

func (*StateInsert[T]) One

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

One inserts a single record into the table It handles auto-increment primary keys and returning values

type StateSave

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

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 It extracts primary keys from the map to determine insert/update logic

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 It automatically generates conditions for fields with non-zero values

func (*StateSave[T]) OnTransaction

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

OnTransaction sets the transaction for the save operation It ensures the save runs within the specified transaction

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 It automatically handles insert/update logic based on primary key presence

func (*StateSave[T]) Take

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

Take limits the number of rows affected by the save operation Note: PostgreSQL does not support LIMIT in UPDATE statements

type StateSelect

type StateSelect[T, R any] struct {
	*StateWhere // Embedded StateWhere for WHERE clause construction
	// contains filtered or unexported fields
}

StateSelect represents a SELECT query state with type parameters for table and result types It provides methods for building and executing SELECT queries with various options

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 It initializes the query state with the provided context and table

func NewStateSelectFrom

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

NewStateSelectFrom creates a new StateSelect from an existing StateWhere It sets up the query state for the specified table

func (*StateSelect[T, R]) All

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

All executes the query and returns all rows as a slice It pre-allocates the slice capacity if a limit is specified

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 It copies joins, conditions, orders, groups, limits, and offset

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]) FetchRow added in v0.8.4

func (s *StateSelect[T, R]) FetchRow(to FetchFunc) (*R, error)

FetchRow executes the query and returns a single row using the provided FetchFunc It handles the query execution and row scanning

func (*StateSelect[T, R]) Filter

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

Filter adds filter conditions to the select query It appends the specified conditions to the WHERE clause

func (*StateSelect[T, R]) GetJoinForeign

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

GetJoinForeign returns the foreign key relationship for the first joined table It looks up the foreign relationship in the table's foreign key registry

func (*StateSelect[T, R]) GetJoinForeigns

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

GetJoinForeigns returns all foreign key relationships for the joined tables It looks up foreign relationships and creates them for joined tables

func (*StateSelect[T, R]) GroupBy

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

GroupBy adds GROUP BY clauses to the query It groups results by the specified fields

func (*StateSelect[T, R]) IterRows

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

IterRows returns an iterator over the query results It yields each row along with any error encountered

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 It adds a JOIN clause with the specified join type and condition

func (*StateSelect[T, R]) LeftJoin

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

LeftJoin performs a LEFT JOIN with another table It automatically adds the joined table's columns to the select list

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 The key must be an integer column that exists in the table

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 It automatically generates conditions for fields with non-zero values

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 It ensures the query runs within the specified transaction

func (*StateSelect[T, R]) One

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

One executes the query and returns the first row as a single result It automatically limits the query to one row for same-model queries

func (*StateSelect[T, R]) OrderBy

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

OrderBy adds ORDER BY clauses to the query It accepts field names with optional DESC keyword for descending order

func (*StateSelect[T, R]) Pagination

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

Pagination returns a paginated query result It calculates total values, pages, and returns the current page data Default values for page and size are 1 and 10 respectively

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 Each key maps to a slice of results with that key value

func (*StateSelect[T, R]) RollUP

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

RollUP enables rollup for aggregation queries It adds ROLL UP clause to GROUP BY operations

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 It accepts field names as strings or Field objects

func (*StateSelect[T, R]) Skip

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

Skip skips the specified number of rows in the result It sets the OFFSET clause to the specified value

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 limits the number of rows returned by the query It sets the LIMIT clause to the specified value

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 It accepts a raw SQL WHERE clause with optional arguments

type StateUpdate

type StateUpdate[T any] struct {
	*StateWhere // Embedded StateWhere for WHERE clause construction
	// contains filtered or unexported fields
}

StateUpdate represents an UPDATE query state for modifying records in a table It provides methods for building and executing UPDATE queries with various options

func (*StateUpdate[T]) Exec

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

Exec executes the UPDATE query and returns any error It builds and runs the UPDATE statement with the specified changes and conditions

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 It appends the specified conditions to the WHERE clause

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 It adds a JOIN clause to the UPDATE statement

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 It automatically creates the join condition based on the foreign key

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 It automatically generates conditions for fields with non-zero values

func (*StateUpdate[T]) OnTransaction

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

OnTransaction sets the transaction for the UPDATE operation It ensures the update runs within the specified 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 where key is the column name and value is the new value

Example:

 changes := []Pair{
		{Key:"name", Value:"John"},
		{Key:"email", Value:"[email protected]"},
	}
 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 It updates columns based on the key-value pairs in the map

Example:

changes := map[string]any{"name": "John", "email": "[email protected]"}
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 Note: PostgreSQL does not support LIMIT in UPDATE statements

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 It accepts a raw SQL WHERE clause with optional arguments

type StateWhere

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

StateWhere represents a query state with WHERE clause building capabilities It provides methods for constructing WHERE clauses for various query types

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 It generates conditions based on the object's non-zero fields

func NewStateWhere

func NewStateWhere(ctx context.Context) *StateWhere

NewStateWhere creates a new StateWhere with the given context It initializes the query builder and sets up the 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 (*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
	StateDelete *StateDeleteWhere

	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: "[email protected]"}
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.
	ColumnNames []string            // ColumnNames is a list of column names in the table.
	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 It looks up the table information from the registry

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    // Junction table name
	Left, Right string    // Left and right column names
	Where       Condition // WHERE clause for filtering
}

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 // Type of the value
	Args   []any        // Slice of values for IN conditions
	Length int          // Length of the value slice
}

Value represents a value or list of values for use in query conditions It handles both single values and slices for IN 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