$ ts-node src/index.ts
Executing (default): CREATE TABLE IF NOT EXISTS "link" ("id" VARCHAR(255) , "url" VARCHAR(255) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY ("id")); COMMENT ON TABLE "link" IS 'Links saved by a user';
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'link' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Server listing on port 3000
We should now see the link table in our database (try to refresh if you don't).
Migrations
Let's try to rename url to uriin our Link model and run the app again.
$ ts-node src/index.ts
Executing (default): CREATE TABLE IF NOT EXISTS "link" ("id" VARCHAR(255) , "uri" VARCHAR(255) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY ("id")); COMMENT ON TABLE "link" IS 'Links saved by a user';
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'link' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Server listing on port 3000
If we look in your UI, nothing changed.
This is because of CREATE TABLE IF NOT EXISTS. The table already exists and the statement gets ignored.
One way of solving this issue is to force sequelize to recreate all the tables with
sequelize.sync({ force: true });
Usingforce: truewill remove the existing data. Use it only for development.
This is fine while we are building database and we don't have any data in production. However, how do we deal with this once we're live? We write migrations
Umzung
$ yarn add umzug @types/umzug
We will store our files in a new migrations folder and create our migration 001_rename_url_to_uri.ts.
.
├── app.ts
├── migrate.ts
└── migrations
  └── 001_rename_url_to_uri.ts
migrations/001_rename_url_to_uri.ts
import { QueryInterface } from 'sequelize';
module.exports = {
// change the database schema
async up(query: QueryInterface) {
await query.renameColumn('link', 'url', 'uri');
},
// revert in case it goes wrong
async down(query: QueryInterface) {
await query.renameColumn('link', 'uri', 'url');
},
};
$ ts-node src/index.ts
.
.
001_rename_url_to_uri migrated
.
.
Server listing on port 3000
Two things happened:
url has been renamed to uri.
A new table SequelizeMeta has been created.
is a framework agnostic migration tool for Node.js. We create migration files and umzug will run them one after the other. It will also store the last migration in a new table.