tusken
                                
                                
                                
                                    tusken copied to clipboard
                            
                            
                            
                        100% type-safe query builder compatible with any Postgres client š Generated table/function types, tree-shakable, implicit type casts, and more
ā ļø This library is currently in alpha. Contributors wanted!
tusken
Postgres client from a galaxy far, far away.
- your database is the source-of-truth for TypeScript generated types
 - type safety for all queries (even subqueries)
- all built-in Postgres functions are available and type-safe
 - implicit type casts are accounted for
 
 - minimal, intuitive SQL building
- shortcuts for common tasks (eg: 
get,put, and more) - identifiers are case-sensitive
 
 - shortcuts for common tasks (eg: 
 - lightweight, largely tree-shakeable
 - works with 
@tusken/clito easily import CSV files, wipe data, generate a type-safe client, dump the schema for migrations, and more - you control the 
pgversion as a peer dependency - query streaming with the 
.streammethod (just installpg-query-streamand runtusken generate) 
Migrations?
Use graphile-migrate.
Install
pnpm i tusken@alpha pg postgres-range postgres-interval
pnpm i @tusken/cli@alpha -D
Usage
First, you need a tusken.config.ts file in your project root, unless you plan on using the default config. By default, the Postgres database is assumed to exist at ./postgres relative to the working directory (customize with dataDir in your config) and the generated types are emitted into the ./src/generated folder (customize with schemaDir in your config).
import { defineConfig } from 'tusken/config'
export default defineConfig({
  dataDir: './postgres',
  schemaDir: './src/generated',
  connection: {
    host: 'localhost',
    port: 5432,
    user: 'postgres',
    password: ' ',
  },
  pool: {
    /* node-postgres pooling options */
  },
})
After running pnpm tusken generate -d <database> in your project root, you can import the database client from ./src/db/<database> as the default export.
import db, { t, pg } from './db/<database>'
The t export contains your user-defined Postgres tables and many native types. The pg export contains your user-defined Postgres functions and many built-in functions.
Creating, updating, deleting one row
Say we have a basic user table like thisā¦
create table "user" (
  "id" serial primary key,
  "name" text,
  "password" text
)
To create a user, use the put methodā¦
// Create a user
await db.put(t.user, { name: 'anakin', password: 'padme4eva' })
// Update a user (merge, not replace)
await db.put(t.user, 1, { name: 'vader', password: 'darkside4eva' })
// Delete a user
await db.put(t.user, 1, null)
Getting a row by primary key
Here we can use the get methodā¦
await db.get(t.user, 1)
Selections are supportedā¦
await db.get(
  t.user(u => [u.name]),
  1
)
Selections can have aliasesā¦
await db.get(
  t.user(u => [{ n: u.name }]),
  1
)
// You can omit the array if you don't mind giving
// everything an alias.
await db.get(
  t.user(u => ({ n: u.name })),
  1
)
Selections can contain function callsā¦
await db.get(
  t.user(u => ({
    name: pg.upper(u.name),
  })),
  1
)
To select all but a few columnsā¦
await db.get(t.user.omit('id', 'password'), 1)
Inner joins
// Find all books with >= 100 likes and also get the author of each.
await db.select(t.author).innerJoin(
  t.book.where(b => b.likes.gte(100)),
  t => t.author.id.eq(t.book.authorId)
)
Ā
What's planned?
This is a vague roadmap. Nothing here is guaranteed to be implemented soon, but they will be at some point (contributors welcome).
- math operators
 - enum types
 - domain types
 - composite types
 - more geometry types
 - array-based primary key
 ANYandSOMEoperators- transactions
 - explicit locking
 - views & materialized views
 - table inheritance
 - window functions
 - plugin packages
- these plugins can do any of:
- alter your schema
 - seed your database
 - extend the runtime API
 
 - auto-loading of packages with 
tusken-plugin-abcor@xyz/tusken-plugin-abcnaming scheme - add some new commands
tusken install(merge plugin schemas into your database)tusken seed(use plugins to seed your database)
 
 - these plugins can do any of:
 NOTIFY/LISTENsupport (just copypg-pubsub?)- define Postgres functions with TypeScript
 - more shortcuts for common tasks
 
What could be improved?
This is a list of existing features that aren't perfect yet. If you find a good candidate for this list, please add it and open a PR.
Contributions are extra welcome in these places:
- comprehensive "playground" example
 - subquery support is incomplete
- bug: selectors cannot treat single-column set queries like an array of scalars
 
 - type safety of comparison operators
- all operators are allowed, regardless of data type
 - see 
.wheremethods andisfunction 
 - the 
jsonbtype should be generic- with option to infer its subtype at build-time from current row data
 
 - missing SQL commands
WITHGROUP BYUPDATEMERGEUSINGHAVINGDISTINCT ONINTERSECTCASE- etc