{"id":13636392,"url":"https://github.com/leafo/pgmoon","last_synced_at":"2025-04-04T15:11:37.372Z","repository":{"id":16610375,"uuid":"19365171","full_name":"leafo/pgmoon","owner":"leafo","description":"A pure Lua Postgres driver for use in OpenResty \u0026 more","archived":false,"fork":false,"pushed_at":"2023-09-06T08:46:06.000Z","size":332,"stargazers_count":394,"open_issues_count":19,"forks_count":93,"subscribers_count":15,"default_branch":"master","last_synced_at":"2024-10-30T06:58:39.295Z","etag":null,"topics":["cqueues","lua","luasocket","moonscript","openresty","postgres","postgresql"],"latest_commit_sha":null,"homepage":"","language":"MoonScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leafo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-05-02T03:40:52.000Z","updated_at":"2024-10-29T03:00:40.000Z","dependencies_parsed_at":"2024-01-08T20:19:20.509Z","dependency_job_id":null,"html_url":"https://github.com/leafo/pgmoon","commit_stats":{"total_commits":257,"total_committers":20,"mean_commits":12.85,"dds":"0.15953307392996108","last_synced_commit":"7b7ef2a3f17d32881c61f0fb258d2ee01718942c"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Fpgmoon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Fpgmoon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Fpgmoon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Fpgmoon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leafo","download_url":"https://codeload.github.com/leafo/pgmoon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247198469,"owners_count":20900081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cqueues","lua","luasocket","moonscript","openresty","postgres","postgresql"],"created_at":"2024-08-02T00:01:00.767Z","updated_at":"2025-04-04T15:11:37.352Z","avatar_url":"https://github.com/leafo.png","language":"MoonScript","readme":"# pgmoon\n\n![test](https://github.com/leafo/pgmoon/workflows/test/badge.svg)\n\n\u003e **Note:** Have you updated from an older version of OpenResty? You must update to\n\u003e pgmoon 1.12 or above, due to a change in Lua pattern compatibility to avoid incorrect \n\u003e results from queries that return affected rows.\n\n**pgmoon** is a PostgreSQL client library written in pure Lua (MoonScript).\n\n**pgmoon** was originally designed for use in [OpenResty][] to take advantage\nof the [cosocket\napi](https://github.com/openresty/lua-nginx-module#ngxsockettcp) to provide\nasynchronous queries but it also works in the regular any Lua environment where\n[LuaSocket][] or [cqueues][] is available.\n\nIt's a perfect candidate for running your queries both inside OpenResty's\nenvironment and on the command line (eg. tests) in web frameworks like [Lapis][].\n\n## Install\n\n```bash\n$ luarocks install pgmoon\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eUsing \u003ca href=\"https://opm.openresty.org/\"\u003eOpenResty's OPM\u003c/a\u003e\u003c/summary\u003e\n\n```bash\n$ opm get leafo/pgmoon\n```\n\n\u003c/details\u003e\n\n\n### Dependencies\n\npgmoon supports a wide range of environments and libraries, so it may be\nnecessary to install additional dependencies depending on how you intend to\ncommunicate with the database:\n\n\u003e **Tip:** If you're using OpenResty then no additional dependencies are needed\n\u003e (generally, a crypto library may be necessary for some authentication\n\u003e methods)\n\nA socket implementation **is required** to use pgmoon, depending on the\nenvironment you can chose one:\n\n* [OpenResty][] \u0026mdash; The built in socket is used, no additional dependencies necessary\n* [LuaSocket][] \u0026mdash; `luarocks install luasocket`\n* [cqueues][] \u0026mdash; `luarocks install cqueues`\n\nIf you're on PUC Lua 5.1 or 5.2 then you will need a bit libray (not needed for LuaJIT):\n\n```bash\n$ luarocks install luabitop\n```\n\nIf you want to use JSON types you will need lua-cjson\n\n```bash\n$ luarocks install lua-cjson\n```\n\nSSL connections may require an additional dependency:\n\n* OpenResty \u0026mdash; `luarocks install lua-resty-openssl`\n* LuaSocket \u0026mdash; `luarocks install luasec`\n* cqueues \u0026mdash; `luarocks install luaossl`\n\nPassword authentication may require a crypto library, [luaossl][].\n\n```bash\n$ luarocks install luaossl\n```\n\u003e **Note:** [LuaCrypto][] can be used as a fallback, but the library is abandoned and not recommended for use\n\n\u003e **Note:** Use within [OpenResty][] will prioritize built  in functions if possible\n\nParsing complex types like Arrays and HStore requires `lpeg` to be installed.\n\n## Example\n\n```lua\nlocal pgmoon = require(\"pgmoon\")\nlocal pg = pgmoon.new({\n  host = \"127.0.0.1\",\n  port = \"5432\",\n  database = \"mydb\",\n  user = \"postgres\"\n})\n\nassert(pg:connect())\n\nlocal res = assert(pg:query(\"select * from users where status = 'active' limit 20\")\n\nassert(pg:query(\"update users set name = $1 where id = $2\", \"leafo\", 99))\n\n```\n\nIf you are using OpenResty you can relinquish the socket to the connection pool\nafter you are done with it so it can be reused in future requests:\n\n```lua\npg:keepalive()\n```\n\n## Considerations\n\nPostgreSQL allows for results to use the same field name multiple times.\nBecause results are extracted into Lua tables, repeated fields will be\noverwritten and previous values will be unavailable:\n\n```lua\npg:query(\"select 1 as dog, 'hello' as dog\") --\u003e { { dog = \"hello\" } }\n```\n\nThere is currently no way around this limitation. If this is something you need\nthen open an [issue](https://github.com/leafo/pgmoon/issues).\n\n\n## Reference\n\nFunctions in table returned by `require(\"pgmoon\")`:\n\n### `new(options={})`\n\nCreates a new `Postgres` object from a configuration object. All fields are\noptional unless otherwise stated. The newly created object will not\nautomatically connect, you must call `conect` after creating the object.\n\nAvailable options:\n\n* `\"database\"`: the database name to connect to **required**\n* `\"host\"`: the host to connect to (default: `\"127.0.0.1\"`)\n* `\"port\"`: the port to connect to (default: `\"5432\"`)\n* `\"user\"`: the database username to authenticate (default: `\"postgres\"`)\n* `\"password\"`: password for authentication, may be required depending on server configuration\n* `\"ssl\"`: enable ssl (default: `false`)\n* `\"ssl_verify\"`: verify server certificate (default: `nil`)\n* `\"ssl_required\"`: abort the connection if the server does not support SSL connections (default: `nil`)\n* `\"socket_type\"`: the type of socket to use, one of: `\"nginx\"`, `\"luasocket\"`, `cqueues` (default: `\"nginx\"` if in nginx, `\"luasocket\"` otherwise)\n* `\"application_name\"`: set the name of the connection as displayed in `pg_stat_activity`. (default: `\"pgmoon\"`)\n* `\"pool\"`: (OpenResty only) name of pool to use when using OpenResty cosocket (default: `\"#{host}:#{port}:#{database}\"`)\n* `\"pool_size\"`: (OpenResty only) Passed directly to OpenResty cosocket connect function, [see docs](https://github.com/openresty/lua-nginx-module#tcpsockconnect)\n* `\"backlog\"`: (OpenResty only) Passed directly to OpenResty cosocket connect function, [see docs](https://github.com/openresty/lua-nginx-module#tcpsockconnect)\n* `\"cqueues_openssl_context\"`: Manually created `opensssl.ssl.context` to use when created cqueues SSL connections\n* `\"luasec_opts\"`: Manually created options object to use when using LuaSec SSL connections\n\nMethods on the `Postgres` object returned by `new`:\n\n### `postgres:connect()`\n\n```lua\nlocal success, err = postgres:connect()\n```\n\nConnects to the Postgres server using the credentials specified in the call to\n`new`. On success returns `true`, on failure returns `nil` and the error\nmessage.\n\n### `postgres:settimeout(time)`\n\n```lua\npostgres:settimeout(5000) -- 5 second timeout\n```\n\nSets the timeout value (in milliseconds) for all subsequent socket operations\n(connect, write, receive). This function does not have any return values.\n\nThe default timeout depends on the underslying socket implementation but\ngenerally corresponds to no timeout.\n\n### `postgres:disconnect()`\n\n```lua\nlocal success, err = postgres:disconnect()\n```\n\nCloses the socket. Returns `nil` if the socket couldn't be closed. On most\nsocket types, `connect` can be called again to reestaablish a connection with\nthe same postgres object instance.\n\n### `postgres:keepalive(...)`\n\n```lua\npostgres:keepalive()\n```\n\nRelinquishes socket to OpenResty socket pool via the `setkeepalive` method. Any\narguments passed here are also passed to `setkeepalive`. After calling this\nmethod, the socket is no longer available for queries and should be considered\ndisconnected.\n\n\u003e Note: This method only works within OpenResty using the nginx cosocket API\n\n### `postgres:query(query_string, ...)`\n\n```lua\n-- return values for successful query\nlocal result, err, num_queries = postgres:query(\"select name from users limit 2\")\n\n-- return value for failure (status is nil)\nlocal status, err, partial_result, num_queries = postgres:query(\"select created_at from tags; select throw_error() from users\")\n```\n\nSends a query (or multiple queries) to the server. On failure the first return\nvalue is `nil`, followed by a string describing the error. Since a single call\nto `postgres:query` can contain multiple queries, the results of any queries that\nsucceeded before the error occurred are returned after the error message.\n(Note: queries are atomic, they either succeed or fail. The partial result will\nonly contain succeed queries, not partially data from the failed query)\n\n\u003cdetails\u003e\n\u003csummary\u003eAdditional return values: notifications and notices\u003c/summary\u003e\n\n---\n\nIn addition to the return values above, pgmoon will also return two additional\nvalues if the query generates them, notifications an notices.\n\n```lua\nlocal result, err, num_queries, notifications, notices  = postgres:query(\"drop table if exists some_table\")\n```\nIn this example, if the table `some_table` does not exist, then  `notices` will\nbe an array containing a message that the table didn't exist.\n\n---\n\n\u003c/details\u003e\n\nThe query function has two modes of operation which correspond to the two\nprotocols the Postgres server provides for sending queries to the database\nserver:\n\n* **Simple protocol**: you only pass in a single argument, the query string\n* **Extended protocol**: you pass in a query with parameter placeholders (`$1`, `$2`, etc.) and then pass in additional arguments which will be used as values for the placeholders\n\nSee [Extended and simple query protocol](#extended-and-simple-query-protocols)\nfor more information about the differences and trade-offs.\n\nOn success, the result returned depends on the kind of query sent:\n\n`SELECT` queries, `INSERT` with `returning`, or anything else that returns a\nresult set will return an array table of results. Each result is a hash table\nwhere the key is the name of the column and the value is the result for that\nrow of the result.\n\n```lua\nlocal res = pg:query(\"select id, name from users\")\n```\n\nMight return:\n\n```lua\n{\n  {\n    id = 123,\n    name = \"Leafo\"\n  },\n  {\n    id = 234,\n    name = \"Lee\"\n  }\n}\n```\n\nAny queries that affect rows like `UPDATE`, `DELETE`, or `INSERT` return a\ntable result with the `affected_rows` field set to the number of rows affected.\n\n\n```lua\nlocal res = pg:query(\"delete from users\")\n```\n\nMight return:\n\n```lua\n{\n  affected_rows = 2\n}\n```\n\nAny queries with no result set or updated rows will return `true`.\n\n\nWhen using the *simple protocol* (calling the function with a single string),\nyou can send multiple queries at once by separating them with a `;`. The number\nof queries executed is returned as a second return value after the result\nobject. When more than one query is executed then the result object changes\nslightly. It becomes a array table holding all the individual results:\n\n```lua\nlocal res, num_queries = pg:query([[\n  select id, name from users;\n  select id, title from posts\n]])\n```\n\nMight return:\n\n```lua\nnum_queries = 2\n\nres = {\n  {\n    {\n      id = 123,\n      name = \"Leafo\"\n    },\n    {\n      id = 234,\n      name = \"Lee\"\n    }\n  },\n  {\n    {\n      id = 546,\n      title = \"My first post\"\n    }\n  }\n}\n```\n\nSimilarly for queries that return affected rows or just `true`, they will be\nwrapped up in an addition array table when there are multiple of them. You can\nalso mix the different query types as you see fit.\n\n### `postgres:escape_literal(val)`\n\n```lua\nlocal sql_fragment = postgres:escape_literal(val)\n\nlocal res = postgres:query(\"select created_at from users where id = \" .. sql_fragment)\n```\n\nEscapes a Lua value int a valid SQL fragment that can be safely concatenated\ninto a query string. **Never** concatenate a variable into query without\nescaping it in some way, or you may open yourself up to [SQL injection\nattacks](https://en.wikipedia.org/wiki/SQL_injection).\n\nThis function is aware of the following Lua value types:\n\n* `type(val) == \"number\"` \u0026#8594; `escape_literal(5.5) --\u003e 5.5`\n* `type(val) == \"string\"` \u0026#8594; `escape_literal(\"your's\") --\u003e 'your''s'`\n* `type(val) == \"boolean\"` \u0026#8594; `escape_literal(true) --\u003e TRUE`\n* `val == pgmoon.NULL` \u0026#8594; `escape_literal(pgmoon.NULL) --\u003e NULL`\n\nAny other type will throw a hard `error`, to ensure that you provide a value\nthat is safe for escaping.\n\n### `postgres:escape_identifier(val)`\n\n```lua\nlocal sql_fragment = postgres:escape_identifier(some_table_name)`\n\nlocal res = postgres:query(\"select * from \" .. sql_fragment .. \" limit 20)\n```\n\nEscapes a Lua value for use as a Postgres identifier. This includes things like\ntable or column names. This does not include regular values, you should use\n`escape_literal` for that. Identifier escaping is required when names collide\nwith built in language keywords.\n\nThe argument, `val`, must be a string.\n\n### `tostring(postgres)`\n\n```lua\nprint(tostring(postgres)) --\u003e \"\u003cPostgres socket: 0xffffff\u003e\"\n```\n\nReturns string representation of current state of `Postgres` object.\n\n## Extended and simple query protocols\n\npgmoon will issue your query to the database server using either the simple or\nextended protocol depending if you provide parameters and parameter\nplaceholders in your query. The simple protocol is used for when your query is\njust a string, and the extended protocol is used when you provide addition\nparameters as arguments to the `query` method.\n\nThe protocols have some trade-offs and differences:\n\n### Extended protocol\n\n```lua\nlocal res, err = postgres:query(\"select name from users where id = $1 and status = $2\", 12, \"ready\")\n```\n\n* **Advantage**: Parameters can be included in query without risk of SQL injection attacks, no need to escape values and interpolate strings\n* **Advantage**: Supports the `pgmoon_serialize` method to allow for custom types to be automatically serialized into parameters for the query\n* **Disadvantage**: Only a single query can be sent a time\n* **Disadvantage**: Substantially more overhead per query. A no-op query may be 50% to 100% slower. (note that this overhead may be negligible depending on the runtime of the query itself)\n* **Disadvantage**: Some kinds of query syntax are not compatible with parameters (eg. `where id in (...)`, dynamic expressions), so you may still need to use string interpolation and assume the associated risks\n\n### Simple protocol\n\n```lua\nlocal res, err = postgres:query(\"select name from users where id = \" .. postgres:escape_literal(12) ..\" and status = \" .. postgres:escape_literal(\"ready\"))\n```\n\n* **Advantage**: Higher performance. Low overhead per query means more queries can be sent per second, even when manually escaping and interpolating parameters\n* **Advantage**: Multiple queries can be sent in a single request (separated by `;`)\n* **Disadvantage**: Any parameters to the query must be manually escaped and interpolated into the query string. This can be error prone and introduce SQL injection attacks if not done correctly\n\n\u003e Note: The extended protocol also supports binary encoding of parameter values\n\u003e \u0026 results, but since Lua treats binary as strings, it's generally going to be\n\u003e faster to just consume the string values from Postgres rather than using the\n\u003e binary protocol which will require binary to string conversion within Lua.\n\n## SSL connections\n\npgmoon can establish an SSL connection to a Postgres server. It can also refuse\nto connect to it if the server does not support SSL. Just as pgmoon depends on\nLuaSocket for usage outside of OpenResty, it depends on luaossl/LuaSec for SSL\nconnections in such contexts.\n\n```lua\nlocal pgmoon = require(\"pgmoon\")\nlocal pg = pgmoon.new({\n  host = \"127.0.0.1\",\n  ssl = true, -- enable SSL\n  ssl_verify = true, -- verify server certificate\n  ssl_required = true, -- abort if the server does not support SSL connections\n  ssl_version = \"tlsv1_2\", -- e.g., defaults to highest available, no less than TLS v1.1\n  cafile = \"...\", -- certificate authority (LuaSec only)\n  cert = \"...\", -- client certificate\n  key = \"...\", -- client key\n})\n\nassert(pg:connect())\n```\n\n\u003e **Note:** In Postgres 12 and above, the minium SSL version accepted by client\n\u003e connections is 1.2. When using LuaSocket + LuaSec to connect to an SSL\n\u003e server, if you don't specify an `ssl_version` then `tlsv1_2` is used.\n\nIn OpenResty, make sure to configure the\n[lua_ssl_trusted_certificate](https://github.com/openresty/lua-nginx-module#lua_ssl_trusted_certificate)\ndirective if you wish to verify the server certificate.\n\n## Authentication types\n\nPostgres has a handful of authentication types. pgmoon currently supports\ntrust, peer and password authentication with scram-sha-256-auth or md5.\n\n## Type conversion\n\nPostgres has a very rich set of types built in. pgmoon will do its best to\nconvert any Postgres types into the appropriate Lua type.\n\nAll integer, floating point, and numeric types are converted into Lua's number\ntype. The boolean type is converted into a Lua boolean. The JSON type is\ndecoded into a Lua table using Lua CJSON. Lua tables can be encoded to JSON as\ndescribed below.\n\nAny array types are automatically converted to Lua array tables. If you need to\nencode an array in Lua to Postgres' array syntax you can use the\n`pgmoon.arrays` module. See below.\n\nAny other types are returned as Lua strings.\n\n## Handling arrays\n\nArrays are automatically deserialized into a Lua object when they are returned\nfrom a query. Numeric, string, and boolean types are automatically loaded\naccordingly. Nested arrays are also supported.\n\nUse `encode_array` to encode a Lua table to array syntax for a query:\n\n```lua\nlocal pgmoon = require(\"pgmoon\")\nlocal pg = pgmoon.new(auth)\npg:connect()\n\nlocal encode_array = require(\"pgmoon.arrays\").encode_array\nlocal my_array = {1,2,3,4,5}\npg:query(\"insert into some_table (some_arr_col) values(\" .. encode_array(my_array) .. \")\")\n```\n\nArrays that are returned from queries have their metatable configured for the\n`PostgresArray` type (defined in `require(\"pgmoon.arrays\")`).\n\n\n### Extended protocol\n\nWhen using the extended query protocol (query with parameters), an array object\ncreated with `PostgresArray` will automatically be serialized when passed as a\nparameter.\n\n```lua\nlocal PostgresArray = require(\"pgmoon.arrays\").PostgresArray\n\npostgres:query(\"update user set tags = $1 where id = 44\", PostgresArray({1,2,4}))\n```\n\nKeep in mind that calling `PostgresArray` mutate the argument by setting its\nmetatable. Make a copy first if you don't want the original object to be\nmutated.\n\nAdditionally, array types must contain values of only the same type. No\nrun-time checking is performed on the object you pass. The type OID is\ndetermined from the first entry of the array.\n\n### Empty Arrays\n\nWhen trying to encode an empty array an error will be thrown. Postgres requires\na type when using an array. When there are values in the array Postgres can\ninfer the type, but with no values in the array no type can be inferred. This\nis illustrated in the erorr provided by Postgres:\n\n\n```\npostgres=# select ARRAY[];\nERROR:  cannot determine type of empty array\nLINE 1: select ARRAY[];\n               ^\nHINT:  Explicitly cast to the desired type, for example ARRAY[]::integer[].\n```\n\nYou can work around this error by always including a typecast with any value\nyou use, to allow you to pass in an empty array and continue to work with an\narray of values assuming the types match.\n\n```lua\nlocal empty_tags = {}\npg:query(\"update posts set tags = \" .. encode_array(empty_tags) .. \"::text[]\")\n```\n\n## Handling JSON\n\n`json` and `jsonb` values are automatically decoded as Lua tables in a query\nresult (using the `cjson` library if available).\n\nTo send JSON in a query you must first convert it into a string literal, then\ninterpolate it into your query. Ensure that you treat it like any other\nparamter, and call `escape_literal` on the string to make it suitable to be\nsafely parsed as a value to PostgreSQL.\n\n```lua\nlocal pgmoon = require(\"pgmoon\")\nlocal pg = pgmoon.new(auth)\nassert(pg:connect())\n\nlocal my_tbl = { hello = \"world\" }\n\nlocal json = require \"cjson\"\n\npg:query(\"update my_table set data = \" .. db.escape_literal(json.encode(my_tbl)) .. \" where id = 124\"\n```\n\n## Handling hstore\n\nBecause `hstore` is an extension type, a query is reuired to find out the type\nid before pgmoon can automatically decode it. Call the `setup_hstore` method on\nyour connection object after connecting to set it up.\n\n```lua\nlocal pgmoon = require(\"pgmoon\")\nlocal pg = pgmoon.new(auth)\npg:connect()\npg:setup_hstore()\n```\n\nUse `encode_hstore` to encode a Lua table into hstore syntax suitable for\ninterpolating into a query.\n\n\u003e Note: The result of `encode_hstore` is a valid Postgres SQL fragment, it is\n\u003e not necessary to call escape_literal on it. It can safely be inserted\n\u003e directly into the query\n\n```lua\nlocal encode_hstore = require(\"pgmoon.hstore\").encode_hstore\nlocal tbl = {foo = \"bar\"}\npg:query(\"insert into some_table (hstore_col) values(\" .. encode_hstore(tbl) .. \")\")\n```\n\nYou can manually decode a hstore value from string using the `decode_hstore`\nfunction. This is only required if you didn't call `setup_hstore`.\n\n```lua\nlocal decode_hstore = require(\"pgmoon.hstore\").decode_hstore\nlocal res = pg:query(\"select * from some_table\")\nlocal hstore_tbl = decode_hstore(res[1].hstore_col)\n```\n\n## Custom type deserializer\n\nPostgreSQL has a rich set of types. When reading a query's results pgmoon must\nattempt to interpret the types from postgres and map them to something usable\nin Lua. By default implementations are included for primitives like numbers,\nbooleans, strings, and JSON.\n\nYou can provie you own type deserializer if you want to add custom behavior for\ncertain types of values returned by PostgreSQL.\n\nYou must have some knowledge of types and type OIDs. Every type in PostgreSQL\nis stored in the `pg_type` catalog table. Each type has an OID (stored as a 32\nbit positive integer) to uniquely identify it. The core types provided by\nPostgres have fixed type OIDs (for example, boolean is always 16), but\nthird-party types may be added without fixed OIDs.\n\nAlso note that any composite versions of existing types have their own OID, for\nexample, while a single boolean value has type OID 16, an array of boolean\nvalues has type OID 1000. Arrays are homogeneous and must contain the same type\nfor every value.\n\nAdding support for a new type in pgmoon can be done using the\n`set_type_deserializer(oid, type_name, [deserializer])` method:\n\n```lua\nlocal pgmoon = require(\"pgmoon\")\nlocal pg = pgmoon.new(config)\n\n-- in this example we create a new deserializer called bignumber and provide\n-- the function to deserialize (type OID 20 is an 8 byte integer)\npg:set_type_deserializer(20, \"bignumber\", function(val)\n    return \"HUGENUMBER:\" .. val\nend)\n\n-- in this example we point another OID to the \"bignumber\" deserializer we\n-- provided above (type OID 701 is a 8 byte floating point number)\npg:set_type_deserializer(701, \"bignumber\")\n```\n\nThe arguments are as follows:\n\n* `oid` The OID from `pg_type` that will be handled\n* `name` The local name of the type. This is a name that points to an existing deserializer or will be used to register a new one if the `deserializer` argument is \n* `deserializer` A function that takes the raw string value from Postgres and converts it into something more useful (optional). Any existing deserializer function with the same name will be overwritten\n\n## Custom type serializer\n\nWhen using the query method with params, (aka the extended query protocol), and\nvalues passed into parameters must be serialized into a string version of that\nvalue and a type OID.\n\npgmoon provides implementations for Lua's basic types: string, boolean,\nnumbers, and `postgres.NULL` for the `NULL` value.\n\nIf you want to support custom types, like JSON, then you will need to provide\nyour own serializer.\n\n\u003e Serializing vs escaping: pgmoon has two methods for preparing data to be sent\n\u003e in a query. *Escaping* is used when you want to turn some value into a SQL\n\u003e fragment that can be safely concatenated into a query. This is done with\n\u003e `postgres:escape_literal()` and is suitable for use with the simple query\n\u003e protocol. *Serializing*, on the other hand, is used to convert a value into a\n\u003e string representation that can be parsed by Postgres as a value when using\n\u003e the extended query protocol. As an example, an *escaped* string would be\n\u003e `'hello'` (notice the quotes, this is a fragment of valid SQL syntax, whereas\n\u003e a serialized string would be just the string: `hello` (and typically paired\n\u003e with a type OID, typically `25` for text). Serializing is the oposite of\n\u003e deserializing, which is described above.\n\n\n\u003e **Note:** Serializing is **NOT** the same as escaping. You can not take a\n\u003e serialized value and concatenate it directly into your query. You may,\n\u003e however, take a serialized value and escape it as a string, then attempt to\n\u003e cast it to the appropriate type within your query.\n\n\nTo provide your own serializer for an object, you can add a method on the\nmetatable called `pgmoon_serialize`. This method takes two arguments, the value\nto be serialized and the current instance of `Postgres` that is doing the\nserialization. The method should return two values: the type OID as an integer,\nand the string representation of that value.\n\n\u003e Note: The type OID 0 can be used for \"unknown\", and Postgres will try to\n\u003e infer the type of the value based on the context. If possible you should\n\u003e always try to provide a specific type OID.\n\n```lua\n-- this metatable will enable an object to be serialized as json for use as a\n-- parameter in postgres:query()\nlocal json_mt = {\n  pgmoon_serialize = function(v)\n    local cjson = require(\"cjson\")\n    return 114, cjson.encode(v) -- 114 is oid from pg_type catalog\n  end\n}\n\nlocal data = {\n  age = 200,\n  color = \"blue\",\n  tags = {\"one\", \"two\"}\n}\n\npostgres:query(\"update user set data = $1 where id = 233\", setmetatable(data, json_mt))\n```\n\nThe `pgmoon_serialize` method can also return `nil` and an error message to\nabort serialization. This will block the query from running at all, and the\nerror will be returned from the `postgres:query()` method.\n\n\u003e Note: Postgres supports a binary representation for values when using the\n\u003e extended query protocol, but at this time pgmoon does not support it.\n\n\n## Converting `NULL`s\n\nBy default `NULL`s in Postgres are converted to `nil`, meaning they aren't\nvisible in the resulting tables. If you want to convert `NULL`s to some visible\nvalue set `convert_null` to `true` on the `Postgres` object and the\n`postgres.NULL` object will be used to represent NULL.\n\n```lua\nlocal pgmoon = require(\"pgmoon\")\nlocal config = {\n  database = \"my_database\",\n  convert_null = true\n}\n\nlocal postgres = pgmoon.new(config)\nassert(postgres:connect())\n\nlocal res = postgres:query(\"select NULL the_null\")\nassert(postgres.NULL == res[1].the_null)\n```\n\nAs shown above, the `NULL` value is set to `postgres.NULL`. It's possible to change\nthis value to make pgmoon use something else as `NULL`. For example if you're\nusing OpenResty you might want to reuse `ngx.null`.\n\nAlso note that you can use `postgres.NULL` as an extended query parameter or\ninside `escape_literal` to generate the value for `NULL`.\n\n# Contact\n\nAuthor: Leaf Corcoran (leafo) ([@moonscript](http://twitter.com/moonscript))\nEmail: leafot@gmail.com\nHomepage: \u003chttp://leafo.net\u003e\n\n\n# Changelog\n\nNote: Future changenotes will be published on GitHub releases page: https://github.com/leafo/pgmoon/releases\n\n* 1.15.0 — 2022-6-3 - Extended query protocol\n* 1.14.0 — 2022-2-17 - OpenResty crypto functions used, better empty array support, \n* 1.13.0 — 2021-10-13 - Add support for scram_sha_256_auth (@murillopaula), 'backlog' and 'pool_size' options while using ngx.socket (@xiaocang), update LuaSec ssl_protocol default options (@jeremymv2), `application_name` option (@mecampbellsoup)\n* 1.12.0 — 2021-01-06 - Lua pattern compatibility fix, Support for Lua 5.1 through 5.4 (@jprjr). Fix bug where SSL vesrion was not being passed. Default to TLS v1.2 when using LuaSec. Luabitop is no longer automatically installed as a dependency. New test suite.\n* 1.11.0 — 2020-03-26 - Allow for TLS v1.2 when using LuaSec (Miles Elam)\n* 1.10.0 — 2019-04-15 - Support luaossl for crypto functions, added better error when missing crypto library\n* 1.9.0 — 2018-04-02 - nginx pool name includes user, connection reports name as `pgmoon`\n* 1.8.0 — 2016-11-07 — Add cqueues support, SSL calling fix for Nginx cosocket (@thibaultCha)\n* 1.7.0 — 2016-09-21 — Add to opm, add support for openresty pool, better default pool, support for hstore (@edan)\n* 1.6.0 — 2016-07-21 — Add support for json and jsonb array decoding\n* 1.5.0 — 2016-07-12 — Add SSL support (@thibaultCha), Add UUID array type (@edan), Add support for notifications (@starius)\n* 1.4.0 — 2016-02-18 — Add support for decoding jsonb, add a json serializer (@thibaultCha)\n* 1.3.0 — 2016-02-11 — Fix bug parsing a string that looked like a number failed, add support for using in ngx when in init context (@thibaultCha), add cleartext password auth, fix warning with md5 auth\n* 1.2.0 — 2015-07-10 — Add support for PostgreSQL Arrays\n* 1.1.1 — 2014-08-12 — Fix a bug with md5 auth\n* 1.1.0 — 2014-05-21 — Add support for multiple queries in one call\n* 1.0.0 — 2014-05-19 — Initial release\n\n## License (MIT)\n\nCopyright (C) 2021 by Leaf Corcoran\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n  [luaossl]: https://github.com/wahern/luaossl\n  [LuaCrypto]: https://luarocks.org/modules/starius/luacrypto\n  [LuaSec]: https://github.com/brunoos/luasec\n  [Lapis]: http://leafo.net/lapis\n  [OpenResty]: https://openresty.org/\n  [LuaSocket]: http://w3.impa.br/~diego/software/luasocket/\n  [cqueues]: http://25thandclement.com/~william/projects/cqueues.html\n","funding_links":[],"categories":["Libraries","Resources"],"sub_categories":["Database drivers","Data Stores"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleafo%2Fpgmoon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleafo%2Fpgmoon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleafo%2Fpgmoon/lists"}