Skip to content

Commit a7ea1f5

Browse files
authored
add docs site (#102)
The current README is hard to navigate and discourages adding more examples. Having a documentation website should allow us to provide more detailed docs.
1 parent dbd2c3b commit a7ea1f5

34 files changed

+11344
-1
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# don't ever lint node_modules
22
node_modules
33
.eslintrc.js
4+
docs

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ coverage/
66
.terraform/
77
.pytest_cache/
88
target/
9+
docs

docs/.gitignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Dependencies
2+
/node_modules
3+
4+
# Production
5+
/build
6+
7+
# Generated files
8+
.docusaurus
9+
.cache-loader
10+
11+
# Misc
12+
.DS_Store
13+
.env.local
14+
.env.development.local
15+
.env.test.local
16+
.env.production.local
17+
18+
npm-debug.log*
19+
yarn-debug.log*
20+
yarn-error.log*

docs/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Website
2+
3+
This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator.
4+
5+
## Installation
6+
7+
```console
8+
yarn install
9+
```
10+
11+
## Local Development
12+
13+
```console
14+
yarn start
15+
```
16+
17+
This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.
18+
19+
## Build
20+
21+
```console
22+
yarn build
23+
```
24+
25+
This command generates static content into the `build` directory and can be served using any static contents hosting service.
26+
27+
## Deployment
28+
29+
```console
30+
GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy
31+
```
32+
33+
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.

docs/babel.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3+
};
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
id: adding-field-with-default
3+
title: adding-field-with-default
4+
---
5+
6+
:::note Postgres Version
7+
8+
This lint only applies to Postgres versions less than 11.
9+
:::
10+
11+
## problem
12+
13+
On Postgres versions less than 11, adding a field with a `DEFAULT` requires a
14+
table rewrite with an `ACCESS EXCLUSIVE` lock.
15+
16+
<https://www.postgresql.org/docs/10/sql-altertable.html#SQL-ALTERTABLE-NOTES>
17+
18+
An `ACCESS EXCLUSIVE` lock blocks reads / writes while the statement is running.
19+
20+
## solution
21+
22+
Add the field as nullable, then set a default, backfill, and remove nullabilty.
23+
24+
Instead of:
25+
26+
```sql
27+
ALTER TABLE "core_recipe" ADD COLUMN "foo" integer DEFAULT 10 NOT NULL;
28+
```
29+
30+
Use:
31+
32+
```sql
33+
ALTER TABLE "core_recipe" ADD COLUMN "foo" integer;
34+
ALTER TABLE "core_recipe" ALTER COLUMN "foo" SET DEFAULT 10;
35+
-- backfill column in batches
36+
ALTER TABLE "core_recipe" ALTER COLUMN "foo" SET NOT NULL;
37+
```
38+
39+
We add our column as nullable, set a default for new rows, backfill our column (ideally done in batches to limit locking), and finally remove nullability.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
id: adding-foreign-key-constraint
3+
title: adding-foreign-key-constraint
4+
---
5+
6+
A foreign key constraint should be added with `NOT VALID`.
7+
8+
Adding a foreign key constraint requires a table scan and a `SHARE ROW EXCLUSIVE` lock on both tables, which blocks writes.
9+
10+
Adding the constraint as `NOT VALID` in one transaction and then using
11+
`VALIDATE` in another transaction will allow writes when adding the
12+
constraint.
13+
14+
## problem
15+
16+
Adding a foreign key constraint requires a table scan and a `SHARE ROW EXCLUSIVE` lock on both tables, which blocks writes to each table.
17+
18+
This means no writes will be allowed to either table while the table you're altering is scanned to validate the constraint.
19+
20+
## solution
21+
22+
To prevent blocking writes to tables, add the constraint as `NOT VALID` in one transaction, then `VALIDATE CONSTRAINT` in another.
23+
24+
While `NOT VALID` prevents row updates while running, it commits instantly if it can get a lock (see ["Safety requirements"](./safe_migrations.md#safety-requirements)). `VALIDATE CONSTRAINT` allows row updates while it scans
25+
the table.
26+
27+
### adding constraint to existing table
28+
29+
Instead of:
30+
31+
```sql
32+
ALTER TABLE "email" ADD CONSTRAINT "fk_user"
33+
FOREIGN KEY ("user_id") REFERENCES "user" ("id");
34+
```
35+
36+
Use:
37+
38+
```sql
39+
ALTER TABLE "email" ADD CONSTRAINT "fk_user"
40+
FOREIGN KEY ("user_id") REFERENCES "user" ("id") NOT VALID;
41+
ALTER TABLE "email" VALIDATE CONSTRAINT "fk_user";
42+
```
43+
44+
Add the foreign key constraint as `NOT VALID` to prevent locking the `"email"` and `"user"` tables.
45+
46+
Run `VALIDATE CONSTRAINT` to scan the `"email"` table in the background while reads and writes continue.
47+
48+
### adding constraint to new table
49+
50+
Instead of:
51+
52+
```sql
53+
CREATE TABLE email (
54+
id BIGINT GENERATED ALWAYS AS IDENTITY,
55+
user_id BIGINT,
56+
email TEXT,
57+
PRIMARY KEY(id),
58+
CONSTRAINT fk_user
59+
FOREIGN KEY ("user_id")
60+
REFERENCES "user" ("id")
61+
);
62+
```
63+
64+
Use:
65+
66+
```sql
67+
CREATE TABLE email (
68+
id BIGINT GENERATED ALWAYS AS IDENTITY,
69+
user_id BIGINT,
70+
email TEXT,
71+
PRIMARY KEY(id)
72+
);
73+
74+
ALTER TABLE "email" ADD CONSTRAINT "fk_user"
75+
FOREIGN KEY ("user_id") REFERENCES "user" ("id") NOT VALID;
76+
ALTER TABLE "email" VALIDATE CONSTRAINT "fk_user";
77+
```
78+
79+
Create the table, add the foreign key constraint as `NOT VALID`, then `VALIDATE` the constraint.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
id: adding-not-nullable-field
3+
title: adding-not-nullable-field
4+
---
5+
6+
Use a check constraint instead of setting a column as `NOT NULL`.
7+
8+
## problem
9+
10+
Adding a column as `NOT NULL` requires a table scan and the `ALTER TABLE` requires
11+
an `ACCESS EXCLUSIVE` lock. Reads and writes will be disabled while this statement is running.
12+
13+
## solution
14+
15+
Add a column as nullable and use a check constraint to verify integrity. The check constraint should be added as `NOT NULL` and then validated.
16+
17+
Instead of:
18+
19+
```sql
20+
ALTER TABLE "core_recipe" ADD COLUMN "foo" integer DEFAULT 10 NOT NULL;
21+
```
22+
23+
Use:
24+
25+
```sql
26+
ALTER TABLE "core_recipe" ADD COLUMN "foo" integer DEFAULT 10;
27+
ALTER TABLE "core_recipe" ADD CONSTRAINT foo_not_null
28+
CHECK ("foo" IS NOT NULL) NOT VALID;
29+
-- backfill column so it's not null
30+
ALTER TABLE "core_recipe" VALIDATE CONSTRAINT foo_not_null;
31+
```
32+
33+
Add the column as nullable, add a check constraint as `NOT VALID` that verifies the column is not null, backfill the column so it no longer contains null values, validate the constraint to verify existing rows are valid.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
id: adding-serial-primary-key-field
3+
title: adding-serial-primary-key-field
4+
---
5+
6+
Outlined in [Citus' 2018 post on tips for Postgres
7+
locking](https://www.citusdata.com/blog/2018/02/22/seven-tips-for-dealing-with-postgres-locks/)
8+
as well as [the Postgres docs](https://www.postgresql.org/docs/current/sql-altertable.html), adding a primary key constraint is a blocking
9+
operation.
10+
11+
Instead of creating the constraint directly, consider creating the
12+
`CONSTRAINT` `USING` an index.
13+
14+
From the Postgres docs:
15+
16+
> To recreate a primary key constraint, without blocking updates while the
17+
> index is rebuilt:
18+
19+
```sql
20+
CREATE UNIQUE INDEX CONCURRENTLY dist_id_temp_idx ON distributors (dist_id);
21+
ALTER TABLE distributors DROP CONSTRAINT distributors_pkey,
22+
ADD CONSTRAINT distributors_pkey PRIMARY KEY USING INDEX dist_id_temp_idx;
23+
```
24+
25+
<https://www.postgresql.org/docs/current/sql-altertable.html>

docs/docs/ban-char-field.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
id: ban-char-field
3+
title: ban-char-field
4+
---
5+
6+
Using `character` is likely a mistake and should almost always be replaced by `text` or `varchar`.
7+
8+
From the postgres docs:
9+
10+
> There is no performance difference among these three types, apart from
11+
> increased storage space when using the blank-padded type, and a few extra CPU
12+
> cycles to check the length when storing into a length-constrained column.
13+
> While character(n) has performance advantages in some other database systems,
14+
> there is no such advantage in PostgreSQL; in fact character(n) is usually the
15+
> slowest of the three because of its additional storage costs. In most
16+
> situations text or character varying should be used instead.
17+
18+
<https://www.postgresql.org/docs/10/datatype-character.html>
19+
20+
See the [`prefer-text-field`](./prefer-text-field.md) rule for info on the advantages of `text` over `varchar`.
21+
22+
Instead of:
23+
24+
```sql
25+
CREATE TABLE "app_user" (
26+
"id" serial NOT NULL PRIMARY KEY,
27+
"name" char(100) NOT NULL,
28+
"email" character NOT NULL,
29+
);
30+
```
31+
32+
Use:
33+
34+
```sql
35+
CREATE TABLE "app_user" (
36+
"id" serial NOT NULL PRIMARY KEY,
37+
"name" varchar(100) NOT NULL,
38+
"email" TEXT NOT NULL,
39+
);
40+
```

0 commit comments

Comments
 (0)