genmai

package module
v0.0.0-...-7858383 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2017 License: MIT Imports: 17 Imported by: 14

README

Genmai Build Status

Simple, better and easy-to-use ORM library for Golang.

Overview

  • flexibility with SQL-like API
  • Transaction support
  • Database dialect interface
  • Query logging
  • Update/Insert/Delete hooks
  • Embedded struct

Database dialect currently supported are:

  • MySQL
  • PostgreSQL
  • SQLite3

Installation

go get -u github.com/naoina/genmai

Schema

Schema of the table will be defined as a struct.

// The struct "User" is the table name "user".
// The field name will be converted to lowercase/snakecase, and used as a column name in table.
// e.g. If field name is "CreatedAt", column name is "created_at".
type User struct {
    // PRIMARY KEY. and column name will use "tbl_id" instead of "id".
    Id int64 `db:"pk" column:"tbl_id"`

    // NOT NULL and Default is "me".
    Name string `default:"me"`

    // Nullable column must use a pointer type, or sql.Null* types.
    CreatedAt *time.Time

    // UNIQUE column if specify the db:"unique" tag.
    ScreenName string `db:"unique"`

    // Ignore column if specify the db:"-" tag.
    Active bool `db:"-"`
}

Query API

Create table
package main

import (
    "time"

    _ "github.com/mattn/go-sqlite3"
    // _ "github.com/go-sql-driver/mysql"
    // _ "github.com/lib/pq"
    "github.com/naoina/genmai"
)

// define a table schema.
type TestTable struct {
    Id        int64      `db:"pk" column:"tbl_id"`
    Name      string     `default:"me"`
    CreatedAt *time.Time
    UserName  string     `db:"unique" size:"255"`
    Active    bool       `db:"-"`
}

func main() {
    db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
    // db, err := genmai.New(&genmai.MySQLDialect{}, "dsn")
    // db, err := genmai.New(&genmai.PostgresDialect{}, "dsn")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    if err := db.CreateTable(&TestTable{}); err != nil {
        panic(err)
    }
}
Insert

A single insert:

obj := &TestTable{
    Name: "alice",
    Active: true,
}
n, err := db.Insert(obj)
if err != nil {
    panic(err)
}
fmt.Printf("inserted rows: %d\n", n)

Or bulk-insert:

objs := []TestTable{
    {Name: "alice", Active: true},
    {Name: "bob", Active: true},
}
n, err := db.Insert(objs)
if err != nil {
    panic(err)
}
fmt.Printf("inserted rows: %d\n", n)
Select
var results []TestTable
if err := db.Select(&results); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
Where
var results []TestTable
if err := db.Select(&results, db.Where("tbl_id", "=", 1)); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
And/Or
var results []TestTable
if err := db.Select(&results, db.Where("tbl_id", "=", 1).And(db.Where("name", "=", "alice").Or("name", "=", "bob"))); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
In
var results []TestTable
if err := db.Select(&results, db.Where("tbl_id").In(1, 2, 4)); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
Like
var results []TestTable
if err := db.Select(&results, db.Where("name").Like("%li%")); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
Between
var results []TestTable
if err := db.Select(&results, db.Where("name").Between(1, 3)); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
Is Null/Is Not Null
var results []TestTable
if err := db.Select(&results, db.Where("created_at").IsNull()); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
results = []TestTable{}
if err := db.Select(&results, db.Where("created_at").IsNotNull()); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
Order by/Offset/Limit
var results []TestTable
if err := db.Select(&results, db.OrderBy("id", genmai.ASC).Offset(2).Limit(10)); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
Distinct
var results []TestTable
if err := db.Select(&results, db.Distinct("name"), db.Where("name").Like("%")); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)
Count
var n int64
if err := db.Select(&n, db.Count(), db.From(&TestTable{})); err != nil {
    panic(err)
}
fmt.Printf("%v\n", n)

With condition:

var n int64
if err := db.Select(&n, db.Count(), db.From(&TestTable{}), db.Where("id", ">", 100)); err != nil {
    panic(err)
}
fmt.Printf("%v\n", n)
Join

Inner Join:

package main

import (
    "database/sql"
    "fmt"
    "time"

    _ "github.com/mattn/go-sqlite3"
    // _ "github.com/go-sql-driver/mysql"
    // _ "github.com/lib/pq"
    "github.com/naoina/genmai"
)

type TestTable struct {
    Id        int64  `db:"pk" column:"tbl_id"`
    Name      string `default:"me"`
    CreatedAt *time.Time
    Active    bool `db:"-"` // column to ignore.
}

type Table2 struct {
    Id   int64 `db:"pk" column:"tbl_id"`
    Body sql.NullString
}

func main() {
    db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
    // db, err := genmai.New(&genmai.MySQLDialect{}, "dsn")
    // db, err := genmai.New(&genmai.PostgresDialect{}, "dsn")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    if err := db.CreateTable(&TestTable{}); err != nil {
        panic(err)
    }
    if err := db.CreateTable(&Table2{}); err != nil {
        panic(err)
    }
    objs1 := []TestTable{
        {Name: "alice", Active: true},
        {Name: "bob", Active: true},
    }
    objs2 := []Table2{
        {Body: sql.NullString{String: "something"}},
    }
    if _, err = db.Insert(objs1); err != nil {
        panic(err)
    }
    if _, err := db.Insert(objs2); err != nil {
        panic(err)
    }
    // fmt.Printf("inserted rows: %d\n", n)
    var results []TestTable
    if err := db.Select(&results, db.Join(&Table2{}).On("tbl_id")); err != nil {
        panic(err)
    }
    fmt.Printf("%v\n", results)
}

Left Join:

var results []TestTable
if err := db.Select(&results, db.LeftJoin(&Table2{}).On("name", "=", "body")); err != nil {
    panic(err)
}
fmt.Printf("%v\n", results)

RIGHT OUTER JOIN and FULL OUTER JOIN are still unsupported.

Update
var results []TestTable
if err := db.Select(&results); err != nil {
    panic(err)
}
obj := results[0]
obj.Name = "nico"
if _, err := db.Update(&obj); err != nil {
    panic(err)
}
Delete

A single delete:

obj := TestTable{Id: 1}
if _, err := db.Delete(&obj); err != nil {
    panic(err)
}

Or bulk-delete:

objs := []TestTable{
    {Id: 1}, {Id: 3},
}
if _, err := db.Delete(objs); err != nil {
    panic(err)
}
Transaction
defer func() {
    if err := recover(); err != nil {
        db.Rollback()
    } else {
        db.Commit()
    }
}()
if err := db.Begin(); err != nil {
    panic(err)
}
// do something.
Using any table name

You can implement TableNamer interface to use any table name.

type UserTable struct {
    Id int64 `db:"pk"`
}

func (u *UserTable) TableName() string {
    return "user"
}

In the above example, the table name user is used instead of user_table.

Using raw database/sql interface
rawDB := db.DB()
// do something with using raw database/sql interface...

Query logging

By default, query logging is disabled. You can enable Query logging as follows.

db.SetLogOutput(os.Stdout) // Or any io.Writer can be passed.

Also you can change the format of output as follows.

db.SetLogFormat("format string")

Format syntax uses Go's template. And you can use the following data object in that template.

- .time        time.Time object in current time.
- .duration    Processing time of SQL. It will format to "%.2fms".
- .query       string of SQL query. If it using placeholder,
               placeholder parameters will append to the end of query.

The default format is:

[{{.time.Format "2006-01-02 15:04:05"}}] [{{.duration}}] {{.query}}

In production, it is recommended to disable this feature in order to somewhat affect performance.

db.SetLogOutput(nil) // To disable logging by nil.

Update/Insert/Delete hooks

Genmai calls Before/After hook method if defined in model struct.

func (t *TestTable) BeforeInsert() error {
    t.CreatedAt = time.Now()
    return nil
}

If Before prefixed hook returns an error, it query won't run.

All hooks are:

  • BeforeInsert/AfterInsert
  • BeforeUpdate/AfterUpdate
  • BeforeDelete/AfterDelete

If use bulk-insert or bulk-delete, hooks method run for each object.

Embedded struct

Common fields can be defined on struct and embed that.

package main

import "time"

type TimeStamp struct {
    CreatedAt time.Time
    UpdatedAt time.Time
}

type User struct {
    Id   int64
    Name string

    TimeStamp
}

Also Genmai has defined TimeStamp struct for commonly used fields.

type User struct {
    Id int64

    genmai.TimeStamp
}

See the Godoc of TimeStamp for more information.

If you'll override hook method defined in embedded struct, you'll should call the that hook in overridden method. For example in above struct case:

func (u *User) BeforeInsert() error {
	if err := u.TimeStamp.BeforeInsert(); err != nil {
		return err
	}
	// do something.
	return nil
}

Documentation

API document and more examples are available here:

http://godoc.org/github.com/naoina/genmai

TODO

  • Benchmark
  • More SQL support
  • Migration

License

Genmai is licensed under the MIT

Documentation

Overview

Package genmai provides simple, better and easy-to-use Object-Relational Mapper.

Example
package main

import (
	"fmt"
	"log"

	_ "github.com/mattn/go-sqlite3"
	"github.com/naoina/genmai"
)

type TestModel struct {
	Id   int64
	Name string
	Addr string
}

func main() {
	db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	for _, query := range []string{
		`CREATE TABLE test_model (
			id INTEGER NOT NULL PRIMARY KEY,
			name TEXT NOT NULL,
			addr TEXT NOT NULL
		)`,
		`INSERT INTO test_model VALUES (1, 'test1', 'addr1')`,
		`INSERT INTO test_model VALUES (2, 'test2', 'addr2')`,
		`INSERT INTO test_model VALUES (3, 'test3', 'addr3')`,
	} {
		if _, err := db.DB().Exec(query); err != nil {
			log.Fatal(err)
		}
	}
	var results []TestModel
	// SELECT * FROM "test_model";
	if err := db.Select(&results); err != nil {
		log.Fatal(err)
	}
	fmt.Println(results)
}
Output:

[{1 test1 addr1} {2 test2 addr2} {3 test3 addr3}]

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrTxDone = errors.New("genmai: transaction hasn't been started or already committed or rolled back")
View Source
var (
	ErrUsingFloatType = errors.New("float types have a rounding error problem.\n" +
		"Please use `genmai.Rat` if you want an exact value.\n" +
		"However, if you still want a float types, please use `genmai.Float32` and `Float64`.")
)

Functions

func ColumnName

func ColumnName(d Dialect, tname, cname string) string

columnName returns the column name that added the table name with quoted if needed.

func IsUnexportedField

func IsUnexportedField(field reflect.StructField) bool

IsUnexportedField returns whether the field is unexported. This function is to avoid the bug in versions older than Go1.3. See following links:

https://code.google.com/p/go/issues/detail?id=7247
http://golang.org/ref/spec#Exported_identifiers

func ToInterfaceSlice

func ToInterfaceSlice(slice []string) []interface{}

ToInterfaceSlice convert to []interface{} from []string.

Types

type AfterDeleter

type AfterDeleter interface {
	// AfterDelete called after a delete by DB.Delete.
	AfterDelete() error
}

AfterDeleter is an interface that hook for after Delete.

type AfterInserter

type AfterInserter interface {
	// AfterInsert called after an insert by DB.Insert.
	AfterInsert() error
}

AfterInserter is an interface that hook for after Insert.

type AfterUpdater

type AfterUpdater interface {
	// AfterUpdate called after an update by DB.Update.
	AfterUpdate() error
}

AfterUpdater is an interface that hook for after Update.

type BeforeDeleter

type BeforeDeleter interface {
	// BeforeDelete called before a delete by DB.Delete.
	// If it returns error, the delete will be cancelled.
	BeforeDelete() error
}

BeforeDeleter is an interface that hook for before Delete.

type BeforeInserter

type BeforeInserter interface {
	// BeforeInsert called before an insert by DB.Insert.
	// If it returns error, the insert will be cancelled.
	BeforeInsert() error
}

BeforeInserter is an interface that hook for before Insert.

type BeforeUpdater

type BeforeUpdater interface {
	// BeforeUpdate called before an update by DB.Update.
	// If it returns error, the update will be cancelled.
	BeforeUpdate() error
}

BeforeUpdater is an interface that hook for before Update.

type Clause

type Clause uint

Clause represents a clause of SQL.

const (
	Where Clause = iota
	And
	Or
	OrderBy
	Limit
	Offset
	In
	Like
	Between
	Join
	LeftJoin
	IsNull
	IsNotNull
)

func (Clause) String

func (c Clause) String() string

type Condition

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

Condition represents a condition for query.

func (*Condition) And

func (c *Condition) And(cond interface{}, args ...interface{}) *Condition

And adds "AND" operator to the Condition and returns it for method chain.

func (*Condition) Between

func (c *Condition) Between(from, to interface{}) *Condition

Between adds "BETWEEN ... AND ..." clause to the Condition and returns it for method chain.

func (*Condition) In

func (c *Condition) In(args ...interface{}) *Condition

In adds "IN" clause to the Condition and returns it for method chain.

func (*Condition) IsNotNull

func (c *Condition) IsNotNull() *Condition

IsNotNull adds "IS NOT NULL" clause to the Condition and returns it for method chain.

func (*Condition) IsNull

func (c *Condition) IsNull() *Condition

IsNull adds "IS NULL" clause to the Condition and returns it for method chain.

func (*Condition) Like

func (c *Condition) Like(arg string) *Condition

Like adds "LIKE" clause to the Condition and returns it for method chain.

func (*Condition) Limit

func (c *Condition) Limit(lim int) *Condition

Limit adds "LIMIT" clause to the Condition and returns it for method chain.

func (*Condition) Offset

func (c *Condition) Offset(offset int) *Condition

Offset adds "OFFSET" clause to the Condition and returns it for method chain.

func (*Condition) Or

func (c *Condition) Or(cond interface{}, args ...interface{}) *Condition

Or adds "OR" operator to the Condition and returns it for method chain.

func (*Condition) OrderBy

func (c *Condition) OrderBy(table, col interface{}, order ...interface{}) *Condition

OrderBy adds "ORDER BY" clause to the Condition and returns it for method chain.

func (*Condition) Where

func (c *Condition) Where(cond interface{}, args ...interface{}) *Condition

Where adds "WHERE" clause to the Condition and returns it for method chain.

type DB

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

DB represents a database object.

func New

func New(dialect Dialect, dsn string) (*DB, error)

New returns a new DB. If any error occurs, it returns nil and error.

func (*DB) Begin

func (db *DB) Begin() error

Begin starts a transaction.

func (*DB) Close

func (db *DB) Close() error

Close closes the database.

func (*DB) Commit

func (db *DB) Commit() error

Commit commits the transaction. If Begin still not called, or Commit or Rollback already called, Commit returns ErrTxDone.

func (*DB) Count

func (db *DB) Count(column ...interface{}) *Function

Count returns "COUNT" function.

func (*DB) CreateIndex

func (db *DB) CreateIndex(table interface{}, name string, names ...string) error

CreateIndex creates the index into database. If table isn't direct/indirect struct, it returns error.

func (*DB) CreateTable

func (db *DB) CreateTable(table interface{}) error

CreateTable creates the table into database. If table isn't direct/indirect struct, it returns error.

func (*DB) CreateTableIfNotExists

func (db *DB) CreateTableIfNotExists(table interface{}) error

CreateTableIfNotExists creates the table into database if table isn't exists. If table isn't direct/indirect struct, it returns error.

func (*DB) CreateUniqueIndex

func (db *DB) CreateUniqueIndex(table interface{}, name string, names ...string) error

CreateUniqueIndex creates the unique index into database. If table isn't direct/indirect struct, it returns error.

func (*DB) DB

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

DB returns a *sql.DB that is associated to DB.

func (*DB) Delete

func (db *DB) Delete(obj interface{}) (affected int64, err error)

Delete deletes the records from database table. The obj must be pointer to struct or slice of struct, and must have field that specified "pk" struct tag. Delete will try to delete record which searched by value of primary key in obj. Delete returns teh number of rows affected by a delete.

func (*DB) Distinct

func (db *DB) Distinct(columns ...string) *Distinct

Distinct returns a representation object of "DISTINCT" statement.

func (*DB) DropTable

func (db *DB) DropTable(table interface{}) error

DropTable removes the table from database. If table isn't direct/indirect struct, it returns error.

func (*DB) From

func (db *DB) From(arg interface{}) *From

From returns a "FROM" statement. A table name will be determined from name of struct of arg. If arg argument is not struct type, it panics.

func (*DB) Insert

func (db *DB) Insert(obj interface{}) (affected int64, err error)

Insert inserts one or more records to the database table. The obj must be pointer to struct or slice of struct. If a struct have a field which specified "pk" struct tag on type of autoincrementable, it won't be used to as an insert value. Insert sets the last inserted id to the primary key of the instance of the given obj if obj is single. Insert returns the number of rows affected by insert.

func (*DB) Join

func (db *DB) Join(table interface{}) *JoinCondition

Join returns a new JoinCondition of "JOIN" clause.

func (*DB) LastInsertId

func (db *DB) LastInsertId() (int64, error)

func (*DB) LeftJoin

func (db *DB) LeftJoin(table interface{}) *JoinCondition

func (*DB) Limit

func (db *DB) Limit(lim int) *Condition

Limit returns a new Condition of "LIMIT" clause.

func (*DB) Offset

func (db *DB) Offset(offset int) *Condition

Offset returns a new Condition of "OFFSET" clause.

func (*DB) OrderBy

func (db *DB) OrderBy(table interface{}, column interface{}, order ...interface{}) *Condition

OrderBy returns a new Condition of "ORDER BY" clause.

func (*DB) Quote

func (db *DB) Quote(s string) string

Quote returns a quoted s. It is for a column name, not a value.

func (*DB) Raw

func (db *DB) Raw(v interface{}) Raw

Raw returns a value that is wrapped with Raw.

func (*DB) Rollback

func (db *DB) Rollback() error

Rollback rollbacks the transaction. If Begin still not called, or Commit or Rollback already called, Rollback returns ErrTxDone.

func (*DB) Select

func (db *DB) Select(output interface{}, args ...interface{}) (err error)

Select fetch data into the output from the database. output argument must be pointer to a slice of struct. If not a pointer or not a slice of struct, It returns error. The table name of the database will be determined from name of struct. e.g. If *[]ATableName passed to output argument, table name will be "a_table_name". If args are not given, fetch the all data like "SELECT * FROM table" SQL.

Example (All)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model";
if err := db.Select(&results); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (Between)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" WHERE "id" BETWEEN 3 AND 5;
if err := db.Select(&results, db.Where("id").Between(3, 5)); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (Columns)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model"."id", "test_model"."name" FROM "test_model";
if err := db.Select(&results, []string{"id", "name"}); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (Complex)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model"."name" FROM "test_model"
//   WHERE "name" LIKE "%alice%" OR ("id" > 100 AND "id" < 200) OR ("id" BETWEEN 700 AND 1000)
//   ORDER BY "id" ASC LIMIT 2 OFFSET 5
if err := db.Select(&results, "name", db.Where("name").
	Like("%alice%").
	Or(db.Where("id", ">", 100).And("id", "<", 200)).
	Or(db.Where("id").Between(700, 1000)).
	Limit(2).Offset(5).OrderBy("id", genmai.ASC),
); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (Count)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var result int64
// SELECT COUNT(*) FROM "test_model";
if err := db.Select(&result, db.Count(), db.From(TestModel{})); err != nil {
	log.Fatal(err)
}
fmt.Println(result)
Output:

Example (CountDistinct)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var result int64
// SELECT COUNT(DISTINCT "test_model"."name") FROM "test_model";
if err := db.Select(&result, db.Count(db.Distinct("name")), db.From(TestModel{})); err != nil {
	log.Fatal(err)
}
fmt.Println(result)
Output:

Example (Distinct)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT DISTINCT "test_model"."name" FROM "test_model";
if err := db.Select(&results, db.Distinct("name")); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (In)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" WHERE "id" IN (1, 3, 5);
if err := db.Select(&results, db.Where("id").In(1, 3, 5)); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (InWithSlice)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
values := []int64{1, 3, 5}
// SELECT "test_model".* FROM "test_model" WHERE "id" IN (1, 3, 5);
if err := db.Select(&results, db.Where("id").In(values)); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (Join)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
type M2 struct {
	Id   int64
	Body string
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" JOIN "m2" ON "test_model"."id" = "m2"."id";
if err := db.Select(&results, "name", db.Join(&M2{}).On("id")); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (JoinWithSpecificTable)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
type M2 struct {
	Id   int64
	Body string
}
type M3 struct {
	TestModelId int64
	M2Id        int64
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" JOIN "m3" ON "test_model"."id" = "m3"."test_model_id" JOIN "m2" ON "m3"."m2_id" = "m2"."id";
if err := db.Select(&results, "name", db.Join(&M3{}).On("id", "=", "test_model_id"), db.Join(&M2{}).On(&M3{}, "m2_id", "=", "id")); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (LeftJoin)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" LEFT JOIN "m2" ON "test_model"."name" = "m2"."body" WHERE "m2"."body" IS NULL;
if err := db.Select(&results, "name", db.LeftJoin(&M2{}).On("name", "=", "body").Where(&M2{}, "body").IsNull()); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (Like)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" WHERE "name" LIKE "alice%";
if err := db.Select(&results, db.Where("name").Like("alice%")); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (Limit)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" LIMIT 3;
if err := db.Select(&results, db.Limit(3)); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (Offset)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" OFFSET 10;
if err := db.Select(&results, db.Offset(10)); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (OrderBy)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" ORDER BY "name" DESC;
if err := db.Select(&results, db.OrderBy("name", genmai.DESC)); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (OrderByMultiple)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" ORDER BY "name" DESC, "addr" DESC;
if err := db.Select(&results, db.OrderBy("name", genmai.DESC, "addr", genmai.DESC)); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (OrderByWithSpecificTable)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" ORDER BY "test_model"."name" DESC;
if err := db.Select(&results, db.OrderBy(TestModel{}, "name", genmai.DESC)); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (Where)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" WHERE "id" = 1;
if err := db.Select(&results, db.Where("id", "=", 1)); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (WhereAnd)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" WHERE "id" = 1 AND "name" = "alice";
if err := db.Select(&results, db.Where("id", "=", 1).And("name", "=", "alice")); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

Example (WhereNested)
db, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
if err != nil {
	log.Fatal(err)
}
var results []TestModel
// SELECT "test_model".* FROM "test_model" WHERE "id" = 1 OR ("name" = "alice" AND "addr" != "Tokyo");
if err := db.Select(&results, db.Where("id", "=", 1).Or(db.Where("name", "=", "alice").And("addr", "!=", "Tokyo"))); err != nil {
	log.Fatal(err)
}
fmt.Println(results)
Output:

func (*DB) SetLogFormat

func (db *DB) SetLogFormat(format string) error

SetLogFormat sets format for logging.

Format syntax uses Go's template. And you can use the following data object in that template.

  • .time time.Time object in current time.
  • .duration Processing time of SQL. It will format to "%.2fms".
  • .query string of SQL query. If it using placeholder, placeholder parameters will append to the end of query.

The default format is:

[{{.time.Format "2006-01-02 15:04:05"}}] [{{.duration}}] {{.query}}

func (*DB) SetLogOutput

func (db *DB) SetLogOutput(w io.Writer)

SetLogOutput sets output destination for logging. If w is nil, it unsets output of logging.

func (*DB) Update

func (db *DB) Update(obj interface{}) (affected int64, err error)

Update updates the one record. The obj must be struct, and must have field that specified "pk" struct tag. Update will try to update record which searched by value of primary key in obj. Update returns the number of rows affected by an update.

func (*DB) Where

func (db *DB) Where(cond interface{}, args ...interface{}) *Condition

Where returns a new Condition of "WHERE" clause.

type Dialect

type Dialect interface {
	// Name returns a name of the dialect.
	// Return value must be same as the driver name.
	Name() string

	// Quote returns a quoted s.
	// It is for a column name, not a value.
	Quote(s string) string

	// PlaceHolder returns the placeholder character of the database.
	// A current number of placeholder will passed to i.
	PlaceHolder(i int) string

	// SQLType returns the SQL type of the v.
	// autoIncrement is whether the field is auto increment.
	// If "size" tag specified to struct field, it will passed to size
	// argument. If it doesn't specify, size is 0.
	SQLType(v interface{}, autoIncrement bool, size uint64) (name string, allowNull bool)

	// AutoIncrement returns the keyword of auto increment.
	AutoIncrement() string

	// FormatBool returns boolean value as string according to the value of b.
	FormatBool(b bool) string

	// LastInsertId returns an SQL to get the last inserted id.
	LastInsertId() string
}

Dialect is an interface that the dialect of the database.

type Distinct

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

Distinct represents a "DISTINCT" statement.

type Float32

type Float32 float32

func (*Float32) Scan

func (f *Float32) Scan(src interface{}) (err error)

Scan implements the database/sql Scanner interface.

func (Float32) Value

func (f Float32) Value() (driver.Value, error)

Value implements the database/sql/driver Valuer interface.

type Float64

type Float64 float64

func (*Float64) Scan

func (f *Float64) Scan(src interface{}) (err error)

Scan implements the database/sql Scanner interface.

func (Float64) Value

func (f Float64) Value() (driver.Value, error)

Value implements the database/sql/driver Valuer interface.

type From

type From struct {
	TableName string
}

From represents a "FROM" statement.

type Function

type Function struct {
	// A function name.
	Name string

	// function arguments (optional).
	Args []interface{}
}

Function represents a function of SQL.

type JoinCondition

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

JoinCondition represents a condition of "JOIN" query.

func (*JoinCondition) Join

func (jc *JoinCondition) Join(table interface{}) *JoinCondition

Join adds table name to the JoinCondition of "JOIN". If table isn't direct/indirect struct type, it panics.

func (*JoinCondition) LeftJoin

func (jc *JoinCondition) LeftJoin(table interface{}) *JoinCondition

LeftJoin adds table name to the JoinCondition of "LEFT JOIN". If table isn't direct/indirect struct type, it panics.

func (*JoinCondition) On

func (jc *JoinCondition) On(larg interface{}, args ...string) *Condition

On adds "[LEFT] JOIN ... ON" clause to the Condition and returns it for method chain.

type MySQLDialect

type MySQLDialect struct{}

MySQLDialect represents a dialect of the MySQL. It implements the Dialect interface.

func (*MySQLDialect) AutoIncrement

func (d *MySQLDialect) AutoIncrement() string

func (*MySQLDialect) FormatBool

func (d *MySQLDialect) FormatBool(b bool) string

FormatBool returns "TRUE" or "FALSE" according to the value of b as boolean for MySQL.

func (*MySQLDialect) LastInsertId

func (d *MySQLDialect) LastInsertId() string

func (*MySQLDialect) Name

func (d *MySQLDialect) Name() string

Name returns name of the MySQLDialect.

func (*MySQLDialect) PlaceHolder

func (d *MySQLDialect) PlaceHolder(i int) string

PlaceHolder returns the placeholder character of the MySQL.

func (*MySQLDialect) Quote

func (d *MySQLDialect) Quote(s string) string

Quote returns a quoted s for a column name.

func (*MySQLDialect) SQLType

func (d *MySQLDialect) SQLType(v interface{}, autoIncrement bool, size uint64) (name string, allowNull bool)

SQLType returns the SQL type of the v for MySQL.

type Order

type Order string

Order represents a keyword for the "ORDER" clause of SQL.

const (
	ASC  Order = "ASC"
	DESC Order = "DESC"
)

func (Order) String

func (o Order) String() string

type PostgresDialect

type PostgresDialect struct{}

PostgresDialect represents a dialect of the PostgreSQL. It implements the Dialect interface.

func (*PostgresDialect) AutoIncrement

func (d *PostgresDialect) AutoIncrement() string

func (*PostgresDialect) FormatBool

func (d *PostgresDialect) FormatBool(b bool) string

FormatBool returns "TRUE" or "FALSE" according to the value of b as boolean for PostgreSQL.

func (*PostgresDialect) LastInsertId

func (d *PostgresDialect) LastInsertId() string

func (*PostgresDialect) Name

func (d *PostgresDialect) Name() string

Name returns name of the PostgresDialect.

func (*PostgresDialect) PlaceHolder

func (d *PostgresDialect) PlaceHolder(i int) string

PlaceHolder returns the placeholder character of the PostgreSQL.

func (*PostgresDialect) Quote

func (d *PostgresDialect) Quote(s string) string

Quote returns a quoted s for a column name.

func (*PostgresDialect) SQLType

func (d *PostgresDialect) SQLType(v interface{}, autoIncrement bool, size uint64) (name string, allowNull bool)

SQLType returns the SQL type of the v for PostgreSQL.

type Rat

type Rat struct {
	*big.Rat
}

Rat is an wrapper of the Rat of math/big. However, Rat implements the sql Scanner interface.

func NewRat

func NewRat(a, b int64) *Rat

NewRat returns a new Rat. This is the similar to NewRat of math/big.

func (*Rat) Scan

func (rat *Rat) Scan(src interface{}) (err error)

Scan implements the database/sql Scanner interface.

func (Rat) Value

func (rat Rat) Value() (driver.Value, error)

Value implements the database/sql/driver Valuer interface.

type Raw

type Raw *interface{}

Raw represents a raw value. Raw value won't quoted.

type SQLite3Dialect

type SQLite3Dialect struct{}

SQLite3Dialect represents a dialect of the SQLite3. It implements the Dialect interface.

func (*SQLite3Dialect) AutoIncrement

func (d *SQLite3Dialect) AutoIncrement() string

func (*SQLite3Dialect) FormatBool

func (d *SQLite3Dialect) FormatBool(b bool) string

FormatBool returns "1" or "0" according to the value of b as boolean for SQLite3.

func (*SQLite3Dialect) LastInsertId

func (d *SQLite3Dialect) LastInsertId() string

func (*SQLite3Dialect) Name

func (d *SQLite3Dialect) Name() string

Name returns name of the dialect.

func (*SQLite3Dialect) PlaceHolder

func (d *SQLite3Dialect) PlaceHolder(i int) string

PlaceHolder returns the placeholder character of the SQLite3.

func (*SQLite3Dialect) Quote

func (d *SQLite3Dialect) Quote(s string) string

Quote returns a quoted s for a column name.

func (*SQLite3Dialect) SQLType

func (d *SQLite3Dialect) SQLType(v interface{}, autoIncrement bool, size uint64) (name string, allowNull bool)

SQLType returns the SQL type of the v for SQLite3.

type TableNamer

type TableNamer interface {
	// TableName returns the table name on DB.
	TableName() string
}

TableNamer is an interface that is used to use a different table name.

type TimeStamp

type TimeStamp struct {
	// Time of creation. This field will be set automatically by BeforeInsert.
	CreatedAt time.Time `json:"created_at"`

	// Time of update. This field will be set by BeforeInsert or BeforeUpdate.
	UpdatedAt time.Time `json:"updated_at"`
}

TimeStamp is fields for timestamps that commonly used.

func (*TimeStamp) BeforeInsert

func (ts *TimeStamp) BeforeInsert() error

BeforeInsert sets current time to CreatedAt and UpdatedAt field. It always returns nil.

func (*TimeStamp) BeforeUpdate

func (ts *TimeStamp) BeforeUpdate() error

BeforeUpdate sets current time to UpdatedAt field. It always returns nil.

Jump to

Keyboard shortcuts

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