A TypeScript API framework that lets clients compose any queries they need within boundaries you control.
Wrap your tables in a stable, public interface. You can refactor your "private" tables and columns without ever breaking clients.
// api.tsexportclassUserextendsModels.User{// Your public interface stays stable as your schema evolvescreatedAt(){// Before: accessing from JSONB metadata// return this.metadata['->>']('createdAt').cast(Timestamptz);// After: direct column access (schema refactored)returnthis.created_at;}}// route.ts// Compiles to the single SQL query you'd write manually.constuser=awaitUser.select().orderBy((u)=>u.createdAt(),{desc: true}).limit(1).one(tg);Allowed operations are just methods on your interface, including relations and mutations. Everything fully composable and typed.
// api.tsexportclassUserextendsModels.User{todos(){returnTodo.select().where((t)=>t.user_id.eq(this.id));}}exportclassTodoextendsModels.Todos{update({ completed }: {completed: boolean}){returnupdate(Todo).set((t)=>({ completed })).where((t)=>t.id.eq(this.id));}}// route.tsconstuser= ... // The only way to get a todo is through a user:consttodo=awaituser.todos().where((t)=>t.id.eq(todoId)).one(tg);// The only way to update a todo is by getting it from a user:awaittodo.update({completed: true}).execute(tg);Give clients a composable query builder with your unescapable data boundaries. Compose queries in the client with every Postgres feature (joins, window functions, CTEs, etc.) and function as primitives.
// api.tsexportclassUserextendsModels.User{// ...}exportclassTodoextendsModels.Todos{// ...}exportclassApiextendsRpcTarget{getUserFromToken(token: string){returnUser.select((u)=>newUser(u)).where((u)=>u.token.eq(token));}}// Clients receive composable query builders// not flat results// frontend.tsxexportfunctionTodoList({ searchQuery }: {searchQuery: string}){consttodos=useTypegresQuery((user)=>user.todos()// Arbitrarily compose your base query....select((t)=>({id: t.id,title: t.title}))// ...using any Postgres function such as `ilike`:.where((t)=>t.title.ilike(`%${searchQuery}%`)).execute(tg));return(<ul>{todos.map((todo)=>(<likey={todo.id}>{todo.title}</li>))}</ul>);}Warning
Developer Preview: Typegres is experimental and not production-ready. The API is evolving rapidly. Try the playground and star the repo to follow along!
Note
This project is evolving quickly! The code examples in this README are correct, but the playground contains the very latest, most ergonomic API I'm working on.
# Install Typegres npm install typegres// Import the typegres libraryimport{typegres,select}from"typegres";// Import your schema definitionimportdbfrom"./schema";consttg=typegres({/* Your db connection options */});constactiveUsers=awaitselect((u)=>({upper: u.name.upper(),isAdult: u.age[">"](18),}),{from: db.users,where: (u)=>u.isActive,},).execute(tg);console.log(activeUsers);// Output: [{upper: 'ALICE', isAdult: true },{upper: 'CHARLIE', isAdult: false }]See the examples directory for complete working examples.
- Try it live: https://typegres.com/play/
- API Reference: https://typegres.com/api/
src/- Main library source codesrc/gen/- Auto-generated PostgreSQL types and functionssite/- Documentation website and interactive playground
Requirements:
nixpackage manager- (optional)
direnvfor automatic environment setup
To contribute, clone the repository (run nix develop if you don't have direnv set up) and run:
# Install dependencies npm install # Start custom PostgreSQL instance: ./start_postgres.sh # Run the codegen script to generate types and functions npm run codegen # Run tests npm test# Type check the code npm run typecheck # Build the library npm run buildMIT © Ryan Rasti