我想在Golang中使用Teng

我是TuneCore日本的新人工程师 skfvr。

这篇文章是Wano Group Advent Calendar 2019的第三天的文章。

本次将讲述如何用Golang自己编写一个类似Perl轻量级ORM工具” Teng “的故事。

请注意

    • 本記事はPerl/Golangのいずれかを持ち上げる/持ち下げる目的の記事でないことを予めお断りしておきます。

 

    • 業務とは関係ありません。

 

    初投稿故、誤字/脱字/知識不足を暖かく見守っていただけると幸いです。知識不足の祭は指摘していただけると嬉しいです。

1. “Teng是什么意思?”

首先使用Teng。Teng是Perl中的一种轻量级ORM。例如,可以像下面这样简化部分代码的编写。

my $hoge = $teng->single('hoge_table',{
    id => 1,
});
# => select * from hoge_table where id = 1

如果查询很简单,可以使用简洁的表达来描述,因此在想要打这样的查询时非常方便。此外,还可以直接编写并执行查询。

my $hoge = $teng->search_by_sql("select * from hoge_table where id = 1");

当我第一次使用它时,我想着“如果在Golang中也能像Teng一样写查询语句,那就太强大了”(感到惊讶)。

顺便提一下,在这个阶段,Go语言已经有了很多方便易用的ORM,比如”gorm”和”sqlx”等等,所以从实战角度来看,不太有必要再花费精力去开发一个自己的ORM,这样感觉上并没有太多优势。

2. 先提一下

我先介绍一下已经完成的东西(由于简化写作,请见谅)。

    sql, args, err := dao.Select(model.TableNameHogeTable, model.HogeTableParam{
        DeleteFlg: st.Statement{"=", false},
        Name:     st.Statement{"=", "hoge"},
    }).SQL()
// => select * from hoge_table where delete_flg = 0 and name = "hoge";
    sql, args, err := dao.Update(model.TableNameHogeTable, model.HogeTableSetter{
        Name: st.Setter{"hoge"},
    }, model.HogeTableParam{
        ID: st.Statement{"=", 225},
    })
// => update hoge_table set name = "hoge" where id = 225;

我竟然做出了一个具有我自我的东西…。

顺便说一下,在Golang中,我经常看到的查询生成器就是这样的。如果不忽略换行的话,这个版本更易读。

sql, args, err := generator.Select(TableNameHogeTable)
.Where("delete_flg", "=", 0)
.Where("name", "=", "hoge")

3. 紹介一下疲劳点。

我会介绍在制作过程中让人感觉很辛苦的一点。其中最辛苦的部分是”模具”。

形状

非常艰辛。

必须将MySQL的类型转换为Golang的类型。

在Perl中,只要掌握标量,哈希和数组这些基本概念,就可以应对各种情况,例如可以写成以下这样。

my $hoge = $teng->single('hoge_table',{
    number  => 25,
    name    => "tutugo"
});

在这种情况下,number和name被称为”数值”和”字符串”,但在Perl中并不相关。如果是用Golang来处理,则需要依赖interface{}。在这个例子中,st.Statement.Value成为interface{},这样我们可以通过它接收一个参数或者一个切片,并在此基础上构建查询的计划。

这次的实现方式不太顺畅,每次都要插入一个名为 st.Statement 的结构体,感觉有些不太自然…。

    sql, args, err := dao.Select(model.TableNameHogeTable, model.HogeTableParam{
        Number: st.Statement{Operation:"=", Value:25},
        Name:     st.Statement{Operation:"=", Value:"tutugo"},
    }).SQL()

作为理想状况,可能是这种感觉吧(处理起来非常麻烦)。

    sql, args, err := dao.Select(model.TableNameHogeTable, model.HogeTableParam{
        Number: 25,
        Name:"tutugo",
    }).SQL()

零值处理

這個地方在Golang中是相當困難的部分。簡單來說

    • 数値の0

 

    • 空文字列 “”

boolean の false

在某些情况下,诸如零值的悲惨命运会被处理。例如,当使用json标签的omitempty选项时,该元素在进行json编码时会被忽略。在著名的gorm中,如果希望处理零值,推荐使用NullInt。

當情況變得複雜時很辛苦。

到目前为止,所有的代码都是这样的感觉。我一直介绍的都是简单的查询。

    sql, args, err := dao.Select(model.TableNameHogeTable, model.HogeTableParam{
        Number: st.Statement{Operation:"=", Value:25},
        Name:     st.Statement{Operation:"=", Value:"tutugo"},
    }).SQL()
// => select * from hoge_table were number = 25 and name = "tutugo"

如果想在这里写一个例如10到30之间的数字,而且又不在20到25之间的数字,该怎么办呢…。

    sql, args, err = dao.Select(model.TableNameHogeTable, &model.HogeTableParam{
        ID: st.StatementAnd{
            st.Statement{"between", []int{10, 30}},
            st.Statement{"not between", []int{20, 25}},
        },
    }).SQL()

// => select * from hoge_table where
//   ( ( id between ? and ? and id not between ? and ? ) )
//   [10 30 20 25]
//

/ || ̄ ̄|| ∧_∧
|…..||__|| ( ^ω^ )  …?
| ̄ ̄\三⊂/ ̄ ̄ ̄/
|    | ( ./     /

/ || ̄ ̄|| ∧_∧
|…..||__|| ( ^ω^ )  …?
| ̄ ̄\三⊂/ ̄ ̄ ̄/
|    | ( ./    /

/ || ̄ ̄|| ∧_∧
|…..||__|| ( ^ω^ )  …?
| ̄ ̄\三⊂/ ̄ ̄ ̄/
|    | ( ./   /

慢慢地我开始感到混乱了…尤其是一些让我尴尬的话语开始出现了。

課題點可以改善。

或者”或”不够有效。

可能是结构有问题的点。例如

select * from hoge_table
where ( id = 1 and name = "kuwahara")
or
( id = 0 and name = "nakai")

这样的查询目前还无法实现,这是因为之前不经思考就进行了这样的实施。

func dao.Select(tableName string, model.Param)

type Hoge struct{
    ID int
    Name string
    Age int
}

type HogeParam struct{
    ID StatementInterface
    Name StatementInterface
    Age StatementInterface
}

总之,就是无法创建 Param 的情况,对吧… 在创建查询时只能选择一个 model.param。我认为这些细节还有很多需要改进的地方。

无法加入

当事者が多くなることと時間の制約があることでしょう。

table_name.id のような表記にする必要がある

join hoge h on ごにょごにょ の「ごにょごにょ」を書けるようにする必要がある。

(おおよそは where 以下の部分と同じだし案外何とかなると思っている)

还有很长一段时间才能通过自制发电机满足一切需求吧…

5. 我的想法

    • reflect すごい。

 

    • 様々な言語で orm や クエリジェネレーター に関わっている方すごい。

 

    落ち着けば仮完成させて放出してみたい(謎の自信)。

最后。参考链接

    • https://metacpan.org/pod/Teng

 

    • https://golang.org/pkg/reflect/

 

    • http://gorm.io/ja_JP/docs/index.html

 

    https://github.com/jmoiron/sqlx
广告
将在 10 秒后关闭
bannerAds