Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/src/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { FixCategoriesSectionTypeExpressionIndex1779700000000 } from './migratio
import { AddStepNameToEtlRun1779710000000 } from './migrations/1779710000000-AddStepNameToEtlRun';
import { AddUniqueUuidToStationItem1780010901444 } from './migrations/1780010901444-AddUniqueUuidToStationItem';
import { MakeItemFksDeferrable1780020000000 } from './migrations/1780020000000-MakeItemFksDeferrable';
import { MigrateTablePksToUuidV71780030000000 } from './migrations/1780030000000-MigrateTablePksToUuidV7';

export const AppDataSource = new DataSource({
type: 'postgres',
Expand Down Expand Up @@ -81,6 +82,7 @@ export const AppDataSource = new DataSource({
AddStepNameToEtlRun1779710000000,
AddUniqueUuidToStationItem1780010901444,
MakeItemFksDeferrable1780020000000,
MigrateTablePksToUuidV71780030000000,
],
synchronize: false,
extra: { parseInt8: true },
Expand Down
287 changes: 287 additions & 0 deletions backend/src/migrations/1780030000000-MigrateTablePksToUuidV7.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class MigrateTablePksToUuidV71780030000000
implements MigrationInterface
{
name = 'MigrateTablePksToUuidV71780030000000';

public async up(queryRunner: QueryRunner): Promise<void> {
// -------------------------------------------------------------------------
// station_* tables — pure SQL tables, no TypeORM entity management
// Order: leaf tables first, then tables with FKs pointing at them
// -------------------------------------------------------------------------

// Drop FK constraints on station_terminal before altering referenced tables
await queryRunner.query(`
Comment on lines +8 to +15
ALTER TABLE station_terminal
DROP CONSTRAINT IF EXISTS station_terminal_star_system_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_planet_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_orbit_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_moon_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_space_station_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_outpost_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_poi_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_city_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_faction_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_company_id_fkey
`);

// Drop FK on station_terminal_distance before altering station_terminal
await queryRunner.query(`
ALTER TABLE station_terminal_distance
DROP CONSTRAINT IF EXISTS station_terminal_distance_terminal_origin_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_distance_terminal_destination_id_fkey
`);

const stationTables = [
'station_faction',
'station_jurisdiction',
'station_company',
'station_star_system',
'station_orbit',
'station_orbit_distance',
'station_planet',
'station_moon',
'station_city',
'station_space_station',
'station_outpost',
'station_poi',
'station_terminal',
'station_terminal_distance',
];

for (const table of stationTables) {
await queryRunner.query(`
ALTER TABLE "${table}"
ALTER COLUMN id DROP DEFAULT,
ALTER COLUMN id TYPE UUID USING gen_random_uuid(),
ALTER COLUMN id SET DEFAULT gen_random_uuid()
`);
Comment on lines +55 to +59
}

// Convert station_terminal FK columns from BIGINT to UUID
const terminalFkCols = [
'star_system_id',
'planet_id',
'orbit_id',
'moon_id',
'space_station_id',
'outpost_id',
'poi_id',
'city_id',
'faction_id',
'company_id',
];
for (const col of terminalFkCols) {
await queryRunner.query(`
ALTER TABLE station_terminal
ALTER COLUMN ${col} TYPE UUID USING NULL::UUID
`);
}
Comment on lines +75 to +80

// Convert station_terminal_distance FK columns
await queryRunner.query(`
ALTER TABLE station_terminal_distance
ALTER COLUMN terminal_origin_id TYPE UUID USING NULL::UUID,
ALTER COLUMN terminal_destination_id TYPE UUID USING NULL::UUID
`);

// Restore FKs on station_terminal
await queryRunner.query(`
ALTER TABLE station_terminal
ADD CONSTRAINT station_terminal_star_system_id_fkey
FOREIGN KEY (star_system_id) REFERENCES station_star_system(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_planet_id_fkey
FOREIGN KEY (planet_id) REFERENCES station_planet(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_orbit_id_fkey
FOREIGN KEY (orbit_id) REFERENCES station_orbit(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_moon_id_fkey
FOREIGN KEY (moon_id) REFERENCES station_moon(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_space_station_id_fkey
FOREIGN KEY (space_station_id) REFERENCES station_space_station(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_outpost_id_fkey
FOREIGN KEY (outpost_id) REFERENCES station_outpost(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_poi_id_fkey
FOREIGN KEY (poi_id) REFERENCES station_poi(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_city_id_fkey
FOREIGN KEY (city_id) REFERENCES station_city(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_faction_id_fkey
FOREIGN KEY (faction_id) REFERENCES station_faction(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_company_id_fkey
FOREIGN KEY (company_id) REFERENCES station_company(id) ON DELETE SET NULL
`);

// Restore FKs on station_terminal_distance
await queryRunner.query(`
ALTER TABLE station_terminal_distance
ADD CONSTRAINT station_terminal_distance_terminal_origin_id_fkey
FOREIGN KEY (terminal_origin_id) REFERENCES station_terminal(id) ON DELETE CASCADE,
ADD CONSTRAINT station_terminal_distance_terminal_destination_id_fkey
FOREIGN KEY (terminal_destination_id) REFERENCES station_terminal(id) ON DELETE CASCADE
`);

// -------------------------------------------------------------------------
// uex_* tables — TypeORM-managed entities
// These tables have no cross-table FKs on the id column (relations join on
// uex_id, not id), so they can be altered independently.
// -------------------------------------------------------------------------

const uexTables = [
'uex_star_system',
'uex_planet',
'uex_moon',
'uex_city',
'uex_space_station',
'uex_outpost',
'uex_poi',
'uex_company',
'uex_category',
'uex_commodity',
'uex_item',
];

for (const table of uexTables) {
await queryRunner.query(`
ALTER TABLE "${table}"
ALTER COLUMN id DROP DEFAULT,
ALTER COLUMN id TYPE UUID USING gen_random_uuid(),
ALTER COLUMN id SET DEFAULT gen_random_uuid()
`);
}
}

public async down(queryRunner: QueryRunner): Promise<void> {
// Drop restored FKs
await queryRunner.query(`
ALTER TABLE station_terminal
DROP CONSTRAINT IF EXISTS station_terminal_star_system_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_planet_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_orbit_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_moon_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_space_station_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_outpost_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_poi_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_city_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_faction_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_company_id_fkey
`);

await queryRunner.query(`
ALTER TABLE station_terminal_distance
DROP CONSTRAINT IF EXISTS station_terminal_distance_terminal_origin_id_fkey,
DROP CONSTRAINT IF EXISTS station_terminal_distance_terminal_destination_id_fkey
`);

// Revert station_terminal FK columns to BIGINT
const terminalFkCols = [
'star_system_id',
'planet_id',
'orbit_id',
'moon_id',
'space_station_id',
'outpost_id',
'poi_id',
'city_id',
'faction_id',
'company_id',
];
for (const col of terminalFkCols) {
await queryRunner.query(`
ALTER TABLE station_terminal
ALTER COLUMN ${col} TYPE BIGINT USING NULL::BIGINT
`);
}

await queryRunner.query(`
ALTER TABLE station_terminal_distance
ALTER COLUMN terminal_origin_id TYPE BIGINT USING NULL::BIGINT,
ALTER COLUMN terminal_destination_id TYPE BIGINT USING NULL::BIGINT
`);

// Revert station_* PKs to BIGSERIAL
const stationTables = [
'station_terminal_distance',
'station_terminal',
'station_poi',
'station_outpost',
'station_space_station',
'station_city',
'station_moon',
'station_planet',
'station_orbit_distance',
'station_orbit',
'station_star_system',
'station_company',
'station_jurisdiction',
'station_faction',
];

for (const table of stationTables) {
await queryRunner.query(`
CREATE SEQUENCE IF NOT EXISTS "${table}_id_seq";
ALTER TABLE "${table}"
ALTER COLUMN id DROP DEFAULT,
ALTER COLUMN id TYPE BIGINT USING NULL::BIGINT,
ALTER COLUMN id SET DEFAULT nextval('"${table}_id_seq"')
`);
Comment on lines +219 to +226
}

// Revert uex_* PKs
const uexTables = [
'uex_item',
'uex_commodity',
'uex_category',
'uex_company',
'uex_poi',
'uex_outpost',
'uex_space_station',
'uex_city',
'uex_moon',
'uex_planet',
'uex_star_system',
];

for (const table of uexTables) {
await queryRunner.query(`
CREATE SEQUENCE IF NOT EXISTS "${table}_id_seq";
ALTER TABLE "${table}"
ALTER COLUMN id DROP DEFAULT,
ALTER COLUMN id TYPE BIGINT USING NULL::BIGINT,
ALTER COLUMN id SET DEFAULT nextval('"${table}_id_seq"')
`);
}

// Restore FKs on station_terminal
await queryRunner.query(`
ALTER TABLE station_terminal
ADD CONSTRAINT station_terminal_star_system_id_fkey
FOREIGN KEY (star_system_id) REFERENCES station_star_system(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_planet_id_fkey
FOREIGN KEY (planet_id) REFERENCES station_planet(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_orbit_id_fkey
FOREIGN KEY (orbit_id) REFERENCES station_orbit(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_moon_id_fkey
FOREIGN KEY (moon_id) REFERENCES station_moon(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_space_station_id_fkey
FOREIGN KEY (space_station_id) REFERENCES station_space_station(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_outpost_id_fkey
FOREIGN KEY (outpost_id) REFERENCES station_outpost(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_poi_id_fkey
FOREIGN KEY (poi_id) REFERENCES station_poi(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_city_id_fkey
FOREIGN KEY (city_id) REFERENCES station_city(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_faction_id_fkey
FOREIGN KEY (faction_id) REFERENCES station_faction(id) ON DELETE SET NULL,
ADD CONSTRAINT station_terminal_company_id_fkey
FOREIGN KEY (company_id) REFERENCES station_company(id) ON DELETE SET NULL
`);

await queryRunner.query(`
ALTER TABLE station_terminal_distance
ADD CONSTRAINT station_terminal_distance_terminal_origin_id_fkey
FOREIGN KEY (terminal_origin_id) REFERENCES station_terminal(id) ON DELETE CASCADE,
ADD CONSTRAINT station_terminal_distance_terminal_destination_id_fkey
FOREIGN KEY (terminal_destination_id) REFERENCES station_terminal(id) ON DELETE CASCADE
`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ describe('OrgInventoryService', () => {

const mockOrg: Organization = { id: 1, name: 'Test Org' } as Organization;
const mockGame: Game = { id: 1, name: 'Star Citizen' } as Game;
const mockItem: UexItem = { id: 1, uexId: 100, name: 'Test Item' } as UexItem;
const mockItem: UexItem = {
id: 'uuid-test-1',
uexId: 100,
name: 'Test Item',
} as UexItem;
const mockUser: User = { id: 1, username: 'testuser' } as User;

const mockOrgInventoryItem: OrgInventoryItem = {
Expand Down
4 changes: 2 additions & 2 deletions backend/src/modules/uex/entities/uex-category.entity.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { UexCategory } from './uex-category.entity';
describe('UexCategory Entity', () => {
it('should create a UexCategory instance', () => {
const category = new UexCategory();
category.id = 1;
category.id = 'uuid-test-1';
category.uexId = 100;
category.name = 'Test Category';
category.type = 'item';
Expand All @@ -13,7 +13,7 @@ describe('UexCategory Entity', () => {
category.deleted = false;

expect(category).toBeDefined();
expect(category.id).toBe(1);
expect(category.id).toBe('uuid-test-1');
expect(category.uexId).toBe(100);
expect(category.name).toBe('Test Category');
expect(category.type).toBe('item');
Expand Down
4 changes: 2 additions & 2 deletions backend/src/modules/uex/entities/uex-category.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { BaseUexEntity } from './base-uex.entity';
where: 'deleted = FALSE',
})
export class UexCategory extends BaseUexEntity {
@PrimaryGeneratedColumn({ type: 'bigint' })
id!: number;
@PrimaryGeneratedColumn('uuid')
id!: string;

@Column({ length: 50, nullable: true })
type?: string;
Expand Down
4 changes: 2 additions & 2 deletions backend/src/modules/uex/entities/uex-city.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import { UexMoon } from './uex-moon.entity';
`(planet_id IS NOT NULL AND moon_id IS NULL) OR (planet_id IS NULL AND moon_id IS NOT NULL)`,
)
export class UexCity extends BaseUexEntity {
@PrimaryGeneratedColumn({ type: 'bigint' })
id!: number;
@PrimaryGeneratedColumn('uuid')
id!: string;

@Column({ name: 'planet_id', type: 'integer', nullable: true })
planetId?: number;
Expand Down
4 changes: 2 additions & 2 deletions backend/src/modules/uex/entities/uex-commodity.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ import { UexCategory } from './uex-category.entity';
})
@Index('idx_uex_commodities_name', ['name'], { where: 'deleted = FALSE' })
export class UexCommodity extends BaseUexEntity {
@PrimaryGeneratedColumn({ type: 'bigint' })
id!: number;
@PrimaryGeneratedColumn('uuid')
id!: string;

@Column({ name: 'id_category', type: 'integer', nullable: true })
idCategory?: number;
Expand Down
4 changes: 2 additions & 2 deletions backend/src/modules/uex/entities/uex-company.entity.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { UexCompany } from './uex-company.entity';
describe('UexCompany Entity', () => {
it('should create a UexCompany instance', () => {
const company = new UexCompany();
company.id = 1;
company.id = 'uuid-test-1';
company.uexId = 200;
company.name = 'Anvil Aerospace';
company.code = 'ANVL';
company.active = true;
company.deleted = false;

expect(company).toBeDefined();
expect(company.id).toBe(1);
expect(company.id).toBe('uuid-test-1');
expect(company.uexId).toBe(200);
expect(company.name).toBe('Anvil Aerospace');
expect(company.code).toBe('ANVL');
Expand Down
4 changes: 2 additions & 2 deletions backend/src/modules/uex/entities/uex-company.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { BaseUexEntity } from './base-uex.entity';
where: 'deleted = FALSE',
})
export class UexCompany extends BaseUexEntity {
@PrimaryGeneratedColumn({ type: 'bigint' })
id!: number;
@PrimaryGeneratedColumn('uuid')
id!: string;

@Column({ length: 255 })
name!: string;
Expand Down
Loading
Loading