Skip to content

Commit dbfc5cc

Browse files
committed
Add more tips to the readme
Thanks to Anthony Murphy!
1 parent bc2b0cb commit dbfc5cc

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

README.md

+56
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ ${createSecondaryTable}`
238238

239239
## Tips
240240

241+
### Date handling
242+
241243
If you want sane date handling, it is recommended you use the following code snippet to fix a `node-postgres` [bug](https://github.com/brianc/node-postgres/issues/818):
242244

243245
```js
@@ -251,6 +253,60 @@ pg.types.setTypeParser(DATATYPE_DATE, (val) => {
251253
})
252254
```
253255

256+
### Schema migrations vs data migrations
257+
258+
General rule: only change schemas and other static data in database migrations.
259+
260+
When writing a migration which affects data, consider whether the migration needs to be run for all possible environments or just some specific environment. Schema changes and static data need changing for all environments. Often, data changes need to only happen in dev or prod (to fix some data), and might be better of run as one-off jobs (manually or otherwise).
261+
262+
### Making a column NOT NULL
263+
264+
```sql
265+
-- No no no nononono (at least for big tables)
266+
ALTER TABLE my_table ALTER COLUMN currently_nullable SET NOT NULL;
267+
```
268+
269+
TL;DR don't do the above without [reading this](https://medium.com/doctolib/adding-a-not-null-constraint-on-pg-faster-with-minimal-locking-38b2c00c4d1c). It can be slow for big tables, and will lock out all writes to the table until it completes.
270+
271+
### Creating indexes
272+
273+
When creating indexes, there are a few important considerations.
274+
275+
Creating an index should probably look like this:
276+
277+
```sql
278+
-- postgres-migrations disable-transaction
279+
CREATE INDEX CONCURRENTLY IF NOT EXISTS name_of_idx
280+
ON table_name (column_name);
281+
```
282+
283+
- `CONCURRENTLY` - without this, writes on the table will block until the index has finished being created. However, it can't be run inside a transaction.
284+
- `-- postgres-migrations disable-transaction` - migrations are run inside a transaction by default. This disables that.
285+
- `IF NOT EXISTS` - since the transaction is disabled, it's possible to end up in a partially applied state where the index exists but the migration wasn't recorded. In this case, the migration will probably get run again. This ensures that will succeed.
286+
287+
See the [Postgres docs on creating indexes](https://www.postgresql.org/docs/9.6/sql-createindex.html).
288+
289+
### Avoid `IF NOT EXISTS`
290+
291+
_Most_ of the time using `IF NOT EXISTS` is not necessary (see above for an exception). In most cases, we would be better off with a failing migration script that tells us that we tried to create a table with a duplicate name.
292+
293+
### Use separate markdown files for complex documentation
294+
295+
A comment that is added to a migration script can never be changed once the migration script has been deployed. For complex migration scripts, consider documenting them in a separate markdown file with the same file name as the migration script. This documentation can then be updated later if a better explanation becomes apparent.
296+
297+
Your file structure might look something like this:
298+
299+
```text
300+
- migrations
301+
- 0001_complex_migration.md <--- Contains documentation that can be updated.
302+
- 0001_complex_migration.sql
303+
- 0002_simple_migration.sql
304+
Rather than this:
305+
- migrations
306+
- 0001_complex_migration.sql <--- Contains documentation that can never be updated.
307+
- 0002_simple_migration.sql
308+
```
309+
254310
## Useful resources
255311

256312
[Stack Overflow: How We Do Deployment - 2016 Edition (Database Migrations)](http://nickcraver.com/blog/2016/05/03/stack-overflow-how-we-do-deployment-2016-edition/#database-migrations)

0 commit comments

Comments
 (0)