├── .dir-locals.el
├── .travis.yml
├── LICENSE.txt
├── test.sh
├── README.md
└── migrations.sql
/.dir-locals.el:
--------------------------------------------------------------------------------
1 | ;;; Directory Local Variables
2 | ;;; For more information see (info "(emacs) Directory Variables")
3 |
4 | ((sql-mode
5 | (sql-product . postgres)))
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | services:
2 | - postgresql
3 |
4 | addons:
5 | postgresql: "9.5"
6 |
7 | script:
8 | ./test.sh
9 |
10 | # Local Variables:
11 | # indent-tabs-mode: nil
12 | # coding: utf-8
13 | # End:
14 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) 2017 Steve Purcell.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | export PGDATABASE=migration-test
4 | THISDIR=$(dirname "$0")
5 |
6 | reset() {
7 | dropdb --if-exists "$PGDATABASE"
8 | createdb "$PGDATABASE"
9 | }
10 |
11 | run_migrations() {
12 | psql -q -v ON_ERROR_STOP=1 -1f "$1"
13 | }
14 |
15 | assert() {
16 | temp=$(mktemp)
17 | cat <<'EOF' > "$temp"
18 | DO
19 | $body$
20 | BEGIN
21 | EOF
22 | cat >> "$temp"
23 | cat <<'EOF' >> "$temp"
24 | END
25 | $body$;
26 | EOF
27 | psql -q -v ON_ERROR_STOP=1 -f "$temp"
28 | }
29 |
30 | fail() {
31 | echo "TEST FAILED" >&2
32 | exit 1;
33 | }
34 |
35 | announce() {
36 | echo
37 | echo "---------------------------------------------------"
38 | echo "$@"
39 | echo "---------------------------------------------------"
40 | }
41 |
42 | test_file=$(mktemp)
43 | cat "$THISDIR/migrations.sql" > "$test_file"
44 |
45 | reset
46 | run_migrations "$test_file"
47 |
48 | announce "Checking initial state"
49 | assert <<'EOF'
50 | ASSERT (EXISTS (SELECT FROM pg_catalog.pg_proc WHERE proname = 'apply_migration'));
51 | ASSERT (NOT EXISTS (SELECT FROM pg_catalog.pg_tables WHERE tablename = 'applied_migrations' AND schemaname = 'public'));
52 | EOF
53 |
54 | announce "Migrating to create a simple table."
55 | cat <<'EOF' >> $test_file
56 | SELECT apply_migration('create_foo', $$
57 | CREATE TABLE foo ();
58 | $$);
59 | EOF
60 | run_migrations "$test_file"
61 |
62 | announce "Checking migration ran and was recorded"
63 | assert <<'EOF'
64 | ASSERT (EXISTS (SELECT 1 FROM applied_migrations WHERE identifier = 'create_foo'));
65 | ASSERT (EXISTS (SELECT FROM pg_catalog.pg_tables WHERE tablename = 'foo' AND schemaname = 'public'));
66 | EOF
67 |
68 | announce "Re-running to check idempotency"
69 | run_migrations "$test_file"
70 | assert <<'EOF'
71 | ASSERT (1 = (SELECT COUNT(1) FROM applied_migrations));
72 | EOF
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/purcell/postgresql-migrations)
2 |
3 |
4 | ## Simple Schema Migrations for PostgreSQL
5 |
6 | ### About
7 |
8 | This repository, which began as a simple Gist, provides a tiny starter
9 | kit and instructions for safely performing schema migrations on a
10 | PostgreSQL database. It works by providing a PLPGSQL procedure which
11 | can execute a chunk of SQL and then note it as having been executed,
12 | so that it will not be executed again the next time.
13 |
14 | We're actively using this in production over at NEC Smart Cities with
15 | great success, so it is now somewhat proven and maintained.
16 |
17 | ### Installation
18 |
19 | Copy `migrations.sql` to your project. Add migrations to the end of
20 | that file in the form of calls to `apply_migration`, as shown in the
21 | examples in that file. To apply all pending migrations, including
22 | bootstrapping the migration function and its `migrations` table, run
23 | the file against your database in a single transaction with psql, or
24 | via your database connection adaptor.
25 |
26 | ```
27 | psql -v ON_ERROR_STOP=1 -1f -- migrations.sql yourdbname
28 | ```
29 |
30 | You should generally arrange to run migrations as the database owner
31 | (or even the super-user), and your applications should use
32 | less-privileged users.
33 |
34 | ### Author
35 |
36 | This software was written by
37 | [Steve Purcell](https://github.com/purcell).
38 |
39 | ### License and copyright
40 |
41 | MIT license.
42 |
43 |