pgmoon

一个用纯 Lua(MoonScript)编写的 PostgreSQL 客户端库

$ opm get agentzh/pgmoon

pgmoon

[!构建状态](https://travis-ci.org/leafo/pgmoon)

pgmoon 是一个用纯 Lua(MoonScript)编写的 PostgreSQL 客户端库。

pgmoon 最初是为了在 [OpenResty][5] 中使用而设计的,它利用 [cosocket api][4] 来提供异步查询,但它也可以在使用 [LuaSocket][1] 的普通 Lua 环境中使用(并可选地使用 [LuaCrypto][2] 进行 MD5 身份验证和 [LuaSec][6] 进行 SSL 连接)。

它是运行您的查询的完美选择,无论是在 OpenResty 的环境中还是在命令行(例如测试)中,在像 [Lapis][3] 这样的 Web 框架中。

安装

    $ luarocks install pgmoon

示例

    local pgmoon = require("pgmoon")
    local pg = pgmoon.new({
      host = "127.0.0.1",
      port = "5432",
      database = "mydb",
      user = "postgres"
    })
    
    assert(pg:connect())
    
    local res = assert(pg:query("select * from users where username = " ..
      pg:escape_literal("leafo")))

如果您使用的是 OpenResty,您应该在完成对套接字的操作后释放它,以便它可以在将来的请求中被重用。

    pg:keepalive()

参考

require("pgmoon") 返回的表中的函数

new(options={})

创建一个新的 Postgres 对象。不会自动连接。接受一个选项表。该表可以包含以下键:

  • "host": 要连接的主机(默认值:"127.0.0.1"

  • "port": 要连接的端口(默认值:"5432"

  • "user": 用于身份验证的数据库用户名(默认值:"postgres"

  • "database": 要连接的数据库名称 必需

  • "password": 用于身份验证的密码,可选,具体取决于服务器配置

  • "ssl": 启用 ssl

  • "ssl_verify": 验证服务器证书

  • "ssl_required": 如果服务器不支持 SSL 连接,则中止连接

new 返回的 Postgres 对象上的方法

success, err = postgres:connect()

使用 new 调用中指定的凭据连接到 Postgres 服务器。成功时返回 true,失败时返回 nil 和错误消息。

success, err = postgres:disconnect()

如果套接字已打开,则关闭到服务器的套接字。在此之后,不应在该对象上调用其他方法,除了再次调用 connect。

success, err = postgres:keepalive(...)

通过 setkeepalive 方法将套接字释放到 OpenResty 套接字池。此处传递的任何参数也会传递给 setkeepalive

result, num_queries = postgres:query(query_string)

result, err, partial, num_queries = postgres:query(query_string)

向服务器发送查询。失败时返回 nil 和错误消息。

成功时返回一个结果,具体取决于发送的查询类型。

SELECT 查询、带有 returningINSERT 或任何其他返回结果集的查询将返回结果的数组表。每个结果都是一个哈希表,其中键是列的名称,值是结果集中该行的结果。

    local res = pg:query("select id, name from users")

可能返回

    {
      {
        id = 123,
        name = "Leafo"
      },
      {
        id = 234,
        name = "Lee"
      }
    }

任何影响行的查询,如 UPDATEDELETEINSERT,都会返回一个表结果,其中 affected_rows 字段设置为受影响的行数。

    local res = pg:query("delete from users")

可能返回

    {
      affected_rows = 2
    }

任何没有结果集或更新行的查询都会返回 true

此方法还支持通过用 ; 分隔来一次发送多个查询。执行的查询数量作为第二个返回值在结果对象之后返回。当执行多个查询时,结果对象会略有变化。它变成一个数组表,包含所有单个结果。

    local res, num_queries = pg:query([[
      select id, name from users;
      select id, title from posts
    ]])

可能返回

    num_queries = 2
    
    res = {
      {
        {
          id = 123,
          name = "Leafo"
        },
        {
          id = 234,
          name = "Lee"
        }
      },
      {
        {
          id = 546,
          title = "My first post"
        }
      }
    }

类似地,对于返回受影响行或只是 true 的查询,当有多个查询时,它们将被包装在额外的数组表中。您也可以根据需要混合使用不同的查询类型。

因为 Postgres 一次执行一个查询,所以前面的查询可能成功,而后面的查询可能失败。如果多个查询发生错误,则错误消息之后将返回部分结果和部分执行的查询数量。

escaped = postgres:escape_literal(val)

转义 Lua 值以用作 Postgres 值,插入到查询字符串中。当将用户提供的数据发送到查询中时,您应该使用此方法来防止 SQL 注入攻击。

escaped = postgres:escape_identifier(val)

转义 Lua 值以用作 Postgres 标识符。这包括表名或列名。这并不包括常规值,您应该使用 escape_literal 来处理常规值。当名称与内置语言关键字冲突时,需要进行标识符转义。

str = tostring(postgres)

返回 Postgres 对象当前状态的字符串表示形式。

SSL 连接

pgmoon 可以建立与 Postgres 服务器的 SSL 连接。如果服务器不支持 SSL,它也可以拒绝连接。正如 pgmoon 在 OpenResty 之外的使用依赖于 LuaSocket 一样,它在这些环境中依赖于 LuaSec 进行 SSL 连接。

    local pgmoon = require("pgmoon")
    local pg = pgmoon.new({
      host = "127.0.0.1",
      ssl = true, -- enable SSL
      ssl_verify = true, -- verify server certificate
      ssl_required = true, -- abort if the server does not support SSL connections
      cafile = "...", -- certificate authority (LuaSec only)
      cert = "...", -- client certificate (LuaSec only)
      key = "...", -- client key (LuaSec only)
    })
    
    assert(pg:connect())

在 OpenResty 中,如果要验证服务器证书,请确保配置 [lua_ssl_trusted_certificate][7] 指令,因为 LuaSec 独有的选项在这种情况下变得无关紧要。

身份验证类型

Postgres 有几种身份验证类型。pgmoon 目前支持 Trust 和 MD5 身份验证。

类型转换

Postgres 内置了一组非常丰富的类型。pgmoon 会尽力将任何 Postgres 类型转换为适当的 Lua 类型。

所有整数、浮点数和数字类型都转换为 Lua 的 number 类型。布尔类型转换为 Lua 布尔值。JSON 类型使用 Lua CJSON 解码为 Lua 表。Lua 表可以像下面描述的那样编码为 JSON。

任何数组类型都会自动转换为 Lua 数组表。如果您需要将 Lua 中的数组编码为 Postgres 的数组语法,可以使用 pgmoon.arrays 模块。见下文。

任何其他类型都作为 Lua 字符串返回。

处理数组

数组在从查询中返回时会自动解码。数字、字符串和布尔类型会根据情况自动加载。嵌套数组也受支持。

使用 encode_array 将 Lua 表编码为查询的数组语法

    local pgmoon = require("pgmoon")
    local pg = pgmoon.new(auth)
    pg:connect()
    
    local encode_array = require("pgmoon.arrays").encode_array
    local my_array = {1,2,3,4,5}
    pg:query("insert into some_table (some_arr_col) values(" .. encode_array(my_array) .. ")")

处理 JSON

jsonjsonb 类型在从查询中返回时会自动解码。

使用 encode_json 将 Lua 表编码为查询的 JSON 语法

    local pgmoon = require("pgmoon")
    local pg = pgmoon.new(auth)
    pg:connect()
    
    local encode_json = require("pgmoon.json").encode_json
    local my_tbl = {hello = "world"}
    pg:query("insert into some_table (some_json_col) values(" .. encode_json(my_tbl) .. ")")

处理 hstore

因为 hstore 是一个扩展类型,所以需要一个查询来找出类型 ID,然后 pgmoon 才能自动解码它。在连接后,在连接对象上调用 setup_hstore 方法来设置它。

    local pgmoon = require("pgmoon")
    local pg = pgmoon.new(auth)
    pg:connect()
    pg:setup_hstore()

使用 encode_hstore 将 Lua 表编码为更新和插入时的 hstore 语法

    local encode_hstore = require("pgmoon.hstore").encode_hstore
    local tbl = {foo = "bar"}
    pg:query("insert into some_table (hstore_col) values(" .. encode_hstore(tbl) .. ")")

您可以使用 decode_hstore 函数手动从字符串中解码 hstore 值。这只有在您没有调用 setup_hstore 时才需要。

    local decode_hstore = require("pgmoon.hstore").decode_hstore
    local res = pg:query("select * from some_table")
    local hstore_tbl = decode_hstore(res[1].hstore_col)

转换 NULL

默认情况下,Postgres 中的 NULL 转换为 nil,这意味着它们在结果表中不可见。如果您想将 NULL 转换为某个可见值,请在 Postgres 对象上将 convert_null 设置为 true

    local pgmoon = require("pgmoon")
    local pg = pgmoon.new(auth)
    pg:connect()
    
    pg.convert_null = true
    local res = pg:query("select NULL the_null")
    
    assert(pg.NULL == res[1].the_null)

如上所示,NULL 值设置为 pg.NULL。您可以更改此值,使 pgmoon 使用其他东西作为 NULL。例如,如果您使用的是 OpenResty,您可能希望重用 ngx.null

联系

作者:Leaf Corcoran (leafo) (@moonscript) 电子邮件:leafot@gmail.com 主页:<http://leafo.net>

变更日志

  • 1.6.0 — 2016-07-21 — 添加对 json 和 jsonb 数组解码的支持

  • 1.5.0 — 2016-07-12 — 添加 SSL 支持 (@thibaultCha),添加 UUID 数组类型 (@edan),添加对通知的支持 (@starius)

  • 1.4.0 — 2016-02-18 — 添加对解码 jsonb 的支持,添加 json 序列化器 (@thibaultCha)

  • 1.3.0 — 2016-02-11 — 修复解析看起来像数字的字符串失败的错误,添加在 init 上下文中在 ngx 中使用的支持 (@thibaultCha),添加明文密码身份验证,修复 md5 身份验证的警告

  • 1.2.0 — 2015-07-10 — 添加对 PostgreSQL 数组的支持

  • 1.1.1 — 2014-08-12 — 修复 md5 身份验证的错误

  • 1.1.0 — 2014-05-21 — 添加对一次调用中使用多个查询的支持

  • 1.0.0 — 2014-05-19 — 初始版本

许可证 (MIT)

版权所有 (C) 2016 by Leaf Corcoran

特此授予任何人免费获得本软件副本和相关文档文件(“软件”)的副本,不受限制地处理软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件的权利,以及允许获得软件的人员这样做,但须符合以下条件:

以上版权声明和本许可声明应包含在软件的所有副本或重要部分中。

软件按“原样”提供,不提供任何形式的明示或暗示保证,包括但不限于适销性、特定用途的适用性和非侵权的保证。在任何情况下,作者或版权持有人均不对因使用或其他与软件相关的任何索赔、损害或其他责任承担任何责任,无论是基于合同、侵权或其他方式造成的,即使已告知此类损害的可能性。

[1]: http://w3.impa.br/~diego/software/luasocket/ [2]: http://mkottman.github.io/luacrypto/ [3]: http://leafo.net/lapis [4]: http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp [5]: https://openresty.org.cn/ [6]: https://github.com/brunoos/luasec [7]: https://github.com/openresty/lua-nginx-module#lua_ssl_trusted_certificate

作者

Leaf Corcoran (leafo)

许可证

mit

版本