TypeScript type generator for PostgreSQL databases
npm install @fallingfish/dbds
DBDataSource (dbds) is primarily a lightweight PostgreSQL-backed data access
object library. It also includes a simple CLI utility for generating TypeScript
types for a PostgreSQL database.
It is built with [dataloader] and [slonik] for simple, out-of-the-box query batching
and request-level caching while keeping the developer as close to the SQL as possible
and avoiding any "magic" ORM-style implicit queries.
- Background
- Install
- Dependencies
- Usage
- CLI
- Contributing
- License
> My biggest beef with any query builders is that they add an unnecessary level
> of abstraction on top of what is already a language designed specifically for
> creating-reading-updating and deleting data. JavaScript is not designed for this.
>
> — [Stop using Knex.js], Gajus Kuizinas, author of [slonik]
dbds does supply abstractions for several common basic queries, but anything
more (such as queries involving complex joins, etc.) is up to the developer to
write the query for.
I created it originally for several personal projects that used similar tech stacks,
and it eventually found its way to my team's project at work.
One remaining frustration was type generation; although various options exist for
generating TypeScript types for PostgreSQL databases, many of them are unmaintained,
have outdated/obsolete dependencies, or otherwise did not meet the requirements
for the projects I'm working on. Here is some prior art that inspired various features
in the type generation aspect of dbds.
- schemats
- database-types
- sq-reflect
Using yarn:
``bash`
yarn add @fallingfish/dbds
Using npm:
`bash`
npm install @fallingfish/dbds
- node-config - must be installed for the --config--prefixed CLI options totypescript
function
- - dbds has typescript as a peer dependency; it's possible thatpackage.json
it will work with versions earlier than the one that is specified in the ,
since no super complicated features are used.
dbds is primarily used by creating child classes of the DBDataSource class;
Subsequent documentation will refer to those classes as simply "datasources".
`typescript`
class ExampleDataSource extends DBDataSource<
Examples,
ContextType,
Examples$Insert
> {}
The above example shows the simplest example datasource, which uses Examples andExamples$Insert interfaces that could be generated by the dbds CLI (see below),ContextType
along with your own GraphQL . Note: the order of the generic type arguments
is historical; the insert type is a relatively new addition.
#### dataloader integration
Technically, dataloader integration is opt-in, but it is an easy way to improve
performance of a GraphQL api with little effort.
##### Creating DataLoaders
Dataloaders can be created by using the LoaderFactory, which is held in the loaders
property of a datasource. This API should be a significant improvement over the original
API spread across numerous functions.
`typescript`
class ExampleDataSource extends DBDataSource<...> {
private idLoader = this.loaders.create('id', 'uuid')
}
This will create a DataLoader based on the id column, which has the type uuid
in the table.
Given a table with a compound unique index on (for example) the first_name andlast_name columns, creating a DataLoader based on those columns is **not currently
supported**, due to limitations in generalized SQL queries (both in terms of actually
generating the queries and the performance of those queries). Generally, it's not
worth it anyway.
##### Using DataLoaders
Most commonly, you will create a wrapper function around each DataLoader. This can
be accomplished by using the create method on the FinderFactory (i.e. thefinders property of a datasource).
`typescript`
class ExampleDataSource extends DBDataSource<...> {
private idLoader = this.loaders.create('id', 'uuid');
public readonly findById = this.finders.create(this.idLoader);
}
Rows could then be looked up by calling someDataSourceInstance.findById(someId),
and those lookups will be cached until the end of the request.
#### Custom queries
The only public query methods are get (formerly known as all) and count,SELECT
both of which peform queries. For any other query, datasources should implementinsert
their own methods using one of the protected query functions: , update,delete
and .
Previously there was a complicated API with a variety of functions that had widely
varying failure cases. Now, all queries have been united under a single API using
the options object.
| option | description |
| ------------ | ----------------------------------------------------- |
| eachResult | function to call once for each object in a result set |expected
| | number of rows to expect; see [slonik] docs |where
| | WHERE clause options |groupBy
| | GROUP BY clause options |orderBy
| | ORDER BY clause options |having
| | HAVING clause options |
keyToColumn and columnToKey key transformation functions are still present in
the options object, but they are not currently used while I figure out the best
way to do so.
dbds comes with a CLI (perhaps unsurprisingly, dbds) for generating types
for your database:
`bash
$ dbds generate --help
Usage: dbds generate
Generation options
-o, --output Destination filename for generated types
[string] [default: STDOUT]
--gen-tables Generate table types [boolean] [default: true]
--gen-enums Generate enum types [boolean] [default: true]
--gen-insert-types Generate table insert types [boolean] [default: true]
--gen-type-objects Generate column type objects [boolean] [default: true]
-N, --newline Type of newline to use
[choices: "lf", "crlf"] [default: "lf"]
Options:
-D, --database Database connection URL, e.g. postgres:///dbname
[string] [default: DATABASE_URL]
-S, --schema Name of the target schema in the database
[string] [default: "public"]
--config-schema Name of the config key containing the schema name
(requires node-config) [string]
--config-database Name of the config key containing the database url
(requires node-config) [string]
--help Show help [boolean]
``
Pull requests, questions, and bug reports are gladly accepted!
MIT License
[dataloader]: https://github.com/graphql/dataloader
[slonik]: https://github.com/gajus/slonik
[stop using knex.js]: https://gajus.medium.com/stop-using-knex-js-and-earn-30-bf410349856c