ts-pg-promise: typed queries for pg-promise without runtime dependencies #559
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hi! This PR is a proposal for a new transform mode in pgtyped ("ts-pg-promise") which adds support for generating types for pg-promise queries without requiring any runtime dependencies1. In our codebase, we use pg-promise a lot and wanted an easy way to get better type safety for SQL queries, and after a bit of research it turned out pgtyped was pretty close to what we would like to have.
The generator searches for
tx.{none,one,oneOrNone,many,manyOrNone}
calls in source files (where the nametx
is configurable as an array of possible names) and inspects the first argument of the call.Queries are automatically named based on the name of the enclosing function. If a function contains several queries or if the function name is not unique across all source files, the conflicting names are disambiguated with a number.
The generator creates an interface containing method signatures for each query so that:
The generator adds 5 fallback overloads to make error messages a little less bad (but they are still not great). Based on some testing, TypeScript always reports the last overload if the argument types don't match, so it would probably require changes to TS compiler itself to improve error messages. Ideally, the overload candidate should be the one whose first parameter passes type check.
Raw and identifier bindings (e.g.
$(foo^)
,$(bar~)
) are not supported (but they are still parsed so that a proper warning message is printed).The generated parameter field types are non-optional and by default not nullable. It seems there was no existing mechanism for adjusting nullabilities of individual parameters, so for this mode we've added a magic comment
/*nullable*/
so you can have for example:Configuration options for
ts-pg-promise
mode:include
: Glob pattern for source files to includeexclude
: Glob pattern for source files to excludeemitFileName
: Path to output filetsconfigPath
: Path to tsconfig.jsonmaxMethodParameterUnionTypeLength
(default:10000
): For dynamic queries, the union type can sometimes become very long because TS cross multiplies each union in an interpolated position in a template literal type. If the total length exceeds this value, the method signature is skipped and the result/parameter interface must be imported to the query manually.variableNames
: Array of variable names to search for in source filesinterfaceName
: Name of the generated interface that contains all the query method signaturesargumentTypeWarning
(default:true
): If set to true, a warning is printed if the type of the query argument is incompatible with type generationparameterKindWarning
(default:true
): If set to true, a warning is printed if the query contains unsupported raw or identifier parametersThere's also some other new general configuration options:
enums.style
(default:type
): Style of enums to generate, can beenum
to generate TS enums ortype
to generate a union of string literals. Forenum
style, a few additional options are available:enums.nameCase
:pascal
to make enum name pascal case orkeep
to not transform the database name at allenums.keyCase
:upper
,lower
orsameAsValue
enums.dropNameSuffix
: If the database enum name ends with this string, it is stripped offinterfaceComments
(default:true
): If set to false, skips generation of commentsdb.schema
: Database schema (search path)anonymousColumnWarning
(default:true
): If set to false, suppresses warning about anonymous columnsDocumentation and tests are incomplete/lacking, but we wanted to send this PR for initial feedback now. Sorry for not opening an issue first, and thanks for reading! =)
Footnotes
The only required runtime change is that trailing
!
or?
in result column names must be stripped off because pgtyped uses this syntax for adjusting result column nullabilities manually. ↩