golang sql mapper

eatmoreapple · 2022-11-01 23:51:58 · 1569 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2022-11-01 23:51:58 的主题,其中的信息可能已经有所发展或是发生改变。

Juice SQL Mapper Framework For Golang

Go Doc Go Report Card License

This is a SQL mapper framework for Golang. It is inspired by MyBatis.

Juice is a simple and lightweight framework. It is easy to use and easy to extend.

Features

  • Simple and lightweight
  • Easy to use
  • Easy to extend
  • Support for multiple databases
  • Dynamic SQL
  • Result to entity mapping
  • Generic type support
  • Middleware support
  • Todo support more

support xml tags

  • select
  • insert
  • update
  • delete
  • sql
  • if
  • where
  • trim
  • set
  • foreach
  • choose
  • when
  • otherwise
  • include

Condition Method

The condition method can be used with if or when tags.

For example:

<!--ids = []int{1,2,3}-->
<if test='len(ids) > 0 && substr("eatmoreapple", 0, 3) == "eat"'>
    your sql node here
</if>

It can register to the framework with your own condition method.

Here are some default condition methods.

  • len: return the length of the given parameter
  • strsub: return the substring of the given parameter
  • join: join the given parameters with the given separator
  • contains: return true if the given parameter contains the given element
  • slice: return the slice of the given parameter

Quick Start

Install

go get github.com/eatmoreapple/juice

Example

touch config.xml

and write the following content into config.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <environments default="prod">
        <environment id="prod">
            <dataSource>root:qwe123@tcp(localhost:3306)/database</dataSource>
            <driver>mysql</driver>
        </environment>
    </environments>


    <mappers>
        <mapper namespace="main.UserRepository" table="user">

            <sql id="columns">
                `id`, `name`, `age`
            </sql>

            <sql id="selectAll">
                select
                <include refid="columns"/>
                from ${table}
            </sql>


            <select id="GetUserByID" debug="true">
                <include refid="selectAll"/>
                where id = #{param}
            </select>

            <insert id="CreateUser" debug="true">
                insert into ${table}
                <trim prefix="(" suffixOverrides="," suffix=")">
                    <if test='name != ""'>
                        name,
                    </if>
                    <if test="age > 0">
                        age,
                    </if>
                </trim>
                <trim prefix="values (" suffix=")" suffixOverrides=",">
                    <if test='name != ""'>
                        #{name},
                    </if>
                    <if test="age > 0">
                        #{age},
                    </if>
                </trim>
            </insert>

            <update id="UpdateUser" debug="true">
                update ${table}
                <set>
                    <if test='name != ""'>
                        `name` = #{name},
                    </if>
                    <if test="age > 0">
                        `age` = #{age},
                    </if>
                </set>
                where id = #{id}
            </update>

            <delete id="DeleteUserByID" debug="true" table="user">
                delete from ${table} where id = #{param}
            </delete>

        </mapper>
    </mappers>
</configuration>
package main

import (
    "context"
    "fmt"
    "github.com/eatmoreapple/juice"
    "reflect"

    _ "github.com/go-sql-driver/mysql"
)

var schema = `
CREATE TABLE IF NOT EXISTS user (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(255) COLLATE utf8mb4_bin NOT NULL,
  age int(11) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
`

type User struct {
    Id   int64  `column:"id" param:"id"`
    Name string `column:"name" param:"name"`
    Age  int    `column:"age" param:"age"`
}

type UserRepository interface {
    GetUserByID(id int64)
    CreateUser(user *User)
    UpdateUser(user *User)
    DeleteUserByID(id int64)
}

type UserRepositoryImpl struct{}

func (u UserRepositoryImpl) UpdateUser(user *User) {
    //TODO implement me
    panic("implement me")
}

func (u UserRepositoryImpl) DeleteUserByID(id int64) {
    //TODO implement me
    panic("implement me")
}

func (u UserRepositoryImpl) CreateUser(user *User) {
    //TODO implement me
    panic("implement me")
}

func (u UserRepositoryImpl) GetUserByID(id int64) {
    //TODO implement me
    panic("implement me")
}

func main() {
    cfg, err := juice.NewXMLConfiguration("config.xml")
    if err != nil {
        fmt.Println(err)
        return
    }

    engine, err := juice.DefaultEngine(cfg)
    if err != nil {
        fmt.Println(err)
        return
    }

    // create table first
    if _, err = engine.DB.Exec(schema); err != nil {
        fmt.Println(err)
        return
    }

    var repo UserRepository = UserRepositoryImpl{}

    // create user first
    user := &User{
        Name: "eatmoreapple",
        Age:  18,
    }

    result, err := engine.Object(repo.CreateUser).ExecContext(context.Background(), user)
    if err != nil {
        fmt.Println(err)
        return
    }
    user.Id, err = result.LastInsertId()
    if err != nil {
        fmt.Println(err)
        return
    }

    // query user
    rows, err := engine.Object(repo.GetUserByID).Query(user.Id)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer rows.Close()

    // todo: iterate rows with your own way

    // query user with auto mapping
    user2, err := juice.NewGenericManager[*User](engine).Object(repo.GetUserByID).Query(user.Id).One()
    if err != nil {
        fmt.Println(err)
        return
    }

    if reflect.DeepEqual(user, user2) {
        fmt.Println("user and user2 are equal")
    } else {
        fmt.Println("user and user2 are not equal")
        return
    }

    // with transaction

    // begin transaction

    // begin
    tx := engine.Tx()

    // update user with tx
    user.Name = "eatmoreapple2"
    user.Age = 20
    result, err = tx.Object(repo.UpdateUser).ExecContext(context.Background(), user)
    if err != nil {
        fmt.Println(err)
        tx.Rollback()
        return
    }
    affected, err := result.RowsAffected()
    if err != nil {
        fmt.Println(err)
        tx.Rollback()
        return
    }
    fmt.Printf("update affected rows: %d\n", affected)

    // delete user with tx
    result, err = tx.Object(repo.DeleteUserByID).ExecContext(context.Background(), user.Id)
    if err != nil {
        fmt.Println(err)
        tx.Rollback()
        return
    }
    affected, err = result.RowsAffected()
    if err != nil {
        fmt.Println(err)
        tx.Rollback()
        return
    }
    fmt.Printf("delete affected rows: %d\n", affected)

    // commit
    if err = tx.Commit(); err != nil {
        fmt.Println(err)
        return
    }
}

License

Juice is licensed under the Apache License, Version 2.0. See LICENSE for the full license text.

Contact

If you like this project, please give me a star. Thank you. And If you have any questions, please contact me by WeChat: eatmoreapple or scan the following QR code.


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1569 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传