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

gdao

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2024 License: BSD-3-Clause Imports: 10 Imported by: 12

README

GDAO —— Go Persistence Framework [中文]

Introduction

Gdao is an innovative persistence layer solution aimed at reducing coding workload, improving productivity, enhancing performance, supporting multi-data source integration, and facilitating data read-write separation. By leveraging Gdao, developers can decrease the amount of code required for the persistence layer by 30% to 50%, establish unified coding standards, minimize errors, and ensure easier maintenance and expansion.

gdao for go is equivalent to hibernate+mybatis for java, the gdao framework combines the abstraction of Hibernate and the flexibility of MyBatis, and solves the pain points of their respective long-standing use on ORM frameworks. Refer to the jdao usage documentation for pain points between hibernate and mybatis

  • The GDAO design structure is both concise and rigorous, with all interfaces and functions named descriptively so their purpose is immediately clear.
  • Even if you are new to GDAO, you can quickly understand its code and the associated data behaviors.
  • The simplicity of GDAO ensures that you can master its usage within minutes.

Official Website

Documentation

Demo

Key Features

  1. Code Generation: Use the Gdao code generation tool to create standardized entity classes for database tables, similar to Thrift/Protobuf.
  2. Efficient Serialization: The standardized entity classes for tables implement efficient serialization and deserialization, higher performance and smaller data volume.
  3. Support for Data Read-Write Separation: Gdao supports binding multiple data sources and data read-write separation, allowing data sources to be bound to tables, classes, mapping interfaces, and other properties.
  4. Support for Data Caching: Gdao supports data caching with detailed control over cache data lifecycle and recycling features.
  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. Support SQL and program separation: Similar to mybatis, gdao supports xml file write sql mapping calls. This is one of the few orm features that supports the separation of SQL and programs, but it is very powerful.
GDAO's Innovative ORM Solution

Gdao is a sibling framework to Jdao, sharing its design patterns.

  1. Standardized Mapped Entity Classes for Single Table CRUD Operations: Over 90% of single-table operations can be performed through entity classes. These CRUD operations are generally not involved in complex SQL optimization and can be generated by entity classes to reduce error rates and simplify maintenance. By utilizing mechanisms such as caching and read-write separation, the persistence layer becomes more efficient and convenient. The data operation format of standardized entity classes is not merely a concatenation of object functions but is more akin to SQL operations, making it easier to understand.
  2. Execution of Complex SQL: Complex SQL, especially multi-table joins, often require optimization based on the table structure and index properties. Using objects to concatenate complex SQL can increase the difficulty of understanding and may lead to developers being unaware of the final executed SQL, thereby increasing risk and maintenance difficulty. Therefore, Gdao recommends using Gdao's CRUD interfaces for complex SQL problems. Gdao provides flexible data conversion and efficient object mapping implementations, avoiding excessive use of time-consuming operations such as reflection.
  3. SQL Mapping Files: For complex SQL operations, Gdao provides corresponding CRUD interfaces. It also supports mapping SQL through XML configuration for interface invocation, similar to the Java MyBatis ORM framework. However, unlike MyBatis which requires mapping all SQL operations, Gdao provides complete SQL mapping interfaces but recommends only mapping complex SQL or operations that standardized entity classes cannot complete. Gdao's SQL configuration files reference the MyBatis configuration file format, implementing a new parser that allows for higher flexibility and tolerance of configuration parameter types (refer to the documentation).


Core Components

1. gdao

Main core entry point providing the following functionalities:

  • Setting data sources
  • SQL CRUD functions
2. gdaoCache

Cache entry point supporting the following functionalities:

  • Binding or unbinding packages, classes, and other properties to enable or disable query caching
3. gdaoSlave

Read-write separation operation entry point supporting the following functionalities:

  • Binding or unbinding packages, classes, and other properties to enable or disable read-write separation
4. gdaoMapper

Execute SQL directly by calling Gdao's CRUD interfaces or use XML file mappings and call through gdaoMapper by Mapper Id


Quick Start

1. Installation

# import gdao
go get github.com/donnie4w/gdao

2. Configure Data Source

gdao.Init(mysqlDB, gdao.MYSQL)
// dataSource is the data source
// gdao.MYSQL is the database type

3. Generate Table Entity Classes

Use the Gdao code generation tool to generate standardized entity classes for database tables.

4. Entity Class Operations

// Set data source
gdao.Init(mysqlDB, gdao.MYSQL)

// Read
hs := dao.NewHstest()
hs.Where(hs.Id.EQ(10))
h, _ := hs.Select(hs.Id, hs.Value, hs.Rowname)
logger.Debug(h)
//[DEBUG][SELECT 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][DELETE][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.SetFloa(123456)
hs.SetAge(123)
hs.Insert()
//[DEBUG][INSERT][insert into hstest(floa, age, value, level, body, rowname, updatetime) values(?,?,?,?,?,?,?)][123456 123 hello123 12345 [104 101 108 108 111] hello1234 2024-07-17 19:36:44]

5. gdao api

CRUD Operations
// Query, return single record
bean, _ := gdao.ExecuteQueryBean("select id, value, rowname from hstest where id=?", 10)
logger.Debug(bean)

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

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

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

6. gdaoCache

Configure Caching
// Bind Hstest to enable caching, cache expiration set to 300 seconds
gdaoCache.BindClass[dao.Hstest]()

// First query Hstest and set data cache based on conditions
hs := dao.NewHstest()
hs.Where((hs.Id.Between(0, 2)).Or(hs.Id.Between(10, 15)))
hs.Limit(3)
hs.Selects()

// For the same conditions, data is directly retrieved from cache
hs = dao.NewHstest()
hs.Where((hs.Id.Between(0, 2)).Or(hs.Id.Between(10, 15)))
hs.Limit(3)
hs.Selects()
Execution Result
[DEBUG][SELECT LIST][ select id, age, rowname, value, updatetime, body, floa, level from hstest where id between ? and ? or (id between ? and ?) LIMIT ? ][0 2 10 15 3]
[DEBUG][SET CACHE][ select id, age, rowname, value, updatetime, body, floa, level from hstest where id between ? and ? or (id between ? and ?) LIMIT ? ][0 2 10 15 3]
[DEBUG][SELECT LIST][ select id, age, rowname, value, updatetime, body, floa, level from hstest where id between ? and ? or (id between ? and ?) LIMIT ? ][0 2 10 15 3]
[DEBUG][GET CACHE][ select id, age, rowname, value, updatetime, body, floa, level from hstest where id between ? and ? or (id between ? and ?) LIMIT ? ][0 2 10 15 3]

7. gdaoSlave

Read-Write Separation
// Set slave data source: mysql
mysqlDB, _ := getDataSource("mysql.json")
gdaoSlave.BindClass[dao.Hstest](mysqlDB, gdao.MYSQL)
// Here the main database is sqlite and the slave database is mysql. Hstest reads data from mysql
hs := dao.NewHstest()
hs.Where(hs.Id.Between(0, 5))
hs.OrderBy(hs.Id.Desc())
hs.Limit(3)
hs.Selects()

8. gdaoMapper

Use XML to Map SQL
<!-- 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>
// Set data source
if db, err := getDataSource("sqlite.json"); err == nil {
   gdao.Init(db, gdao.SQLITE)  
   gdao.SetLogger(true)
}

// Read and parse XML configuration
hs1, _ := gdaoMapper.Select[dao.Hstest1]("user.selectHstest1", 1)
fmt.Println(hs1)

id, _ := gdaoMapper.Select[int64]("user.selectHstest1", 1)
fmt.Println(*id)
Execution Result
[DEBUG][Mapper Id] user.selectHstest1 
SELECTONE SQL[SELECT * FROM hstest1 ORDER BY id DESC LIMIT ?]ARGS[1]
Id:52, Rowname:rowname>>>123456789, Value:[104 101 108 108 111 32 103 100 97 111], Goto:[49 50 51 52 53]
[DEBUG][Mapper Id] user.selectHstest1 
SELECTONE SQL[SELECT * FROM hstest1 ORDER BY id DESC LIMIT ?]ARGS[1]
52

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 TableBase[T]](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) ([]int64, 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, error)

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.DataBean, error)

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) (int64, 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 Scan

func Scan[T any](dataBean *DataBean) (t *T, err error)

func SetLogger

func SetLogger(on bool)

func UnbindDataSource

func UnbindDataSource(tableNames ...string)

func UnbindDataSourceWithClass

func UnbindDataSourceWithClass[T TableBase[T]]()

func UnbindMapperDataSource

func UnbindMapperDataSource(namespace string)

func UnbindMapperIdDataSource

func UnbindMapperIdDataSource(namespace, id string)

Types

type GStruct

type GStruct[P any, T any] interface {
	Scanner
	TableBase[T]

	// 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() (int64, error)
	// Insert sql: insert
	Insert() (int64, error)
	// Delete sql: delete
	Delete() (int64, error)
	// AddBatch sql: add data to batch sql
	AddBatch()
	// ExecBatch sql:database batch operation
	ExecBatch() ([]int64, 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 Scanner

type Scanner interface {
	Scan(fieldname string, value any)

	// ToGdao
	// : when don't create an object by calling a New method of the standardized entity class,
	// but by using some other method such as the new keyword, then should call the ToGdao function,
	// which initializes the relevant data for database operations
	ToGdao()
}

type Table

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

func (*Table[T]) AddBatch

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

func (Table[T]) ClassName

func (t Table[T]) ClassName()

func (*Table[T]) Decode

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

func (*Table[T]) Delete

func (t *Table[T]) Delete() (int64, error)

func (*Table[T]) Encode

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

func (*Table[T]) ExecBatch

func (t *Table[T]) ExecBatch() ([]int64, 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() (int64, 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

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

func (*Table[T]) Update

func (t *Table[T]) Update() (int64, 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