infra(server): fix Album TypeORM relations and change ids to uuids (#1582)

* infra: make api-key primary key column a UUID

* infra: move ManyToMany relations in album entity, make ownerId ManyToOne

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
Zack Pollard
2023-02-18 20:58:55 +00:00
committed by GitHub
parent 917f1dea9f
commit 000d0a08f4
24 changed files with 368 additions and 461 deletions

View File

@@ -2,14 +2,15 @@ import {
Column,
CreateDateColumn,
Entity,
JoinTable,
ManyToMany,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { AssetAlbumEntity } from './asset-album.entity';
import { SharedLinkEntity } from './shared-link.entity';
import { UserAlbumEntity } from './user-album.entity';
import { AssetEntity } from './asset.entity';
import { UserEntity } from './user.entity';
@Entity('albums')
@@ -17,12 +18,12 @@ export class AlbumEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@ManyToOne(() => UserEntity, { eager: true, onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
owner!: UserEntity;
@Column()
ownerId!: string;
@ManyToOne(() => UserEntity, { eager: true })
owner!: UserEntity;
@Column({ default: 'Untitled Album' })
albumName!: string;
@@ -35,11 +36,13 @@ export class AlbumEntity {
@Column({ comment: 'Asset ID to be used as thumbnail', type: 'varchar', nullable: true })
albumThumbnailAssetId!: string | null;
@OneToMany(() => UserAlbumEntity, (userAlbums) => userAlbums.albumInfo)
sharedUsers?: UserAlbumEntity[];
@ManyToMany(() => UserEntity, { eager: true })
@JoinTable()
sharedUsers!: UserEntity[];
@OneToMany(() => AssetAlbumEntity, (assetAlbumEntity) => assetAlbumEntity.albumInfo)
assets?: AssetAlbumEntity[];
@ManyToMany(() => AssetEntity, { eager: true })
@JoinTable()
assets!: AssetEntity[];
@OneToMany(() => SharedLinkEntity, (link) => link.album)
sharedLinks!: SharedLinkEntity[];

View File

@@ -3,8 +3,8 @@ import { UserEntity } from './user.entity';
@Entity('api_keys')
export class APIKeyEntity {
@PrimaryGeneratedColumn()
id!: number;
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column()
name!: string;
@@ -12,12 +12,12 @@ export class APIKeyEntity {
@Column({ select: false })
key?: string;
@Column()
userId!: string;
@ManyToOne(() => UserEntity)
user?: UserEntity;
@Column()
userId!: string;
@CreateDateColumn({ type: 'timestamptz' })
createdAt!: string;

View File

@@ -1,31 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne, OneToOne, PrimaryGeneratedColumn, Unique } from 'typeorm';
import { AlbumEntity } from './album.entity';
import { AssetEntity } from './asset.entity';
@Entity('asset_album')
@Unique('UQ_unique_asset_in_album', ['albumId', 'assetId'])
export class AssetAlbumEntity {
@PrimaryGeneratedColumn()
id!: string;
@Column()
albumId!: string;
@Column()
@OneToOne(() => AssetEntity, (entity) => entity.id)
assetId!: string;
@ManyToOne(() => AlbumEntity, (album) => album.assets, {
onDelete: 'CASCADE',
nullable: true,
})
@JoinColumn({ name: 'albumId' })
albumInfo!: AlbumEntity;
@ManyToOne(() => AssetEntity, {
onDelete: 'CASCADE',
nullable: true,
})
@JoinColumn({ name: 'assetId' })
assetInfo!: AssetEntity;
}

View File

@@ -1,13 +1,11 @@
export * from './album.entity';
export * from './api-key.entity';
export * from './asset-album.entity';
export * from './asset.entity';
export * from './device-info.entity';
export * from './exif.entity';
export * from './smart-info.entity';
export * from './system-config.entity';
export * from './tag.entity';
export * from './user-album.entity';
export * from './user.entity';
export * from './user-token.entity';
export * from './shared-link.entity';

View File

@@ -1,27 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn, Unique } from 'typeorm';
import { UserEntity } from './user.entity';
import { AlbumEntity } from './album.entity';
@Entity('user_shared_album')
@Unique('PK_unique_user_in_album', ['albumId', 'sharedUserId'])
export class UserAlbumEntity {
@PrimaryGeneratedColumn()
id!: string;
@Column()
albumId!: string;
@Column()
sharedUserId!: string;
@ManyToOne(() => AlbumEntity, (album) => album.sharedUsers, {
onDelete: 'CASCADE',
nullable: true,
})
@JoinColumn({ name: 'albumId' })
albumInfo!: AlbumEntity;
@ManyToOne(() => UserEntity)
@JoinColumn({ name: 'sharedUserId' })
userInfo!: UserEntity;
}

View File

@@ -0,0 +1,20 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class APIKeyUUIDPrimaryKey1675808874445 implements MigrationInterface {
name = 'APIKeyUUIDPrimaryKey1675808874445'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "api_keys" DROP CONSTRAINT "PK_5c8a79801b44bd27b79228e1dad"`);
await queryRunner.query(`ALTER TABLE "api_keys" DROP COLUMN "id"`);
await queryRunner.query(`ALTER TABLE "api_keys" ADD "id" uuid NOT NULL DEFAULT uuid_generate_v4()`);
await queryRunner.query(`ALTER TABLE "api_keys" ADD CONSTRAINT "PK_5c8a79801b44bd27b79228e1dad" PRIMARY KEY ("id")`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "api_keys" DROP CONSTRAINT "PK_5c8a79801b44bd27b79228e1dad"`);
await queryRunner.query(`ALTER TABLE "api_keys" DROP COLUMN "id"`);
await queryRunner.query(`ALTER TABLE "api_keys" ADD "id" SERIAL NOT NULL`);
await queryRunner.query(`ALTER TABLE "api_keys" ADD CONSTRAINT "PK_5c8a79801b44bd27b79228e1dad" PRIMARY KEY ("id")`);
}
}

View File

@@ -0,0 +1,82 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class FixAlbumEntityTypeORM1675812532822 implements MigrationInterface {
name = 'FixAlbumEntityTypeORM1675812532822'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "asset_album" RENAME TO "albums_assets_assets"`);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP CONSTRAINT "FK_7ae4e03729895bf87e056d7b598"`);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP CONSTRAINT "FK_256a30a03a4a0aff0394051397d"`);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP CONSTRAINT "UQ_unique_asset_in_album"`);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP CONSTRAINT "PK_a34e076afbc601d81938e2c2277"`);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" DROP COLUMN "id"`);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" RENAME COLUMN "albumId" TO "albumsId"`);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" RENAME COLUMN "assetId" TO "assetsId"`);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" ADD CONSTRAINT "PK_c67bc36fa845fb7b18e0e398180" PRIMARY KEY ("albumsId", "assetsId")`);
await queryRunner.query(`CREATE INDEX "IDX_e590fa396c6898fcd4a50e4092" ON "albums_assets_assets" ("albumsId") `);
await queryRunner.query(`CREATE INDEX "IDX_4bd1303d199f4e72ccdf998c62" ON "albums_assets_assets" ("assetsId") `);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" ADD CONSTRAINT "FK_e590fa396c6898fcd4a50e40927" FOREIGN KEY ("albumsId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "albums_assets_assets" ADD CONSTRAINT "FK_4bd1303d199f4e72ccdf998c621" FOREIGN KEY ("assetsId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "user_shared_album" RENAME TO "albums_shared_users_users"`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP CONSTRAINT "FK_543c31211653e63e080ba882eb5"`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP CONSTRAINT "FK_7b3bf0f5f8da59af30519c25f18"`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP CONSTRAINT "PK_unique_user_in_album"`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP CONSTRAINT "PK_b6562316a98845a7b3e9a25cdd0"`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP COLUMN "id"`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" RENAME COLUMN "albumId" TO "albumsId"`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" RENAME COLUMN "sharedUserId" TO "usersId"`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ADD CONSTRAINT "PK_7df55657e0b2e8b626330a0ebc8" PRIMARY KEY ("albumsId", "usersId")`);
await queryRunner.query(`CREATE INDEX "IDX_427c350ad49bd3935a50baab73" ON "albums_shared_users_users" ("albumsId") `);
await queryRunner.query(`CREATE INDEX "IDX_f48513bf9bccefd6ff3ad30bd0" ON "albums_shared_users_users" ("usersId") `);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ADD CONSTRAINT "FK_427c350ad49bd3935a50baab737" FOREIGN KEY ("albumsId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ADD CONSTRAINT "FK_f48513bf9bccefd6ff3ad30bd06" FOREIGN KEY ("usersId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "albums" DROP CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4"`)
await queryRunner.query(`ALTER TABLE "albums" ADD CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "albums_assets_assets" RENAME TO "asset_album"`);
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" RENAME TO "user_shared_album"`);
await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_e590fa396c6898fcd4a50e40927"`);
await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_4bd1303d199f4e72ccdf998c621"`);
await queryRunner.query(`ALTER TABLE "user_shared_album" DROP CONSTRAINT "FK_427c350ad49bd3935a50baab737"`);
await queryRunner.query(`ALTER TABLE "user_shared_album" DROP CONSTRAINT "FK_f48513bf9bccefd6ff3ad30bd06"`);
await queryRunner.query(`DROP INDEX "public"."IDX_427c350ad49bd3935a50baab73"`);
await queryRunner.query(`DROP INDEX "public"."IDX_f48513bf9bccefd6ff3ad30bd0"`);
await queryRunner.query(`DROP INDEX "public"."IDX_e590fa396c6898fcd4a50e4092"`);
await queryRunner.query(`DROP INDEX "public"."IDX_4bd1303d199f4e72ccdf998c62"`);
await queryRunner.query(`ALTER TABLE "albums" DROP CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4"`);
await queryRunner.query(
`ALTER TABLE "albums" ADD CONSTRAINT "FK_b22c53f35ef20c28c21637c85f4" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
);
await queryRunner.query(`ALTER TABLE "user_shared_album" DROP CONSTRAINT "PK_7df55657e0b2e8b626330a0ebc8"`);
await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "PK_323f8dcbe85373722886940f143" PRIMARY KEY ("albumsId")`);
await queryRunner.query(`ALTER TABLE "user_shared_album" DROP COLUMN "usersId"`);
await queryRunner.query(`ALTER TABLE "user_shared_album" DROP CONSTRAINT "PK_323f8dcbe85373722886940f143"`);
await queryRunner.query(`ALTER TABLE "user_shared_album" DROP COLUMN "albumsId"`);
await queryRunner.query(`ALTER TABLE "user_shared_album" ADD "sharedUserId" uuid NOT NULL`);
await queryRunner.query(`ALTER TABLE "user_shared_album" ADD "albumId" uuid NOT NULL`);
await queryRunner.query(`ALTER TABLE "user_shared_album" ADD "id" SERIAL NOT NULL`);
await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "PK_b6562316a98845a7b3e9a25cdd0" PRIMARY KEY ("id")`);
await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "PK_unique_user_in_album" UNIQUE ("albumId", "sharedUserId")`);
await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "FK_7b3bf0f5f8da59af30519c25f18" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_shared_album" ADD CONSTRAINT "FK_543c31211653e63e080ba882eb5" FOREIGN KEY ("sharedUserId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "PK_c67bc36fa845fb7b18e0e398180"`);
await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "PK_b4f2e5b96efc25cbccd80a04f7a" PRIMARY KEY ("albumsId")`);
await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "PK_b4f2e5b96efc25cbccd80a04f7a"`);
await queryRunner.query(`ALTER TABLE "asset_album" RENAME COLUMN "albumsId" TO "albumId"`);
await queryRunner.query(`ALTER TABLE "asset_album" RENAME COLUMN "assetsId" TO "assetId"`);
await queryRunner.query(`ALTER TABLE "asset_album" ADD "id" SERIAL NOT NULL`);
await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "PK_a34e076afbc601d81938e2c2277" PRIMARY KEY ("id")`);
await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "UQ_unique_asset_in_album" UNIQUE ("albumId", "assetId")`);
await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "FK_256a30a03a4a0aff0394051397d" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "asset_album" ADD CONSTRAINT "FK_7ae4e03729895bf87e056d7b598" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
}

View File

@@ -12,12 +12,12 @@ export class APIKeyRepository implements IKeyRepository {
return this.repository.save(dto);
}
async update(userId: string, id: number, dto: Partial<APIKeyEntity>): Promise<APIKeyEntity> {
async update(userId: string, id: string, dto: Partial<APIKeyEntity>): Promise<APIKeyEntity> {
await this.repository.update({ userId, id }, dto);
return this.repository.findOneOrFail({ where: { id: dto.id } });
}
async delete(userId: string, id: number): Promise<void> {
async delete(userId: string, id: string): Promise<void> {
await this.repository.delete({ userId, id });
}
@@ -35,7 +35,7 @@ export class APIKeyRepository implements IKeyRepository {
});
}
getById(userId: string, id: number): Promise<APIKeyEntity | null> {
getById(userId: string, id: string): Promise<APIKeyEntity | null> {
return this.repository.findOne({ where: { userId, id } });
}

View File

@@ -24,9 +24,7 @@ export class SharedLinkRepository implements ISharedLinkRepository {
},
album: {
assets: {
assetInfo: {
exifInfo: true,
},
exifInfo: true,
},
},
},
@@ -37,9 +35,7 @@ export class SharedLinkRepository implements ISharedLinkRepository {
},
album: {
assets: {
assetInfo: {
createdAt: 'ASC',
},
createdAt: 'ASC',
},
},
},
@@ -69,9 +65,7 @@ export class SharedLinkRepository implements ISharedLinkRepository {
relations: {
assets: true,
album: {
assets: {
assetInfo: true,
},
assets: true,
},
user: true,
},
@@ -109,7 +103,7 @@ export class SharedLinkRepository implements ISharedLinkRepository {
id,
album: {
assets: {
assetId,
id: assetId,
},
},
},