V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  ç™»å½•
The Go Programming Language
› http://golang.org/
› Go Playground
Go Projects
› Revel Web Framework
› beego
IIInsomnia
V2EX  â€º  Go

🔥 Go 轻量级开发通用库 🚀🚀🚀

  •  1
     
  •   IIInsomnia · 27 天前 · 1897 次点击

    yiigo

    golang GitHub release pkg.go.dev MIT license

    Go 轻量级开发通用库

    Features

    • 支持 MySQL
    • 支持 PostgreSQL
    • 支持 SQLite3
    • 支持 MongoDB
    • 支持 Redis
    • 支持 NSQ
    • 邮件使用 gomail
    • 配置使用 toml
    • SQL 使用 sqlx
    • ORM 推荐 ent
    • 日志使用 zap
    • 包含一些实用的辅助方法,如: http 、cypto 、date 、IP 、version compare 、SQL Builder 等

    Requirements

    Go1.15+

    Installation

    go get -u github.com/shenghui0779/yiigo
    

    Usage

    Config

    • yiigo.toml
    [app]
    env = "dev" # dev | beta | prod
    debug = true
    
    [db]
    
        [db.default]
        driver = "mysql" # mysql | postgres | sqlite3
        dsn = "username:[email protected](localhost:3306)/dbname?timeout=10s&charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&loc=Local" # mysql
        # dsn = "host=localhost port=5432 user=root password=secret dbname=test connect_timeout=10 sslmode=disable" # postgres
        # dsn = "file::memory:?cache=shared" # sqlite3
        max_open_conns = 20
        max_idle_conns = 10
        conn_max_idle_time = 60 # 秒
        conn_max_lifetime = 60 # 秒
    
    [mongo]
    
        [mongo.default]
        # 参考: https://docs.mongodb.com/manual/reference/connection-string
        dsn = "mongodb://localhost:27017/?connectTimeoutMS=10000&minPoolSize=10&maxPoolSize=20&maxIdleTimeMS=60000&readPreference=primary"
    
    [redis]
    
        [redis.default]
        address = "127.0.0.1:6379"
        password = ""
        database = 0
        connect_timeout = 10 # 秒
        read_timeout = 10 # 秒
        write_timeout = 10 # 秒
        pool_size = 10
        pool_limit = 20
        idle_timeout = 60 # 秒
        wait_timeout = 10 # 秒
        prefill_parallelism = 0 # 预填充连接数
    
    [nsq]
    lookupd = ["127.0.0.1:4161"]
    nsqd = "127.0.0.1:4150"
    
    [email]
    
        [email.default]
        host = "smtp.exmail.qq.com"
        port = 25
        username = ""
        password = ""
    
    [log]
    
        [log.default]
        path = "app.log"
        max_size = 500
        max_age = 0
        max_backups = 0
        compress = true
    
    # 自定义配置
    
    [foo]
    amount = 100
    ports = [80, 81, 82]
    weight = 50.6
    prices = [23.5, 46.7, 45.9]
    hosts = ["127.0.0.1", "192.168.1.1", "192.168.1.80"]
    birthday = "2019-07-12 13:03:19"
    
    • usage
    yiigo.Env("app.env").String()
    yiigo.Env("app.debug").Bool()
    yiigo.Env("foo.amount").Int()
    yiigo.Env("foo.ports").Ints()
    yiigo.Env("foo.weight").Float()
    yiigo.Env("foo.price").Floats()
    yiigo.Env("foo.hosts").Strings()
    yiigo.Env("foo.birthday").Time("2006-01-02 15:04:05")
    

    MySQL

    // default db
    yiigo.DB().Get(&User{}, "SELECT * FROM user WHERE id = ?", 1)
    
    // other db
    yiigo.DB("other").Get(&User{}, "SELECT * FROM user WHERE id = ?", 1)
    

    ORM(ent)

    import "<your_project>/ent"
    
    // default driver
    client := ent.NewClient(ent.Driver(yiigo.EntDriver()))
    
    // other driver
    client := ent.NewClient(ent.Driver(yiigo.EntDriver("other")))
    

    MongoDB

    // default mongodb
    yiigo.Mongo().Database("test").Collection("numbers").InsertOne(context.Background(), bson.M{"name": "pi", "value": 3.14159})
    
    // other mongodb
    yiigo.Mongo("other").Database("test").Collection("numbers").InsertOne(context.Background(), bson.M{"name": "pi", "value": 3.14159})
    

    Redis

    // default redis
    conn, err := yiigo.Redis().Get(context.Background())
    
    if err != nil {
        log.Fatal(err)
    }
    
    defer yiigo.Redis().Put(conn)
    
    conn.Do("SET", "test_key", "hello world")
    
    // other redis
    conn, err := yiigo.Redis("other").Get(context.Background())
    
    if err != nil {
        log.Fatal(err)
    }
    
    defer yiigo.Redis("other").Put(conn)
    
    conn.Do("SET", "test_key", "hello world")
    

    HTTP

    // default client
    yiigo.HTTPGet(context.Background(), "URL", yiigo.WithHTTPTimeout(5*time.Second))
    
    // new client
    c := yiigo.NewHTTPClient(*http.Client)
    c.Get(context.Background(), "URL", yiigo.WithHTTPTimeout(5*time.Second))
    

    Logger

    // default logger
    yiigo.Logger().Info("hello world")
    
    // other logger
    yiigo.Logger("other").Info("hello world")
    

    SQL Builder

    😊 为不想手写 SQL 的你生成 SQL 语句,用于 sqlx 的相关方法;

    ⚠️ 作为辅助方法,目前支持的特性有限,复杂的 SQL (如:子查询等)还需自己手写

    builder := yiigo.NewSQLBuilder(yiigo.MySQL)
    
    • Query
    builder.Wrap(
        yiigo.Table("user"),
        yiigo.Where("id = ?", 1),
    ).ToQuery()
    // SELECT * FROM user WHERE id = ?
    // [1]
    
    builder.Wrap(
        yiigo.Table("user"),
        yiigo.Where("name = ? AND age > ?", "shenghui0779", 20),
    ).ToQuery()
    // SELECT * FROM user WHERE name = ? AND age > ?
    // [shenghui0779 20]
    
    builder.Wrap(
        yiigo.Table("user"),
        yiigo.WhereIn("age IN (?)", []int{20, 30}),
    ).ToQuery()
    // SELECT * FROM user WHERE age IN (?, ?)
    // [20 30]
    
    builder.Wrap(
        yiigo.Table("user"),
        yiigo.Select("id", "name", "age"),
        yiigo.Where("id = ?", 1),
    ).ToQuery()
    // SELECT id, name, age FROM user WHERE id = ?
    // [1]
    
    builder.Wrap(
        yiigo.Table("user"),
        yiigo.Distinct("name"),
        yiigo.Where("id = ?", 1),
    ).ToQuery()
    // SELECT DISTINCT name FROM user WHERE id = ?
    // [1]
    
    builder.Wrap(
        yiigo.Table("user"),
        yiigo.LeftJoin("address", "user.id = address.user_id"),
        yiigo.Where("user.id = ?", 1),
    ).ToQuery()
    // SELECT * FROM user LEFT JOIN address ON user.id = address.user_id WHERE user.id = ?
    // [1]
    
    builder.Wrap(
        yiigo.Table("address"),
        yiigo.Select("user_id", "COUNT(*) AS total"),
        yiigo.GroupBy("user_id"),
        yiigo.Having("user_id = ?", 1),
    ).ToQuery()
    // SELECT user_id, COUNT(*) AS total FROM address GROUP BY user_id HAVING user_id = ?
    // [1]
    
    builder.Wrap(
        yiigo.Table("user"),
        yiigo.Where("age > ?", 20),
        yiigo.OrderBy("age ASC", "id DESC"),
        yiigo.Offset(5),
        yiigo.Limit(10),
    ).ToQuery()
    // SELECT * FROM user WHERE age > ? ORDER BY age ASC, id DESC OFFSET 5 LIMIT 10
    // [20]
    
    wrap1 := builder.Wrap(
        Table("user_1"),
        Where("id = ?", 2),
    )
    
    builder.Wrap(
        Table("user_0"),
        Where("id = ?", 1),
        Union(wrap1),
    ).ToQuery()
    // (SELECT * FROM user_0 WHERE id = ?) UNION (SELECT * FROM user_1 WHERE id = ?)
    // [1, 2]
    
    builder.Wrap(
        Table("user_0"),
        Where("id = ?", 1),
        UnionAll(wrap1),
    ).ToQuery()
    // (SELECT * FROM user_0 WHERE id = ?) UNION ALL (SELECT * FROM user_1 WHERE id = ?)
    // [1, 2]
    
    builder.Wrap(
        Table("user_0"),
        WhereIn("age IN (?)", []int{10, 20}),
        Limit(5),
        Union(
            builder.Wrap(
                Table("user_1"),
                Where("age IN (?)", []int{30, 40}),
                Limit(5),
            ),
        ),
    ).ToQuery()
    // (SELECT * FROM user_0 WHERE age IN (?, ?) LIMIT ?) UNION (SELECT * FROM user_1 WHERE age IN (?, ?) LIMIT ?)
    // [10, 20, 5, 30, 40, 5]
    
    builder.Wrap(Table("user")).ToTruncate()
    // TRUNCATE user
    
    • Insert
    type User struct {
        ID     int    `db:"-"`
        Name   string `db:"name"`
        Age    int    `db:"age"`
        Phone  string `db:"phone,omitempty"`
    }
    
    builder.Wrap(Table("user")).ToInsert(&User{
        Name: "yiigo",
        Age:  29,
    })
    // INSERT INTO user (name, age) VALUES (?, ?)
    // [yiigo 29]
    
    builder.Wrap(yiigo.Table("user")).ToInsert(yiigo.X{
        "name": "yiigo",
        "age":  29,
    })
    // INSERT INTO user (name, age) VALUES (?, ?)
    // [yiigo 29]
    
    • Batch Insert
    type User struct {
        ID     int    `db:"-"`
        Name   string `db:"name"`
        Age    int    `db:"age"`
        Phone  string `db:"phone,omitempty"`
    }
    
    builder.Wrap(Table("user")).ToBatchInsert([]*User{
        {
            Name: "shenghui0779",
            Age:  20,
        },
        {
            Name: "yiigo",
            Age:  29,
        },
    })
    // INSERT INTO user (name, age) VALUES (?, ?), (?, ?)
    // [shenghui0779 20 yiigo 29]
    
    builder.Wrap(yiigo.Table("user")).ToBatchInsert([]yiigo.X{
        {
            "name": "shenghui0779",
            "age":  20,
        },
        {
            "name": "yiigo",
            "age":  29,
        },
    })
    // INSERT INTO user (name, age) VALUES (?, ?), (?, ?)
    // [shenghui0779 20 yiigo 29]
    
    • Update
    type User struct {
        Name   string `db:"name"`
        Age    int    `db:"age"`
        Phone  string `db:"phone,omitempty"`
    }
    
    builder.Wrap(
        Table("user"),
        Where("id = ?", 1),
    ).ToUpdate(&User{
        Name: "yiigo",
        Age:  29,
    })
    // "UPDATE user SET name = ?, age = ? WHERE id = ?"
    // [yiigo 29 1]
    
    builder.Wrap(
        yiigo.Table("user"),
        yiigo.Where("id = ?", 1),
    ).ToUpdate(yiigo.X{
        "name": "yiigo",
        "age":  29,
    })
    // UPDATE user SET name = ?, age = ? WHERE id = ?
    // [yiigo 29 1]
    
    builder.Wrap(
        yiigo.Table("product"),
        yiigo.Where("id = ?", 1),
    ).ToUpdate(yiigo.X{
        "price": yiigo.Clause("price * ? + ?", 2, 100),
    })
    // UPDATE product SET price = price * ? + ? WHERE id = ?
    // [2 100 1]
    
    • Delete
    builder.Wrap(
        yiigo.Table("user"),
        yiigo.Where("id = ?", 1),
    ).ToDelete()
    // DELETE FROM user WHERE id = ?
    // [1]
    

    Documentation

    Enjoy 😊

    5 条回复  â€¢  2021-04-23 08:00:48 +08:00
    betteron
        1
    betteron   27 天前
    ORM 推荐 ent 的理由是啥, 我们现在在用 gorm,与之比较呢?
    masterclock
        2
    masterclock   27 天前
    gorm:
    db.Where("name = ?", 1).Find(&users)

    ent:
    client.User.Query(user.Name("xyz")).All(ctx)

    以前也用 gorm,类型信息全没了,实在不爽。
    FightPig
        3
    FightPig   26 天前
    我习惯用 gorm,看个人习惯了
    alinwu05
        4
    alinwu05   25 天前
    yiigo,和 yii 什么关系?
    IIInsomnia
        5
    IIInsomnia   25 天前
    @alinwu05 没啥关系,就是用的他的谐音和通“易”的说法,旨在对新手来说,让 Go 开发更容易
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2607 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 11:26 · PVG 19:26 · LAX 04:26 · JFK 07:26
    ♥ Do have faith in what you're doing.