Skip to content

Dwarfartisan/pgears

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages