Help us shape the future of Go! Take the 2026 Go Developer Survey

gdao

package module
v1.2.3 Latest Latest
Warning

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

Go to latest
Published: Jun 10, 2026 License: BSD-3-Clause Imports: 15 Imported by: 12

README

GDAO —— Go Persistence Framework [中文]

Introduction

GDAO is a comprehensive persistence layer solution. Its primary purpose is to reduce coding effort, enhance productivity, improve performance, support the integration of multiple data sources, facilitate read-write separation, and establish a standard for persistence layer programming. By leveraging GDAO effectively, it's possible to reduce the amount of coding required in the persistence layer by 30%, even up to 50%, while simultaneously establishing a unified programming standard for the persistence layer, reducing errors, and making maintenance and expansion easier. For Go, GDAO serves a similar role as Hibernate + MyBatis do for Java. The GDAO framework combines the abstraction of Hibernate with the flexibility of MyBatis, addressing long-standing pain points in ORM frameworks. For more information about the pain points of Hibernate and MyBatis, refer to the JDAO usage documentation.

GDAO fully implements the core features of MyBatis in Go, achieving the separation of SQL from the application code, and implementing powerful dynamic SQL functionality. It is currently the only ORM in Go that completely separates SQL from the application.

Usage Documentation

Example Program


Key Features

  1. Full Table Object Mapping: Supports mapping table operations to standard struct object operations.
  2. Full SQL Object Mapping: Supports complete SQL operation mapping to object operations.
  3. Separation of SQL and Code: Supports the separation of SQL from the program, akin to MyBatis.

Main Functionality

  1. Code Generation: Run the GDAO code generation tool to create standardized entity classes for database tables. Similar to thrift/protobuf.
  2. Efficient Serialization: Standardized entity classes for tables implement efficient serialization and deserialization. Higher performance, smaller data size.
  3. Read-Write Splitting: GDAO supports binding multiple slave data source connections and implementing read-write separation for bound tables or SQL queries.
  4. Data Caching: GDAO supports data caching and provides detailed control over cache validity and data eviction characteristics.
  5. Broad Compatibility: GDAO theoretically supports all databases that implement the Go database driver interface.
  6. Advanced Features: Supports transactions, stored procedures, batch processing, and other database operations.
  7. Dynamic SQL: GDAO implements rich dynamic SQL construction features. Supports dynamic SQL tag mapping construction and native SQL dynamic construction.
  8. MyBatis Characteristics: GDAO's mapping module is the implementation of MyBatis in Go. It is also the only known ORM in Go that supports the separation of SQL from the application.

GDAO Persistence Layer Solution

Note: Full table mapping and full SQL mapping can potentially lead to some issues such as over-encapsulation of objects and large numbers of repetitive, similar SQL statements. GDAO uses the abstraction of table mapping combined with the semi-automated management of SQL mapping to solve problems in the persistence layer.

  1. Full Table Object Mapping for CRUD Operations on Single Tables: Mapping all operations to table object operations is a classic approach used by Hibernate, which can lead to over-encapsulation problems. GDAO supports auto-generating mapping entity classes for tables specifically to handle CRUD operations on single tables. Its underlying dynamic SQL construction effectively addresses the issue of large numbers of similar SQL statements resulting from similar table operation behaviors.
  2. Full SQL Object Mapping for Complex SQL Operations: In practice, complex SQL, especially multi-table joins, often requires optimization, which requires understanding of the database schema, index properties, etc. Concatenating complex SQL strings using Go objects can increase the difficulty of comprehension. Eventually, developers may not know what the final executed SQL statement looks like after object concatenation, which increases risk and maintenance difficulty. GDAO implements the core feature of SQL mapping from MyBatis, allowing SQL to be configured in XML and mapped to Go objects.
  3. SqlBuilder for Native SQL Dynamic Construction: GDAO implements dynamic construction of native SQL. For extremely complex SQL, including functions or stored procedures, GDAO supports dynamic construction using SqlBuilder. It is the procedural implementation of dynamic tags, based on Go programs to construct any form of SQL.

Quick Start

1. Installation

go get github.com/donnie4w/gdao

2. Configuring Data Source

gdao.Init(mysqldb, gdao.MYSQL) // Initialize gdao data source; mysqldb is an sql.DB object, gdao.MYSQL is the database type

3. Standard Entity Class Operations

// Read
hs := dao.NewHstest()
hs.Where(hs.Id.EQ(10))
h, err := hs.Select(hs.Id, hs.Value, hs.Rowname)
//[DEBUG][SELETE ONE][ select id,value,rowname from hstest where id=?][10] 
// Update
hs := dao.NewHstest()
hs.SetRowname("hello10")
hs.Where(hs.Id.EQ(10))
hs.Update()
//[DEBUG][UPDATE][update hstest set rowname=? where id=?][hello10 10]
// Delete
hs := dao.NewHstest()
hs.Where(hs.Id.EQ(10))
hs.Delete()
//[DEBUG][UPDATE][delete from hstest where id=?][10]
// Insert
hs := dao.NewHstest()
hs.SetValue("hello123")
hs.SetLevel(12345)
hs.SetBody([]byte("hello"))
hs.SetRowname("hello1234")
hs.SetUpdatetime(time.Now())
hs.Insert()
//[DEBUG][INSERT][insert  into hstest(floa,age,value,level,body,rowname,updatetime )values(?,?,?,?,?)][hello123 12345 hello hello1234 2024-07-17 19:36:44]

4. Native SQL Operations

// Query, return a single row; gdao is the entry point for native SQL operations
gdao.ExecuteQueryBean("select id,value,rowname from hstest where id=?", 10)

// Insert
gdao.ExecuteUpdate("insert into hstest2(rowname,value) values(?,?)", "helloWorld", "123456789");

// Update
gdao.ExecuteUpdate("update hstest set value=? where id=1", "hello");

// Delete
gdao.ExecuteUpdate("delete from hstest where id = ?", 1);

5. Configuring Cache

// Bind Hstest and enable caching; default cache expiration is 300 seconds; gdaoCache is the entry point for cache operations
gdaoCache.BindClass[dao.Hstest]()

6. Read-Write Splitting

mysqldb := getDataSource("mysql.json") // Get slave data source: mysqldb
gdaoSlave.BindClass[dao.Hstest](mysqldb, gdao.MYSQL) // Here the master database is sqlite, the slave database is mysql; Hstest reads from the mysql data source; gdaoSlave is the entry point for read-write splitting operations

7. SQL Mapping

<!-- MyBatis style XML configuration file -->
<mapper namespace="user">
   <select id="selectHstest1" parameterType="int64" resultType="hstest1">
      SELECT * FROM hstest1  order by id desc limit #{limit}
   </select>
</mapper>
// Read and parse XML configuration
hs1, _ := gdaoMapper.Select[dao.Hstest1]("user.selectHstest1", 1)
fmt.Println(hs1)

8. dynamic SQL Mapping

<!-- where if -->
 <select id="demo1" resultType="Hstest">
     SELECT * FROM hstest
     <where>
         <if test="rowname== 'hello'">
             and rowname = #{rowname}
         </if>
         <if test="id >0">
             AND id = #{id}
         </if>
     </where>
 </select>
hs := dao.NewHstest()
hs.SetId(12)
gdaoMapper.SelectBean("dynamic.demo1", hs)  //exec mapper id  [SELECT * FROM hstest WHERE id = ?]ARGS[12]

9. SqlBuilder Dynamic SQL

func Test_sqlBuilder_if(t *testing.T) {
   context := map[string]any{"id": 12}
   
   builder := &SqlBuilder{}
   builder.Append("SELECT * FROM hstest where 1=1").
           AppendIf("id>0", context, "and id=?", context["id"])  // Dynamic SQL, when id>0, dynamically add and id=?
   
   bean := builder.SelectOne()  // Query SQL: SELECT * FROM hstest where 1=1 and id=?  [ARGS][12]
   logger.Debug(bean)
}

Documentation

Index

Constants

View Source
const (
	MYSQL base.DBType
	POSTGRESQL
	MARIADB
	SQLITE
	ORACLE
	SQLSERVER
	DB2
	SYBASE
	DERBY
	FIREBIRD
	INGRES
	GREENPLUM
	TERADATA
	NETEZZA
	VERTICA
	TIDB
	OCEANBASE
	OPENGAUSS
	HSQLDB
	ENTERPRISEDB
	SAPHANA
	COCKROACHDB
	INFORMIX
)

Variables

This section is empty.

Functions

func BindDataSource

func BindDataSource(db *sql.DB, dbtype DBType, tableNames ...string)

BindDataSource binds an open database connection to a specified data source type and list of table names.

Parameters:

db (*sql.DB): An open database connection.
dbtype (DBType): The data source type, such as gdao.MYSQL, gdao.POSTGRESQL, etc.
tableNames (...string): A list of table names to be bound to the data source.

Description:

This method initializes and configures a data source to be used for subsequent data operations. It takes an open database connection,
a data source type, and one or more table names that need to be bound. This allows the data source to be used for CRUD operations within the application.

Example:

db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
    log.Fatal(err)
}
defer db.Close()

BindDataSource(db, gdao.MYSQL, "users", "orders")

func BindDataSourceWithClass

func BindDataSourceWithClass[T gdaoStruct.TableClass](db *sql.DB, dbtype DBType)

BindDataSourceWithClass binds the provided database connection and data source type to a generic table base class.

Parameters:

db (*sql.DB): An open database connection.
dbtype (DBType): The data source type, such as gdao.MYSQL, gdao.POSTGRESQL, etc.

Description:

This function initializes the generic table base class to work with the specified database connection and data source type.

Type Parameters:

T: The type of the table base class that is the standardized entity class generated by gdao

Example:

db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
    log.Fatal(err)
}
defer db.Close()

// assuming dao.Hstest is the standardized entity class generated by gdao
BindDataSourceWithClass[dao.Hstest](db, gdao.MYSQL)

func BindMapperDataSource

func BindMapperDataSource(namespace string, db *sql.DB, dbtype DBType)

BindMapperDataSource binds the provided database connection and data source type to a specific namespace in the XML mapping files.

Parameters:

namespace (string): The namespace in the XML mapping files that corresponds to the CRUD to bind.
db (*sql.DB): An open database connection.
dbtype (DBType): The data source type, such as gdao.MYSQL, gdao.POSTGRESQL, etc.

Description:

If there is only one data source, the call to the gdao.Init function has already set the data source for all operations.
If there are multiple data sources and the xml needs to be set to specify the data source, you can call this function for binding

Example:

db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
    log.Fatal(err)
}
defer db.Close()

//  assuming users is the namespace of XML mapping
BindMapperDataSource("users", db, gdao.MYSQL)

func BindMapperIdDataSource

func BindMapperIdDataSource(namespace, id string, db *sql.DB, dbtype DBType)

BindMapperIdDataSource is similar to the BindMapperDataSource function, but it needs to specify the id of a CURD property

// assuming users is the namespace of XML mapping and selectHstest is the id of select tag BindMapperIdDataSource("users","selectHstest", db, gdao.MYSQL)

func ExecuteBatch

func ExecuteBatch(sql string, args [][]any) ([]sql.Result, error)

ExecuteBatch executes a batch of SQL statements. sql is the SQL statement to execute for each batch item. args is a slice of slices, where each inner slice contains the arguments for a single SQL statement. The function returns a slice of int64 values representing the number of rows affected by each SQL statement and any error encountered. If there's an error, it returns nil and the specific error information; otherwise, it returns the slice of affected rows and nil.

func ExecuteQuery

func ExecuteQuery[T any](sql string, args ...any) (r *T, err error)

ExecuteQuery executes an SQL query and returns the parsed results. T is a generic type that represents the specific struct or type the query result should be converted to. sql is the SQL query statement to execute. args is an optional list of parameters to substitute placeholders in the SQL query. The function returns a pointer to a value of type *T, which is typically a pointer to a struct that holds the query results. If there's an error, it returns nil and the specific error information; otherwise, it returns a filled result object and nil.

func ExecuteQueryBean

func ExecuteQueryBean(sql string, args ...any) *base.DataBean

ExecuteQueryBean executes an SQL query and returns a single DataBean object. sql is the SQL query statement to execute. args is an optional list of parameters to substitute placeholders in the SQL query. The function returns a pointer to a DataBean object, which typically holds the data retrieved from a single row in the query results. If there's an error, it returns nil and the specific error information; otherwise, it returns a filled DataBean object and nil.

func ExecuteQueryBeans

func ExecuteQueryBeans(sql string, args ...any) *base.DataBeans

ExecuteQueryBeans executes an SQL query and returns a list of DataBean objects. sql is the SQL query statement to execute. args is an optional list of parameters to substitute placeholders in the SQL query. The function returns a slice of pointers to DataBean objects, where each element represents one row of the query results. If there's an error, it returns nil and the specific error information; otherwise, it returns a slice of filled DataBean objects and nil.

func ExecuteQueryList

func ExecuteQueryList[T any](sql string, args ...any) (r []*T, err error)

ExecuteQueryList executes an SQL query and returns a list of parsed results. T is a generic type that represents the specific struct or type the query results should be converted to. sql is the SQL query statement to execute. args is an optional list of parameters to substitute placeholders in the SQL query. The function returns a slice of pointers to values of type T, where each element represents one row of the query results. If there's an error, it returns nil and the specific error information; otherwise, it returns a slice of filled result objects and nil.

func ExecuteUpdate

func ExecuteUpdate(sql string, args ...any) (sql.Result, error)

ExecuteUpdate executes an SQL update, insert, or delete statement. sql is the SQL statement to execute. args is an optional list of parameters to substitute placeholders in the SQL statement. The function returns the number of rows affected by the SQL statement and any error encountered. If there's an error, it returns -1 and the specific error information; otherwise, it returns the number of affected rows and nil.

func GetDefaultDBHandle

func GetDefaultDBHandle() DBhandle

func Init

func Init(db *sql.DB, dbtype DBType)

Init initializes the gdao package by binding the provided database connection and data source type.

Parameters:

db (*sql.DB): An open database connection.
dbtype (DBType): The data source type, such as gdao.MYSQL, gdao.POSTGRESQL, etc.

Description:

This function sets up gdao to work with the specified database connection and data source type.
It is typically called at the beginning of the application to configure the gdao package for use with a specific database.

Example:

db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
    log.Fatal(err)
}
defer db.Close()

gdao.Init(db, gdao.MYSQL)

func NewDBHandle

func NewDBHandle(db *sql.DB, dbtype DBType) DBhandle

func NewTransaction

func NewTransaction() (r Transaction, err error)

func NewTransactionWithDBhandle

func NewTransactionWithDBhandle(db DBhandle) (r Transaction, err error)

func PreCompile added in v1.1.2

func PreCompile(limit uint32)

func SetLogger

func SetLogger(on bool)

func UnbindDataSource

func UnbindDataSource(tableNames ...string)

func UnbindDataSourceWithClass

func UnbindDataSourceWithClass[T gdaoStruct.TableClass]()

func UnbindMapperDataSource

func UnbindMapperDataSource(namespace string)

func UnbindMapperIdDataSource

func UnbindMapperIdDataSource(namespace, id string)

Types

type GStruct

type GStruct[P any, T any] interface {
	Scanner
	// UseCache use default gdaoCache or not use cache
	UseCache(use bool)

	// UseTransaction use specified transaction
	UseTransaction(transaction Transaction)

	// UseDBHandle use specified DBhandle
	UseDBHandle(db DBhandle) *Table[T]

	// UseCommentLine set annotations for sql
	UseCommentLine(commentline string)

	MustMaster(must bool)

	// Where adds a WHERE clause to the query with one or more conditions.
	//
	// Parameters:
	//
	//	wheres: Variable length argument list of *Where[T] objects representing the conditions to add to the WHERE clause.
	//
	// Returns:
	//
	//	A pointer to the Table[T] instance to allow method chaining.
	//
	// Description:
	//
	//	This function allows you to specify one or more conditions that will be added to the WHERE clause of the SQL query.
	//	Each *Where[T] object represents a condition that must be satisfied by the rows returned by the query.
	//	Multiple conditions can be combined to form complex queries.
	//
	// Example:
	//
	//	// Assuming "hs" is an instance of a Table struct that represents a table named "hstest"
	//	// And "Rowname" and "Id" are columns in the "hstest" table
	//	hs := dao.NewHstest()
	//	hs = hs.Where(hs.Rowname.RLIKE(1)).GroupBy(hs.Id).Having(hs.Id.Count().LT(2)).Limit(2)
	//	hslist, _ := hs.Selects()
	Where(wheres ...*Where[T]) *Table[T]
	// OrderBy sql: order by
	OrderBy(sorts ...*Sort[T]) *Table[T]
	// GroupBy sql: group by
	GroupBy(columns ...Column[T]) *Table[T]
	// Having sql: having
	Having(havings ...*Having[T]) *Table[T]
	Limit2(offset, limit int64)
	Limit(limit int64)
	// Selects sql:select from table and Return data slice
	Selects(columns ...Column[T]) (_r []P, err error)
	// Select sql:select from table and Return first data
	Select(columns ...Column[T]) (_r P, err error)
	// Update sql: update
	Update() (sql.Result, error)
	// Insert sql: insert
	Insert() (sql.Result, error)
	// Delete sql: delete
	Delete() (sql.Result, error)
	// AddBatch sql: add data to batch sql
	AddBatch()
	// ExecBatch sql:database batch operation
	ExecBatch() ([]sql.Result, error)
	//Copy object data
	Copy(h P) P
	// Encode Serialized object
	Encode() ([]byte, error)
	// Decode deserialization
	Decode(bs []byte) (err error)
	String() string
	// TableName return table name
	TableName() string
}

type Table

type Table[T any] struct {
	//GStruct[*T, T]
	gdaoStruct.TableClass
	// contains filtered or unexported fields
}

func (*Table[T]) AddBatch

func (t *Table[T]) AddBatch()

func (*Table[T]) Decode

func (*Table[T]) Decode(data []byte) (map[string]any, error)

func (*Table[T]) Delete

func (t *Table[T]) Delete() (sql.Result, error)

func (*Table[T]) Encode

func (*Table[T]) Encode(m map[string]any) ([]byte, error)

func (*Table[T]) ExecBatch

func (t *Table[T]) ExecBatch() ([]sql.Result, error)

func (*Table[T]) GroupBy

func (t *Table[T]) GroupBy(columns ...Column[T]) *Table[T]

func (*Table[T]) Having

func (t *Table[T]) Having(havings ...*Having[T]) *Table[T]

func (*Table[T]) Init

func (t *Table[T]) Init(s string, columns []Column[T])

func (*Table[T]) Insert

func (t *Table[T]) Insert() (sql.Result, error)

func (*Table[T]) IsInit

func (t *Table[T]) IsInit() bool

func (*Table[T]) Limit

func (t *Table[T]) Limit(limit int64)

func (*Table[T]) Limit2

func (t *Table[T]) Limit2(offset, limit int64)

func (*Table[T]) MustMaster

func (t *Table[T]) MustMaster(must bool)

func (*Table[T]) OrderBy

func (t *Table[T]) OrderBy(sorts ...*Sort[T]) *Table[T]

func (*Table[T]) Put0

func (t *Table[T]) Put0(k string, v any)

func (*Table[T]) Select

func (t *Table[T]) Select(columns ...Column[T]) (_r *T, err error)

func (*Table[T]) Selects

func (t *Table[T]) Selects(columns ...Column[T]) (_r []*T, err error)

func (*Table[T]) TableName added in v1.1.1

func (t *Table[T]) TableName() string

func (*Table[T]) Update

func (t *Table[T]) Update() (sql.Result, error)

func (*Table[T]) UseCache

func (t *Table[T]) UseCache(use bool)

func (*Table[T]) UseCommentLine

func (t *Table[T]) UseCommentLine(commentline string)

func (*Table[T]) UseDBHandle

func (t *Table[T]) UseDBHandle(db DBhandle) *Table[T]

func (*Table[T]) UseTransaction

func (t *Table[T]) UseTransaction(transaction Transaction)

func (*Table[T]) Where

func (t *Table[T]) Where(wheres ...*Where[T]) *Table[T]

Where adds a WHERE clause to the query with one or more conditions.

Parameters:

wheres: Variable length argument list of *Where[T] objects representing the conditions to add to the WHERE clause.

Returns:

A pointer to the Table[T] instance to allow method chaining.

Description:

This function allows you to specify one or more conditions that will be added to the WHERE clause of the SQL query.
Each *Where[T] object represents a condition that must be satisfied by the rows returned by the query.
Multiple conditions can be combined to form complex queries.

Example:

// Assuming "hs" is an instance of a Table struct that represents a table named "hstest"
// And "Rowname" and "Id" are columns in the "hstest" table
hs := dao.NewHstest()
hs = hs.Where(hs.Rowname.RLIKE(1)).GroupBy(hs.Id).Having(hs.Id.Count().LT(2)).Limit(2)
hslist, _ := hs.Selects()

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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