Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

111 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PGears

Toolkits for easy to use PostgreSQL in Golang

说明一下……

首先,这个是给公司的项目自用的,所以不会坑。但是不保证符合正常的需要……我本来就是个不正常的程序员啊……

普通用户我推荐 xorm 或 beedb,前者功能很全,很强大,后者使用简单方便。一般的场景够用了。

PGears 顾名思义,着眼于为 Go 语言项目访问和操作 PostgreSQL 提供一组方便的工具。不一定全是 ORM , 也应该不是完整的 ORM 工具。实际上 ORM 工具我只喜欢 SQLAlchemy ……

通用性

通常来说,一个完整的数据库访问工具总是要考虑通用性。但是在这里,我希望尽可能实现对 Postgres 的支持。PG 的异步访问,丰富的数据类型,强大的编程能力。对应用层编程的支持可以带来很多提升。但是如果 要开发一个普适于多种数据库产品的访问工具,难免要在特异性的支持上有所牺牲。例如 MySQL 就缺少很多 Postgres 里好用的数据类型。

动态和静态化

在 Python 里我常常感到很不舒服的是,有些代码我们都知道它其实是确定的,但是在一个全动态的语言中, 它总会一遍又一遍的被执行。例如传统上的 SQLAlchemy 或 WxPython 的初始化逻辑(wx很久不用了,不过 SQLAlchemy 在这方面是有所改进的)。Go 本身是个静态化的语言,而且它的反射功能相当有限。加上没有模板 /宏这样的编译期代码推导能力。我们很难写出强类型的普适代码。

ADO.net 在早期 CLR 不提供范型的时代,就提供了一个代码生成工具,它非常好用,可以帮助程序员构造出尽 可能安全和高效的代码。

例如,解决对象到存储的映射时,一个常见的做法是对象隐含一个id属性,映射到数据库表的自增整型 id 主键。 这在大多数的中小型应用场景够用了,而且是最合理的做法。但是如果要面对一个分布(未必很大)的架构,自增 id 不是很好用,特别是我们需要切分数据库,迁移对象的时候,很麻烦。

但是要在一个静态类型的语言中,同时支持多种不同的 PK 类型,也确实不容易。Beedb 和 XORM 都在这方面下了功夫,有很多值得学习的地方。

PGears 中会结合运行时的类型检测,通过反射构造静态类型函数的功能,和一些代码生成的工具,尽可能提供便于 ……便于我自己使用的组合吧……如果我自己都用着不方便就不用跟别人说很好用了……

对象映射和 SQL

从编程语言的角度讲,我们需要将一些对象存储起来,需要的时候再找到它们,加载,处理,再保存。从数据库的 角度,我们有一些数据,需要管理,所以要在编程语言中表现成适于处理的形式。前者的话,我接触过的技术中, 当年 Mono 相关的有一个对象数据库 db4 ,算是走的比较远的。后者对应的是一些比较完整的 ORM 工具会提供的 SQL 表达式对象化功能。

类型映射

Go 的类型系统跟 Java 或 C# 不太一样,后两者有一个逻辑自洽的类型系统,有 Object 和 Type 类型( Type 是 Object 的子类),有高度一致性的 Equal、Compare和Disposable机制。这些 Python 也有, Go 没有。另一方面 Go 的对象机制也不像 C/C++ ,一切都可以追溯到比较原始的字节和指针。Go 的对象体系基于一组互相独立的类型:各种字节宽度的浮点数和有或无符号的整型,字符串、线性定长序列(数组 )和变长序列(Slice),Map,Struct,Func,Interface和interface{}以及它们的指针组成。相当的 不简洁。加上没有代码生成技术(目前的版本甚至也没有足够强的类型推导),这使得我们不太容易实现一个类 似 Java 中的 Hibernate (代码生成能力限制)或者 Python 的 SQLAlchemy(类型的动态程度限制) 的工具。

构造一组接受 interface{} 参数,通过反射获取并分析结构,再填充数据,是个可行的做法。目前看到 的工具主要是通过这样的方式工作的。甚至在数据库访问工具的底层,我们总是只能通过类似的做法处理—— 在数据库和应用层的边界上,我们接受字节流,然后分析内容,根据协议做转型。

但是另一方面,反射并不是一个高效的做法,何况重复的在运行期分析一个已经静态化的结构,很浪费。Go 是一 门静态编译型语言,我们使用它并不是为了把 Python 里要做的事情重复一遍。何况在静态类型语言里重复动态 语言擅长的事情其实很笨拙。例如在Python里我们可以 在运行期定义出新的类型,在 Go 里就没有办法运行时构造新的 struct——如果你有办法,请来教教我, 非常感谢:)。

PGrears 在这方面计划采取一个折衷的方式。一方面我们也应该提供 interface{} 方式的泛化接口,另一方 面提供可以将接口静态化的工具,这方面可以利用 reflect.MakeFunc 。官方文档提供了一个非常 好的范例。在函数生成和绑定的逻辑中,可以尽可能的完成一些能确定的逻辑。这样虽然还是要大量使用反射, 但是比起完全在业务函数调用的时候做分析,也能好很多。一方面可以减少一些参数传递时类型错误造成的panic, 另一方面结构分析逻辑可以在整个进程的生命期只执行一次。而且静态化之后的函数便于将来手工优化, 我认为这种风格值得鼓励,将来无论在文档还是工具上都应该尽量予以支持。

当然,我觉得根本解决方案还是要语言内置一个足够强的代码生成技术,但是目前没有。朋友推荐了一个类似 CodeSmith的 http://clipperhouse.github.io/gen 项目,可以尝试。不过 PGears 会尝试内置一个类似的东西。

在类似 sqlexpress 这一层上,会尽量的提供一些特有功能和语法的支持。无论如何,PostgreSQL 的 PL/SQL 开发,总是会遵循不同于 Golang 的思路,所以完全复现有困难,只能说尽量找一条中间道路。

PostgreSQL 特有类型和功能

目前在 pq 这一层上没有对 Postgres 有特别突出的支持,只实现了一个时间类型。不过沿着的设计思路拓展 下去还是不太难的。接下来会参考同行的实现对pq贡献一些代码。例如JSON类型的支持,是一个值得尝试的方向。

在pg中没有看到异步化的支持,事实上 Python 的 psycopg2 一直有异步能力,应该是在 c 层面带来的。 这是一个值得探索的点。另外 go 本身就有很好的异步模型,可以充分利用。

在 SQL Expressisons 的层面上,支持PG的全文搜索、正则表达式、服务器端函数等功能,是比较自然的方向。

PostgreSQL 的 SQL 编程能力非常的强大,甚至包括递归语法,当然这种东西是否需要支持,取决于我们项目 中是否会用到……

null 和 nil

某种角度上讲,关系型数据库的 null 值可以对应到应用层语言的 nil 。不过在 go 中使用 nil 并不像在 PostgreSQL 中使用 null 那么方便和安全——由于有 interface{} 存在,其实已经比其它很多语言都好了 ——,其实 go 的内置库已经提供了一组 NullXxxx 类型,可以方便的处理带空值的类型。考虑到只是在类型分 析时提供若干分支,我会尽量提供对这一组类型的支持。

路线图

其实路线图什么的真没有……

目前的目标就是尽快做出一个简单够用的工具,我手头好几个网站项目要用到……然后,剩下的,就看心情吧……

——刘鑫

版本

1.0.1(假设刘老师的版本定为1.0)

增加支持sqlite Debug测试,需要下载 https://github.com/mattn/go-sqlite3 组件

注意测试用的dbUrl ,必须用 sqlite://./test.db,你可以理解成sqlite:// 以后再扩展其他数据库也会如此考虑。

package auth

import (
	"你的model目录"
	_"github.com/Dwarfartisan/pgears/exp"
	"testing"
)

func TestServer2(t * testing.T){
	models.Engine.CreateTable("你的model表,注意此处需要填写完成路径")
	models...等单元测试的编码。
}

1.0.2

增加了tag里面对db fieldtype 的支持定义,具体可以参见example里面的例子。

About

PostgresQL Database Access Components

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages