Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding pllua (Lua PostgreSQL Procedural Language) type annotations. #36

Merged
merged 1 commit into from
Jul 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/busted/run_tests
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be consistent with check-all.sh, and btw, /bin/sh sometimes points to other shells like dash, where BASH_SOURCE is not defined.

set -ex
cd `dirname $BASH_SOURCE`
cyan build --prune
Expand Down
65 changes: 65 additions & 0 deletions types/pllua/pllua/elog.d.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
local record elog
enum Severity
"debug"
"log"
"info"
"notice"
"warning"
"error"
end

record ELogInfo
sqlstate: string
message: string
detail: string
table: string
column: string
datatype: string
constraint: string
schema: string
end

elog: function(Severity, message: string)
elog: function(Severity, sqlstate: string, message: string)
elog: function(Severity, sqlstate: string, message: string, detail: string)
elog: function(Severity, sqlstate: string, message: string, detail: string, hint: string)
elog: function(Severity, ELogInfo)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to "re-export" a module or a bunch of symbols? At least being able to do something like:

local elog = require 'pllua.elog'
[...]
   elog: typeof(elog.elog)
   debug: typeof(elog.debug)
   log: typeof(elog.log)
   info: typeof(elog.info)
   notice: typeof(elog.notice)
   warning: typeof(elog.warning)
   error: typeof(elog.error)

Something like typeof would also be helpful for referencing local types that could not be exported.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nested type should be publicly accessible just like the record attributes, so you should be able to use elog.ELogInfo from client code that requires this module.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, elog.ELogInfo is being exported (and it's being used in spi.d.tl), however I meant being able to express a "poly" type and associate that to a type variable, something like type logfunction = function(message: string) & function(sqlstate: string, message: string) & ... but I guess we first would need some syntax to express type intersection.


debug: function(message: string)
debug: function(sqlstate: string, message: string)
debug: function(sqlstate: string, message: string, detail: string)
debug: function(sqlstate: string, message: string, detail: string, hint: string)
debug: function(ELogInfo)

log: function(message: string)
log: function(sqlstate: string, message: string)
log: function(sqlstate: string, message: string, detail: string)
log: function(sqlstate: string, message: string, detail: string, hint: string)
log: function(ELogInfo)

info: function(message: string)
info: function(sqlstate: string, message: string)
info: function(sqlstate: string, message: string, detail: string)
info: function(sqlstate: string, message: string, detail: string, hint: string)
info: function(ELogInfo)

notice: function(message: string)
notice: function(sqlstate: string, message: string)
notice: function(sqlstate: string, message: string, detail: string)
notice: function(sqlstate: string, message: string, detail: string, hint: string)
notice: function(ELogInfo)

warning: function(message: string)
warning: function(sqlstate: string, message: string)
warning: function(sqlstate: string, message: string, detail: string)
warning: function(sqlstate: string, message: string, detail: string, hint: string)
warning: function(ELogInfo)

error: function(message: string)
error: function(sqlstate: string, message: string)
error: function(sqlstate: string, message: string, detail: string)
error: function(sqlstate: string, message: string, detail: string, hint: string)
error: function(ELogInfo)
end

return elog
48 changes: 48 additions & 0 deletions types/pllua/pllua/error.d.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
local record err
enum SQLErrorSeverity
"error"
end

-- SQL errors caught in Lua code are represented as objects rather than strings,
-- though print() or tostring() will give a formatted text representation
-- The pllua.error module provides the following simple functions as a table:
record SQLError
-- Mandatory fields:
category: string -- The error category name, e.g. "data_exception", or a 5-character sqlstate category code (xx000) if no name is known
errcode: string -- The error code name, e.g. "numeric_value_out_of_range", or a 5-character sqlstate if no name for the error is known
severity: SQLErrorSeverity -- A string "error" (other values like "warning" should never be seen)
sqlstate: string -- The 5-character sqlstate code for the error
message: string -- The error message text

-- Optional fields:
context: string|nil -- The error context
column: string|nil -- Name of a column associated with the error, if any
constraint: string|nil -- Name of a constraint associated with the error, if any
datatype: string|nil -- Name of a data type associated with the error, if any
detail: string|nil -- Detail message supplied for the error, if any
hint: string|nil -- The hint text for the error
internal_position: integer|nil -- the character position within the internal query
internal_query: string|nil -- internal query text for the error
message_id: string|nil -- Untranslated error message text (not available in PostgreSQL 9.5)
pg_source_file: string|nil -- Source file of the error
pg_source_function: string|nil -- Source function name of the error
pg_source_line: integer|nil -- source line number of the error
position: integer|nil -- character position of the error within the original query
schema: string|nil -- Name of a schema associated with the error, if any
table: string|nil -- Name of a table associated with the error, if any
end

-- returns "error" if e is an SQL error object, otherwise nothing
type: function(e: SQLError): SQLErrorSeverity
type: function(e: any): nil

-- returns e.errcode if e is an SQL error object, otherwise nothing
errcode: function(e: SQLError): string -- returns e.errcode
errcode: function(e: any): nil

-- returns e.category if e is an SQL error object, otherwise nothing
category: function(e: SQLError): string
category: function(e: any): nil
end

return err
49 changes: 49 additions & 0 deletions types/pllua/pllua/jsonb.d.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
local record jsonb
type JsonValue = string | {string|integer:JsonValue} | number | boolean | nil

record ConversionOptions
map: function(val: JsonValue): JsonValue
null: any
empty_object: boolean
array_thresh: integer
array_frac: integer
end

record JsonbDatum
userdata

-- If the returned JsonValue is a table, its metatable will indicate
-- whether it corresponds to a json array or object:
metamethod __call: function(JsonbDatum, options: ConversionOptions): JsonValue

typeinfo: JsonbTypeInfo
end

record JsonbTypeInfo
userdata

metamethod __call: function(JsonbTypeInfo, json: string | {string|integer:any}): JsonbDatum

fromstring: function(JsonbTypeInfo, string): JsonbDatum
frombinary: function(JsonbTypeInfo, string): JsonbDatum
name: function(JsonbTypeInfo, typmod: string): string
end

is_object: function(table): boolean
is_array: function(table): boolean
set_as_array: function(table): table
set_as_object: function(table): table
set_as_unknown: function(table): table

-- In addition the following functions are provided from version 2.0.8 on:
-- note: iterators hold their state in upvalues:
pairs: function(val: JsonbDatum): (function(): string|integer, JsonbDatum, integer)
ipairs: function(val: JsonbDatum): (function(): integer, JsonbDatum)
type: function(val: JsonbDatum)
type: function(val: JsonbDatum | JsonValue, lax: boolean)
end

local jval: jsonb.JsonbDatum
print((jval{} as table).pelota)

return jsonb
47 changes: 47 additions & 0 deletions types/pllua/pllua/numeric.d.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require 'pllua.pgtype'

-- NumericDatum has metamethods for mathematical operations, but care must be
-- taken if == is used, since Lua compares their types before calling __eq, so
-- the comparison of userdata and number values will always be false.
local record numeric
record NumericDatum
userdata

metamethod __tostring: function(NumericDatum): string
metamethod __add: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __div: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __eq: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __idiv: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __le: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __lt: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __mod: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __mul: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __pow: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __sub: function(NumericDatum|number, NumericDatum|number): NumericDatum
metamethod __unm: function(NumericDatum): NumericDatum

typeinfo: TypeInfo
end

abs: function(number|NumericDatum): NumericDatum
ceil: function(number|NumericDatum): NumericDatum
equal: function(number|NumericDatum, number|NumericDatum): boolean
exp: function(number|NumericDatum): NumericDatum
floor: function(number|NumericDatum): NumericDatum
isnan: function(number|NumericDatum): boolean
sign: function(number|NumericDatum): NumericDatum -- yes, a datum with -1, 0 or 1
sqrt: function(number|NumericDatum): NumericDatum
log: function(number|NumericDatum): NumericDatum
log: function(number|NumericDatum, base: number|NumericDatum): NumericDatum
tointeger: function(number|NumericDatum): integer|nil
tointeger: function(number|NumericDatum): integer|nil
tointeger: function(number|NumericDatum): integer|nil
trunc: function(number|NumericDatum): NumericDatum
trunc: function(number|NumericDatum, digits: integer): NumericDatum
round: function(number|NumericDatum): NumericDatum
round: function(number|NumericDatum, digits: integer): NumericDatum

new: function(number|NumericDatum): NumericDatum
end

return numeric
20 changes: 20 additions & 0 deletions types/pllua/pllua/paths.d.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Module added in pllua version 2.0.2.

local record paths
bin: function(): string
lib: function(): string
pkglib: function(): string
libdir: function(): string
share: function(): string
locale: function(): string | nil
-- The following directories may be defined but not exist:
doc: function(): string | nil
etc: function(): string | nil
html: function(): string | nil
include: function(): string | nil
includeserver: function(): string | nil
man: function(): string | nil
pkginclude: function(): string | nil
end

return paths
39 changes: 39 additions & 0 deletions types/pllua/pllua/pgtype.d.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
local type Datum = any

-- TypeInfo can't be exported here since in tl a module cannot return a Map
-- with records inside nor a maprecord (map|record). This is why it's global.
global record TypeInfo
userdata

-- Construct a new Datum object by copying from the specified value, which must already be of a compatible type
metamethod __call: function(TypeInfo, datum: Datum): Datum
-- Construct a new Datum object of the specified type from the arguments given. The nature of the arguments varies according to the category of type being constructed.
-- More info in: https://pllua.github.io/pllua/#S2.6
-- Consider casting Datum to the correct datum type such as time.DatetimeDatum or numeric.NumericDatum,
-- or even {string|integer:Datum} for rows/arrays, but be careful when using pairs/ipairs:
metamethod __call: function(TypeInfo, ...: any): Datum
-- If cyclic requires were supported we could have:
--metamethod __call: function(TypeInfo, time.CalendarTable): time.DatetimeDatum

-- Construct a new Datum object given its standard text representation in str. For some types the distinction between typeinfo:fromstring(str) and typeinfo(str) is significant.
fromstring: function(TypeInfo, string): Datum
-- Construct a new Datum object given its wire-protocol binary representation in str. This is less useful than it might seem because for many data types, the interpretation of the binary representation is dependent on the client_encoding setting.
frombinary: function(TypeInfo, string): Datum
--Returns the name of the type as SQL syntax (same as the format_type function in SQL, or ::regtype output)
name: function(TypeInfo, typmod: string): string

-- For array or range types, returns the typeinfo of the element type
element: function(TypeInfo): TypeInfo
-- For row types, returns the typeinfo of the named column
element: function(TypeInfo, column_name: string): TypeInfo
end

local type SQLTypeName = string
local type datumtofunction = function(value: Datum|any, argno: integer): TypeInfo

-- pgtype contains as well a special entry called "array" whose type is {SQLTypeName: TypeInfo}.
-- you will have to cast pgtype to use it, or you can use pgtype['elemtype[]'] instead.
-- There's also another special entry "jsonb" which returns a JsonbTypeInfo
local pgtype: {SQLTypeName: TypeInfo} | datumtofunction

return pgtype
Loading