From a7c5c68540562e4667317c998505f049a1696f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sun, 3 May 2020 20:18:42 +0200 Subject: [PATCH] feat(api): setup database migrations --- src/database/database.module.ts | 12 +- .../migrations/01-CreateUsersTable.ts | 49 +++++ .../migrations/02-CreateLibraryTables.ts | 194 ++++++++++++++++++ .../migrations/03-CreateListensTable.ts | 75 +++++++ src/music-library/album.entity.ts | 2 +- src/music-library/track.entity.ts | 2 +- 6 files changed, 329 insertions(+), 5 deletions(-) create mode 100644 src/database/migrations/01-CreateUsersTable.ts create mode 100644 src/database/migrations/02-CreateLibraryTables.ts create mode 100644 src/database/migrations/03-CreateListensTable.ts diff --git a/src/database/database.module.ts b/src/database/database.module.ts index 87d798d..0ed79a6 100644 --- a/src/database/database.module.ts +++ b/src/database/database.module.ts @@ -17,9 +17,15 @@ export const DatabaseModule = TypeOrmModule.forRootAsync({ entities: [join(__dirname, "..", "**/*.entity.{ts,js}")], // Migrations - // migrationsRun: true, - // migrations: [join(__dirname, "migrations", "*.{ts,js}")], - synchronize: true, + migrationsRun: true, + migrations: [join(__dirname, "migrations", "*.{ts,js}")], + + // Debug/Development Options + // + // logging: true, + // + // synchronize: true, + // migrationsRun: false, }), inject: [ConfigService], }); diff --git a/src/database/migrations/01-CreateUsersTable.ts b/src/database/migrations/01-CreateUsersTable.ts new file mode 100644 index 0000000..13fe9f7 --- /dev/null +++ b/src/database/migrations/01-CreateUsersTable.ts @@ -0,0 +1,49 @@ +import { MigrationInterface, QueryRunner, Table, TableIndex } from "typeorm"; + +export class CreateUsersTable0000000000001 implements MigrationInterface { + async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: "user", + columns: [ + { + name: "id", + type: "uuid", + isPrimary: true, + isGenerated: true, + generationStrategy: "uuid", + }, + { + name: "displayName", + type: "varchar", + }, + { + name: "photo", + type: "varchar", + isNullable: true, + }, + { name: "spotifyId", type: "varchar", isNullable: true }, + { name: "spotifyAccesstoken", type: "varchar", isNullable: true }, + { name: "spotifyRefreshtoken", type: "varchar", isNullable: true }, + { + name: "spotifyLastrefreshtime", + type: "timestamp", + isNullable: true, + }, + ], + indices: [ + new TableIndex({ + name: "IDX_USER_SPOTIFY_ID", + columnNames: ["spotifyId"], + isUnique: true, + }), + ], + }), + true + ); + } + + async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable("user"); + } +} diff --git a/src/database/migrations/02-CreateLibraryTables.ts b/src/database/migrations/02-CreateLibraryTables.ts new file mode 100644 index 0000000..3f999bb --- /dev/null +++ b/src/database/migrations/02-CreateLibraryTables.ts @@ -0,0 +1,194 @@ +import { + MigrationInterface, + QueryRunner, + Table, + TableIndex, + TableForeignKey, +} from "typeorm"; +import { TableColumnOptions } from "typeorm/schema-builder/options/TableColumnOptions"; + +const spotifyLibraryDetailsColumns: TableColumnOptions[] = [ + { name: "spotifyId", type: "varchar", isNullable: true }, + { name: "spotifyUri", type: "varchar", isNullable: true }, + { name: "spotifyType", type: "varchar", isNullable: true }, + { name: "spotifyHref", type: "varchar", isNullable: true }, +]; + +const primaryUUIDColumn: TableColumnOptions = { + name: "id", + type: "uuid", + isPrimary: true, + isGenerated: true, + generationStrategy: "uuid", +}; + +export class CreateLibraryTables0000000000002 implements MigrationInterface { + async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: "artist", + columns: [ + primaryUUIDColumn, + { + name: "name", + type: "varchar", + }, + ...spotifyLibraryDetailsColumns, + ], + indices: [ + new TableIndex({ + name: "IDX_ARTIST_SPOTIFY_ID", + columnNames: ["spotifyId"], + isUnique: true, + }), + ], + }), + true + ); + + await queryRunner.createTable( + new Table({ + name: "album", + columns: [ + primaryUUIDColumn, + { + name: "name", + type: "varchar", + }, + ...spotifyLibraryDetailsColumns, + ], + indices: [ + new TableIndex({ + name: "IDX_ALBUM_SPOTIFY_ID", + columnNames: ["spotifyId"], + isUnique: true, + }), + ], + }) + ); + + await queryRunner.createTable( + new Table({ + name: "track", + columns: [ + primaryUUIDColumn, + { + name: "name", + type: "varchar", + }, + { name: "albumId", type: "uuid" }, + ...spotifyLibraryDetailsColumns, + ], + indices: [ + new TableIndex({ + name: "IDX_TRACK_SPOTIFY_ID", + columnNames: ["spotifyId"], + isUnique: true, + }), + ], + foreignKeys: [ + new TableForeignKey({ + name: "FK_TRACK_ALBUM_ID", + columnNames: ["albumId"], + referencedColumnNames: ["id"], + referencedTableName: "album", + }), + ], + }) + ); + + await queryRunner.createTable( + new Table({ + name: "album_artists", + columns: [ + { + name: "albumId", + type: "uuid", + isPrimary: true, + }, + { + name: "artistId", + type: "uuid", + isPrimary: true, + }, + ], + indices: [ + new TableIndex({ + name: "IDX_ALBUM_ARTISTS_ALBUM_ID", + columnNames: ["albumId"], + }), + new TableIndex({ + name: "IDX_ALBUM_ARTISTS_ARTIST_ID", + columnNames: ["artistId"], + }), + ], + foreignKeys: [ + new TableForeignKey({ + name: "FK_ALBUM_ID", + columnNames: ["albumId"], + referencedColumnNames: ["id"], + referencedTableName: "album", + }), + new TableForeignKey({ + name: "FK_ARTIST_ID", + columnNames: ["artistId"], + referencedColumnNames: ["id"], + referencedTableName: "artist", + }), + ], + }), + true + ); + + await queryRunner.createTable( + new Table({ + name: "track_artists", + columns: [ + { + name: "trackId", + type: "uuid", + isPrimary: true, + }, + { + name: "artistId", + type: "uuid", + isPrimary: true, + }, + ], + indices: [ + new TableIndex({ + name: "IDX_TRACK_ARTISTS_TRACK_ID", + columnNames: ["trackId"], + }), + new TableIndex({ + name: "IDX_TRACK_ARTISTS_ARTIST_ID", + columnNames: ["artistId"], + }), + ], + foreignKeys: [ + new TableForeignKey({ + name: "FK_TRACK_ARTISTS_TRACK_ID", + columnNames: ["trackId"], + referencedColumnNames: ["id"], + referencedTableName: "track", + }), + new TableForeignKey({ + name: "FK_TRACK_ARTISTS_ARTIST_ID", + columnNames: ["artistId"], + referencedColumnNames: ["id"], + referencedTableName: "artist", + }), + ], + }), + true + ); + } + + async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable("track_artists"); + await queryRunner.dropTable("album_artists"); + await queryRunner.dropTable("track"); + await queryRunner.dropTable("album"); + await queryRunner.dropTable("artist"); + } +} diff --git a/src/database/migrations/03-CreateListensTable.ts b/src/database/migrations/03-CreateListensTable.ts new file mode 100644 index 0000000..5f866a2 --- /dev/null +++ b/src/database/migrations/03-CreateListensTable.ts @@ -0,0 +1,75 @@ +import { + MigrationInterface, + QueryRunner, + Table, + TableIndex, + TableForeignKey, +} from "typeorm"; +import { TableColumnOptions } from "typeorm/schema-builder/options/TableColumnOptions"; + +const primaryUUIDColumn: TableColumnOptions = { + name: "id", + type: "uuid", + isPrimary: true, + isGenerated: true, + generationStrategy: "uuid", +}; + +export class CreateListensTable0000000000003 implements MigrationInterface { + async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: "listen", + columns: [ + primaryUUIDColumn, + { + name: "playedAt", + type: "timestamp", + }, + { + name: "trackId", + type: "uuid", + }, + { + name: "userId", + type: "uuid", + }, + ], + indices: [ + new TableIndex({ + name: "IDX_LISTEN_TRACK_ID", + columnNames: ["trackId"], + }), + new TableIndex({ + name: "IDX_LISTEN_USER_ID", + columnNames: ["userId"], + }), + new TableIndex({ + name: "IDX_LISTEN_UNIQUE", + isUnique: true, + columnNames: ["trackId", "userId", "playedAt"], + }), + ], + foreignKeys: [ + new TableForeignKey({ + name: "FK_LISTEN_TRACK_ID", + columnNames: ["trackId"], + referencedColumnNames: ["id"], + referencedTableName: "track", + }), + new TableForeignKey({ + name: "FK_LISTEN_USER_ID", + columnNames: ["userId"], + referencedColumnNames: ["id"], + referencedTableName: "user", + }), + ], + }), + true + ); + } + + async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable("listen"); + } +} diff --git a/src/music-library/album.entity.ts b/src/music-library/album.entity.ts index 49f849c..c25fa33 100644 --- a/src/music-library/album.entity.ts +++ b/src/music-library/album.entity.ts @@ -19,7 +19,7 @@ export class Album { name: string; @ManyToMany((type) => Artist, (artist) => artist.albums) - @JoinTable() + @JoinTable({ name: "album_artists" }) artists: Artist[]; @OneToMany((type) => Track, (track) => track.album) diff --git a/src/music-library/track.entity.ts b/src/music-library/track.entity.ts index 75beeff..5a798ae 100644 --- a/src/music-library/track.entity.ts +++ b/src/music-library/track.entity.ts @@ -22,7 +22,7 @@ export class Track { album: Album; @ManyToMany((type) => Artist) - @JoinTable() + @JoinTable({ name: "track_artists" }) artists: Artist[]; @Column((type) => SpotifyLibraryDetails)