From fcf1329816aeab9ae10c10c65521b5a61ae9b7e5 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Tue, 13 Aug 2024 10:00:04 +0200 Subject: [PATCH] feat: exclude archived projects from insights and project stats (#7843) --- .../project}/project-store.e2e.test.ts | 33 ++++++++++++--- src/lib/features/project/project-store.ts | 41 +++++++++++++------ src/test/fixtures/fake-project-store.ts | 7 ++-- 3 files changed, 60 insertions(+), 21 deletions(-) rename src/{test/e2e/stores => lib/features/project}/project-store.e2e.test.ts (77%) diff --git a/src/test/e2e/stores/project-store.e2e.test.ts b/src/lib/features/project/project-store.e2e.test.ts similarity index 77% rename from src/test/e2e/stores/project-store.e2e.test.ts rename to src/lib/features/project/project-store.e2e.test.ts index b7820753e4..4f5c9cbdae 100644 --- a/src/test/e2e/stores/project-store.e2e.test.ts +++ b/src/lib/features/project/project-store.e2e.test.ts @@ -1,9 +1,9 @@ -import type { IEnvironmentStore } from '../../../lib/features/project-environments/environment-store-type'; +import type { IEnvironmentStore } from '../project-environments/environment-store-type'; -import dbInit, { type ITestDb } from '../helpers/database-init'; -import getLogger from '../../fixtures/no-logger'; -import type { IProjectStore, IUnleashStores } from '../../../lib/types'; -import type { IProjectInsert } from '../../../lib/features/project/project-store-type'; +import dbInit, { type ITestDb } from '../../../test/e2e/helpers/database-init'; +import getLogger from '../../../test/fixtures/no-logger'; +import type { IProjectStore, IUnleashStores } from '../../types'; +import type { IProjectInsert } from './project-store-type'; let stores: IUnleashStores; let db: ITestDb; @@ -11,7 +11,9 @@ let projectStore: IProjectStore; let environmentStore: IEnvironmentStore; beforeAll(async () => { - db = await dbInit('project_store_serial', getLogger); + db = await dbInit('project_store_serial', getLogger, { + experimental: { flags: { archiveProjects: true } }, + }); stores = db.stores; projectStore = stores.projectStore; environmentStore = stores.environmentStore; @@ -21,6 +23,25 @@ afterAll(async () => { await db.destroy(); }); +test('should exclude archived projects', async () => { + const project = { + id: 'archive-me', + name: 'archive-me', + description: 'Blah', + mode: 'open' as const, + }; + await projectStore.create(project); + await projectStore.archive(project.id); + + const allProjects = await projectStore.getAll(); + const count = await projectStore.count(); + const modeCounts = await projectStore.getProjectModeCounts(); + + expect(allProjects).toMatchObject([{ id: 'default' }]); + expect(count).toBe(1); + expect(modeCounts).toMatchObject([{ mode: 'open', count: 1 }]); +}); + test('should have default project', async () => { const project = await projectStore.get('default'); expect(project).toBeDefined(); diff --git a/src/lib/features/project/project-store.ts b/src/lib/features/project/project-store.ts index eeef8d2f9d..45d8e56741 100644 --- a/src/lib/features/project/project-store.ts +++ b/src/lib/features/project/project-store.ts @@ -131,8 +131,9 @@ class ProjectStore implements IProjectStore { ) .leftJoin('project_stats', 'project_stats.project', 'projects.id') .orderBy('projects.name', 'asc'); + if (this.flagResolver.isEnabled('archiveProjects')) { - projects = projects.where('projects.archived_at', null); + projects = projects.where(`${TABLE}.archived_at`, null); } if (query) { @@ -221,12 +222,18 @@ class ProjectStore implements IProjectStore { } async getAll(query: IProjectQuery = {}): Promise { - const rows = await this.db + let projects = this.db .select(COLUMNS) .from(TABLE) .where(query) .orderBy('name', 'asc'); + if (this.flagResolver.isEnabled('archiveProjects')) { + projects = projects.where(`${TABLE}.archived_at`, null); + } + + const rows = await projects; + return rows.map(this.mapRow); } @@ -706,14 +713,17 @@ class ProjectStore implements IProjectStore { } async count(): Promise { - return this.db - .from(TABLE) - .count('*') - .then((res) => Number(res[0].count)); + let count = this.db.from(TABLE).count('*'); + + if (this.flagResolver.isEnabled('archiveProjects')) { + count = count.where(`${TABLE}.archived_at`, null); + } + + return count.then((res) => Number(res[0].count)); } async getProjectModeCounts(): Promise { - const result: ProjectModeCount[] = await this.db + let query = this.db .select( this.db.raw( `COALESCE(${SETTINGS_TABLE}.project_mode, 'open') as mode`, @@ -729,11 +739,18 @@ class ProjectStore implements IProjectStore { .groupBy( this.db.raw(`COALESCE(${SETTINGS_TABLE}.project_mode, 'open')`), ); + + if (this.flagResolver.isEnabled('archiveProjects')) { + query = query.where(`${TABLE}.archived_at`, null); + } + + const result: ProjectModeCount[] = await query; + return result.map(this.mapProjectModeCount); } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - mapProjectModeCount(row): ProjectModeCount { + private mapProjectModeCount(row): ProjectModeCount { return { mode: row.mode, count: Number(row.count), @@ -741,7 +758,7 @@ class ProjectStore implements IProjectStore { } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - mapLinkRow(row): IEnvironmentProjectLink { + private mapLinkRow(row): IEnvironmentProjectLink { return { environmentName: row.environment_name, projectId: row.project_id, @@ -749,7 +766,7 @@ class ProjectStore implements IProjectStore { } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - mapRow(row): IProject { + private mapRow(row): IProject { if (!row) { throw new NotFoundError('No project found'); } @@ -772,7 +789,7 @@ class ProjectStore implements IProjectStore { }; } - mapProjectEnvironmentRow(row: { + private mapProjectEnvironmentRow(row: { environment_name: string; default_strategy: CreateFeatureStrategySchema; }): ProjectEnvironment { @@ -785,7 +802,7 @@ class ProjectStore implements IProjectStore { }; } - getAggregatedApplicationsData(rows): IProjectApplication[] { + private getAggregatedApplicationsData(rows): IProjectApplication[] { const entriesMap = new Map(); rows.forEach((row) => { diff --git a/src/test/fixtures/fake-project-store.ts b/src/test/fixtures/fake-project-store.ts index 11d712d212..b0da4b6f07 100644 --- a/src/test/fixtures/fake-project-store.ts +++ b/src/test/fixtures/fake-project-store.ts @@ -50,7 +50,7 @@ export default class FakeProjectStore implements IProjectStore { async getProjectsWithCounts(): Promise { return this.projects - .filter((project) => project.archivedAt !== null) + .filter((project) => project.archivedAt === null) .map((project) => { return { ...project, @@ -105,7 +105,8 @@ export default class FakeProjectStore implements IProjectStore { destroy(): void {} async count(): Promise { - return this.projects.length; + return this.projects.filter((project) => project.archivedAt === null) + .length; } async get(key: string): Promise { @@ -117,7 +118,7 @@ export default class FakeProjectStore implements IProjectStore { } async getAll(): Promise { - return this.projects; + return this.projects.filter((project) => project.archivedAt === null); } // eslint-disable-next-line @typescript-eslint/no-unused-vars