Fullstack CourseLearn by building
Back to roadmap

Week 2 — PostgreSQL & TypeORM

Learn SQL first, then connections (pool/SSL), then TypeORM entities, repos, migrations, seeds, relations, and transactions — then ship Notes P2 as this week’s mini-project.

End-of-week mini-project · practice only

Library Catalog API (Postgres + TypeORM)

Model a small library — books, authors, publishers, and loans — with real tables, migrations, seeds, and every relationship kind.

Definition

A PostgreSQL-backed Nest service that stores a book catalog and lending records using TypeORM entities, reviewed migrations, and 1:1 / 1:N / N:N relations.

In simpler words

Build the backend a small library would use: add books and authors, connect them properly, and lend a book out inside one safe transaction.

Concepts covered this week

Tables & columns
books, authors, publishers, book_details, and loans tables with typed columns.
Primary & foreign keys
PKs on every table and FKs linking loans → books and books → publishers.
SQL CRUD
Explore insert/select/update/delete in psql before wrapping them in TypeORM.
Joins
A "books with author + publisher" list built from joined tables.
DB connections: URL, pooling, SSL, timeouts
DATABASE_URL plus pool size, SSL, and connect timeout in the data source.
Nest ↔ PostgreSQL: TypeORM root/env
TypeOrmModule.forRootAsync reads config from ConfigService/env.
Entities
Book, Author, Publisher, BookDetail, and Loan entity classes.
Repositories / QueryBuilder
A /books/search endpoint filters by title/author using the QueryBuilder.
Migrations (deep dive)
Generate and run migrations with synchronize: false; review the SQL first.
Seeders
A seed script inserts a few publishers, authors, and books.
Relationships: 1:1, 1:N, N:N
Book↔BookDetail (1:1), Publisher↔Book (1:N), Book↔Author (N:N), Book↔Loan (1:N).
Transactions & multi-write consistency
Borrowing a book creates a Loan and decrements availableCopies atomically.

Deliverables

  • Five entities wired with correct 1:1, 1:N, and N:N relations
  • Reviewed migrations (synchronize: false) plus a seeder
  • GET /books with author + publisher joined; GET /books/search via QueryBuilder
  • POST /loans that borrows a book inside a transaction and updates availableCopies

Build guide

  1. Sketch the ERDOn paper, draw books, authors, publishers, book_details, loans and mark each relationship cardinality before coding.
  2. Explore in psqlCreate the tables by hand and run raw CRUD + a join to feel the SQL your entities will generate.
  3. Wire the connectionConfigure TypeOrmModule.forRootAsync with DATABASE_URL, pool size, SSL, and a connect timeout; keep synchronize: false.
  4. Define entities + relationsAdd @OneToOne (BookDetail), @ManyToOne/@OneToMany (Publisher↔Book, Book↔Loan), and @ManyToMany (Book↔Author).
  5. Generate + run a migrationRead the generated SQL, then run it. Add a seeder that inserts sample publishers, authors, and books.
  6. Query without N+1Build GET /books that joins author + publisher, and /books/search using the QueryBuilder for title/author filters.
  7. Borrow in a transactionPOST /loans opens a transaction: insert the loan and decrement availableCopies; roll back if no copies remain.

Acceptance checklist

- [ ] TypeOrmModule.forRootAsync reads env; synchronize: false
- [ ] 1:1, 1:N, and N:N relations all present and migrated
- [ ] Migration SQL reviewed before running; seeder inserts sample data
- [ ] GET /books joins author + publisher (no N+1)
- [ ] POST /loans is transactional and cannot oversell copies

Stretch goals

  • Add a return-book endpoint that restores availableCopies in a transaction.
  • Add pagination to GET /books using take/skip.
  • Add a unique constraint on ISBN and handle the conflict cleanly.

Tips

  • Never flip synchronize to true — practice the migration workflow instead.
  • Read the generated SQL before every migration run.