Fullstack CourseLearn by building
Back to week 2

Topic

Tables & columns

Definition

A table is a named collection of rows that all share the same fixed set of typed columns, and each column definition fixes a name, a data type, and any constraints for every row.

In simpler words

A table is a strict spreadsheet: every row has the same columns, and each column only accepts one kind of value.

Everything else in this week — keys, joins, TypeORM entities — is just more structure on top of tables and columns. Read raw SQL before you read decorators.

After this you can

  • Read a CREATE TABLE statement and describe the resulting shape
  • Name the Postgres types used in this repo (uuid, varchar, text, timestamptz)
  • Explain NOT NULL, UNIQUE, and DEFAULT as column-level rules

What CREATE TABLE actually says

Definition

A CREATE TABLE statement declares a table name and an ordered list of columns, each with a data type and optional constraints, before any row exists.

In simpler words

It is the blueprint: nothing is stored yet, but every future row must match this shape.

This repo’s first migration creates two tables this way — read it like a spec, not like magic.

Every column line has the same anatomy: name, type, then constraints (NOT NULL is implicit unless the column is nullable).

tickets table (from InitSchema)

CREATE TABLE "tickets" (
  "id" uuid NOT NULL DEFAULT gen_random_uuid(),
  "title" character varying(200) NOT NULL,
  "description" text,
  "status" character varying(32) NOT NULL DEFAULT 'open',
  "assignee_id" uuid,
  "created_at" TIMESTAMPTZ NOT NULL DEFAULT now(),
  "updated_at" TIMESTAMPTZ NOT NULL DEFAULT now(),
  CONSTRAINT "PK_tickets" PRIMARY KEY ("id")
);

description and assignee_id omit NOT NULL — they are the only nullable columns on this table.

Choosing column types

Definition

A column’s data type constrains which values Postgres accepts, how much space it reserves, and which operations (sorting, comparing, indexing) are valid on it.

In simpler words

The type is a promise: “this column is always a UUID / always text / always a timestamp,” so the database can reject anything that breaks that promise.

uuid — used for every primary key here; gen_random_uuid() (from the pgcrypto extension) generates one automatically.

character varying(n) — bounded text, good for titles and emails where a max length is a real business rule.

text — unbounded text, used for ticket.description where a length cap would be arbitrary.

timestamptz — always store timestamps with timezone; created_at/updated_at both use it with a now() default.

UUID primary key needs the extension

CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- then columns can default to gen_random_uuid()

Without pgcrypto, gen_random_uuid() does not exist and the default fails.

Constraints are column-level rules

Definition

A constraint restricts which values a column or row may take, such as forbidding NULL, requiring uniqueness, or supplying a value when none is given.

In simpler words

Constraints are how the table enforces its own rules, so bad data cannot slip in even if application code has a bug.

NOT NULL (the default unless a column is written without it) — description and assignee_id are the exceptions on tickets.

UNIQUE — users.email has UQ_users_email so two accounts can never share an email.

DEFAULT — tickets.status defaults to 'open'; users.role defaults to 'member'; both save a value even if the app forgets to send one.

users.email uniqueness

"email" character varying NOT NULL,
...
CONSTRAINT "UQ_users_email" UNIQUE ("email")

A duplicate INSERT on email raises a Postgres error before any application code runs.

Keep in mind

  • Read the migration SQL before the entity — the table is the ground truth TypeORM is trying to describe.
  • A column with no explicit NOT NULL and no default is nullable; check both before assuming.
  • Prefer a type that matches the real constraint (length, timezone) over a generic “big enough” type.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥ 80% (enforced by the API) to save progress.

Checking your session…

10 questions · concept 3 · syntax 2 · practical 3 · logic 2

Concept1. Which statement best defines Tables & columns?
Syntax2. Which code-level choice matches Tables & columns?
Practical3. A reviewer spots a bug related to Tables & columns. What is the right fix?
Logic4. Which reasoning correctly explains Tables & columns?
Concept5. Which boundary does correct use of Tables & columns preserve?
Practical6. What is the safest next step when applying Tables & columns?
Syntax7. Which implementation direction matches the rule for Tables & columns?
Logic8. Which consequence follows from applying Tables & columns correctly?
Concept9. Which claim about Tables & columns is true in this Nest + Postgres monorepo?
Practical10. Which team practice best demonstrates Tables & columns?