DEV Community

Cover image for golang generic orm
Seiya
Seiya

Posted on

golang generic orm

ggm

golang generic orm, base on sqlx

install

go get github.com/daodao97/ggm
Enter fullscreen mode Exit fullscreen mode

usage

Below is an example which shows some common use cases for ggm. Check model_test.go for more usage.

init db

We can initialize some db resources commonly used by programs, like this

// map[conn_name]db_config
ggm.Init(map[string]*ggm.Config{
    "default": {
        DSN: "root@tcp(127.0.0.1:3306)/ggm_test?&parseTime=true",
    },
})
Enter fullscreen mode Exit fullscreen mode

Of course, we can also instantiate some temporary DB resources, like this

m := ggm.NewConn(&ggm.Config{
    DSN: "root@tcp(127.0.0.1:3306)/ggm_test?&parseTime=true" 
})
Enter fullscreen mode Exit fullscreen mode

data model

For example, we have a table with the following structure

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '0',
  `profile` varchar(200) NOT NULL,
  `is_deleted` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `ctime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `mtime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Enter fullscreen mode Exit fullscreen mode

struct define

The structure model for this table is

type User struct {
    Id      int             `db:"id,pk"   json:"id"`
    Name    string          `db:"name"    json:"name"`
    Profile string          `db:"profile" json:"profile"`
    CTime   time.Time       `db:"ctime"   json:"ctime"`
}

func (u User) Table() string {
    return "user"
}

Enter fullscreen mode Exit fullscreen mode

interface: Table() string the struct must implement.

struct field must have db tag, value is db field name.

set conn

If you are using a db resource that is not the default

func (u User) Conn() string {
    return "conn_name"
}
Enter fullscreen mode Exit fullscreen mode

fake delete

If you have a field to mark fake delete

func (u User) FakeDeleteKey() string {
    return "is_deleted"
}
Enter fullscreen mode Exit fullscreen mode

then, the delete sql will converted to update ${fakeDeleteKey} = 1 when we delete data

select sql will auto add ${fackDeleteKey} = 0, to filter deleted data.

select

m := ggm.New[*User]() // or ggm.New[User]() 

m.Select(ggm.WhereEq("id", 1))
Enter fullscreen mode Exit fullscreen mode

detail of where condition see where condition

insert

user := &User{Name: "Seiya"}

// single insert
m.Insert(user)

// batch insert
m.Insert(user, user2, ...)
Enter fullscreen mode Exit fullscreen mode

update

use primary key update

user := &User{Id: 1, Name: "Seiya!!!"}
m.Update(user)
Enter fullscreen mode Exit fullscreen mode

with where condition

user := &User{Name: "Seiya!!!"}
m.Update(user, ggm.WhereEq("id", 1))
Enter fullscreen mode Exit fullscreen mode

delete

m.Delete(ggm.WhereEq("id", 1))
Enter fullscreen mode Exit fullscreen mode

where condition

m.Select(
    WhereEq("id", 1),
    WhereGt("age", 20),
    WhereLike("name", "dd"),
    WhereGroup(
        WhereEq("sex", 1),
        WhereOrEq("class", 2),
        WhereGroup(
            WhereEq("sex1", 1),
            WhereEq("class2", 2),
        ),
    ),
    OrderBy("id", DESC),
)
Enter fullscreen mode Exit fullscreen mode

more example, checkout sql_test.go

data type

Json

If the value of field user.profile is json_string like {"skill":"Pegasus Ryuseiken"}

type User struct {
    Id      int                 `db:"id,pk"   json:"id"`
    Name    string              `db:"name"    json:"name"`
    Profile *ggm.Json[*Profile] `db:"profile" json:"profile"`
    CTime   time.Time           `db:"ctime"   json:"ctime"`
}

type Profile struct {
    Skill string `json:"skill"`
}
Enter fullscreen mode Exit fullscreen mode

Profile{Skill: "xxx"} <==> '{"skill":"xxx"}'

Data can be automatically converted into struct for use by programs.

Time

type User struct {
    Id      int                 `db:"id,pk"   json:"id"`
    Name    string              `db:"name"    json:"name"`
    Profile *ggm.Json[*Profile] `db:"profile" json:"profile"`
    CTime   ggm.Time            `db:"ctime"   json:"ctime"`
}
Enter fullscreen mode Exit fullscreen mode

when api response or json.Marshal

ctime : 2022-03-19T11:52:19Z => 2022-03-19 11:52:19

define yourself data type

Implement the following interfaces

type DataType[T any] interface {
    Value() (driver.Value, error)
    Scan(value any) error
    MarshalJSON() ([]byte, error)
    UnmarshalJSON(b []byte) error
    Get() T
}
Enter fullscreen mode Exit fullscreen mode

Linked data

hasOne

one to one

type User struct {
    Id      int             `db:"id,pk"   json:"id"`
    Name    string          `db:"name"    json:"name"`
    Profile *Json[*Profile] `db:"profile" json:"profile"`
    Score   int             `db:"score"   json:"score" hasOne:"user_score:uid"`
    Score2  int             `db:"score2"  json:"score2" hasOne:"user_score:uid"`
}
Enter fullscreen mode Exit fullscreen mode

hasMany

one to N

type User struct {
    Id      int             `db:"id,pk"   json:"id"`
    Name    string          `db:"name"    json:"name"`
    Profile *Json[*Profile] `db:"profile" json:"profile"`
    Logs    []*Log          `json:"logs"  hasMany:"user_log:uid"`
}

type Log struct {
    Message string `db:"message" json:"message"`
}
Enter fullscreen mode Exit fullscreen mode

hasOne or hasMany tag token:

[conn.][database.]table:[local_key->]foreign_key

m.Select() will auto query the linked data into the struct.

Check model_test.go for detail.

Top comments (0)