diff --git a/apps/event-queue/src/repository/in-memory/resource.ts b/apps/event-queue/src/repository/in-memory/resource.ts index ff8c2bcc4..669b01237 100644 --- a/apps/event-queue/src/repository/in-memory/resource.ts +++ b/apps/event-queue/src/repository/in-memory/resource.ts @@ -1,9 +1,7 @@ import type { Tx } from "@ctrlplane/db"; import type { FullResource } from "@ctrlplane/events"; -import _ from "lodash"; -import { isPresent } from "ts-is-present"; -import { and, eq, isNull } from "@ctrlplane/db"; +import { eq } from "@ctrlplane/db"; import { db as dbClient } from "@ctrlplane/db/client"; import * as schema from "@ctrlplane/db/schema"; @@ -14,39 +12,6 @@ type InMemoryResourceRepositoryOptions = { tx?: Tx; }; -const getInitialEntities = async (workspaceId: string) => { - const dbResult = await dbClient - .select() - .from(schema.resource) - .leftJoin( - schema.resourceMetadata, - eq(schema.resource.id, schema.resourceMetadata.resourceId), - ) - .where( - and( - eq(schema.resource.workspaceId, workspaceId), - isNull(schema.resource.deletedAt), - ), - ); - - return _.chain(dbResult) - .groupBy((row) => row.resource.id) - .map((group) => { - const [first] = group; - if (first == null) return null; - const { resource } = first; - const metadata = Object.fromEntries( - group - .map((r) => r.resource_metadata) - .filter(isPresent) - .map((m) => [m.key, m.value]), - ); - return { ...resource, metadata }; - }) - .value() - .filter(isPresent); -}; - export class InMemoryResourceRepository implements Repository { private entities: Map; private db: Tx; @@ -57,14 +22,6 @@ export class InMemoryResourceRepository implements Repository { this.entities.set(entity.id, entity); this.db = opts.tx ?? dbClient; } - static async create(workspaceId: string) { - const initialEntities = await getInitialEntities(workspaceId); - const inMemoryResourceRepository = new InMemoryResourceRepository({ - initialEntities, - tx: dbClient, - }); - return inMemoryResourceRepository; - } get(id: string) { return this.entities.get(id) ?? null; diff --git a/apps/event-queue/src/selector/in-memory/deployment-resource.ts b/apps/event-queue/src/selector/in-memory/deployment-resource.ts index 0a9104e1d..def7d3844 100644 --- a/apps/event-queue/src/selector/in-memory/deployment-resource.ts +++ b/apps/event-queue/src/selector/in-memory/deployment-resource.ts @@ -2,7 +2,7 @@ import type { FullResource } from "@ctrlplane/events"; import _ from "lodash"; import { isPresent } from "ts-is-present"; -import { and, eq, inArray, isNull } from "@ctrlplane/db"; +import { and, eq, inArray } from "@ctrlplane/db"; import { db as dbClient } from "@ctrlplane/db/client"; import * as schema from "@ctrlplane/db/schema"; import { logger } from "@ctrlplane/logger"; @@ -59,38 +59,7 @@ export class InMemoryDeploymentResourceSelector return this.matches; } - static async create(workspaceId: string) { - const allEntitiesDbResult = await dbClient - .select() - .from(schema.resource) - .leftJoin( - schema.resourceMetadata, - eq(schema.resource.id, schema.resourceMetadata.resourceId), - ) - .where( - and( - eq(schema.resource.workspaceId, workspaceId), - isNull(schema.resource.deletedAt), - ), - ); - - const allEntities = _.chain(allEntitiesDbResult) - .groupBy((row) => row.resource.id) - .map((group) => { - const [first] = group; - if (first == null) return null; - const { resource } = first; - const metadata = Object.fromEntries( - group - .map((r) => r.resource_metadata) - .filter(isPresent) - .map((m) => [m.key, m.value]), - ); - return { ...resource, metadata }; - }) - .value() - .filter(isPresent); - + static async create(workspaceId: string, initialEntities: FullResource[]) { const allSelectors = await dbClient .select() .from(schema.deployment) @@ -103,7 +72,7 @@ export class InMemoryDeploymentResourceSelector const inMemoryDeploymentResourceSelector = new InMemoryDeploymentResourceSelector({ - initialEntities: allEntities, + initialEntities, initialSelectors: allSelectors, }); diff --git a/apps/event-queue/src/selector/in-memory/environment-resource.ts b/apps/event-queue/src/selector/in-memory/environment-resource.ts index 6c9851506..cf5e517f3 100644 --- a/apps/event-queue/src/selector/in-memory/environment-resource.ts +++ b/apps/event-queue/src/selector/in-memory/environment-resource.ts @@ -2,7 +2,7 @@ import type { FullResource } from "@ctrlplane/events"; import _ from "lodash"; import { isPresent } from "ts-is-present"; -import { and, eq, inArray, isNull } from "@ctrlplane/db"; +import { and, eq, inArray } from "@ctrlplane/db"; import { db as dbClient } from "@ctrlplane/db/client"; import * as schema from "@ctrlplane/db/schema"; import { logger } from "@ctrlplane/logger"; @@ -59,38 +59,7 @@ export class InMemoryEnvironmentResourceSelector return this.matches; } - static async create(workspaceId: string) { - const allEntitiesDbResult = await dbClient - .select() - .from(schema.resource) - .leftJoin( - schema.resourceMetadata, - eq(schema.resource.id, schema.resourceMetadata.resourceId), - ) - .where( - and( - eq(schema.resource.workspaceId, workspaceId), - isNull(schema.resource.deletedAt), - ), - ); - - const allEntities = _.chain(allEntitiesDbResult) - .groupBy((row) => row.resource.id) - .map((group) => { - const [first] = group; - if (first == null) return null; - const { resource } = first; - const metadata = Object.fromEntries( - group - .map((r) => r.resource_metadata) - .filter(isPresent) - .map((m) => [m.key, m.value]), - ); - return { ...resource, metadata }; - }) - .value() - .filter(isPresent); - + static async create(workspaceId: string, initialEntities: FullResource[]) { const allSelectors = await dbClient .select() .from(schema.environment) @@ -103,7 +72,7 @@ export class InMemoryEnvironmentResourceSelector const inMemoryEnvironmentResourceSelector = new InMemoryEnvironmentResourceSelector({ - initialEntities: allEntities, + initialEntities, initialSelectors: allSelectors, }); diff --git a/apps/event-queue/src/workspace/workspace.ts b/apps/event-queue/src/workspace/workspace.ts index 24367567b..8372cbe89 100644 --- a/apps/event-queue/src/workspace/workspace.ts +++ b/apps/event-queue/src/workspace/workspace.ts @@ -1,3 +1,10 @@ +import type { FullResource } from "@ctrlplane/events"; +import _ from "lodash"; +import { isPresent } from "ts-is-present"; + +import { and, eq, isNull } from "@ctrlplane/db"; +import { db as dbClient } from "@ctrlplane/db/client"; +import * as schema from "@ctrlplane/db/schema"; import { logger } from "@ctrlplane/logger"; import type { ResourceRelationshipManager } from "../relationships/resource-relationship-manager.js"; @@ -40,7 +47,43 @@ type WorkspaceOptions = { repository: WorkspaceRepository; }; -const createSelectorManager = async (id: string) => { +const getInitialResources = async (id: string): Promise => { + const dbResult = await dbClient + .select() + .from(schema.resource) + .leftJoin( + schema.resourceMetadata, + eq(schema.resource.id, schema.resourceMetadata.resourceId), + ) + .where( + and( + eq(schema.resource.workspaceId, id), + isNull(schema.resource.deletedAt), + ), + ); + + return _.chain(dbResult) + .groupBy((row) => row.resource.id) + .map((group) => { + const [first] = group; + if (first == null) return null; + const { resource } = first; + const metadata = Object.fromEntries( + group + .map((r) => r.resource_metadata) + .filter(isPresent) + .map((m) => [m.key, m.value]), + ); + return { ...resource, metadata }; + }) + .value() + .filter(isPresent); +}; + +const createSelectorManager = async ( + id: string, + initialResources: FullResource[], +) => { log.info(`Creating selector manager for workspace ${id}`); const [ @@ -48,8 +91,8 @@ const createSelectorManager = async (id: string) => { environmentResourceSelector, policyTargetReleaseTargetSelector, ] = await Promise.all([ - InMemoryDeploymentResourceSelector.create(id), - InMemoryEnvironmentResourceSelector.create(id), + InMemoryDeploymentResourceSelector.create(id, initialResources), + InMemoryEnvironmentResourceSelector.create(id, initialResources), InMemoryPolicyTargetReleaseTargetSelector.create(id), ]); @@ -63,18 +106,19 @@ const createSelectorManager = async (id: string) => { }); }; -const createRepository = async (id: string) => { +const createRepository = async ( + id: string, + initialResources: FullResource[], +) => { log.info(`Creating repository for workspace ${id}`); const [ inMemoryReleaseTargetRepository, inMemoryReleaseRepository, - inMemoryResourceRepository, inMemoryVersionReleaseRepository, ] = await Promise.all([ InMemoryReleaseTargetRepository.create(id), InMemoryReleaseRepository.create(id), - InMemoryResourceRepository.create(id), InMemoryVersionReleaseRepository.create(id), ]); @@ -82,7 +126,9 @@ const createRepository = async (id: string) => { versionRepository: new DbVersionRepository(id), environmentRepository: new DbEnvironmentRepository(id), deploymentRepository: new DbDeploymentRepository(id), - resourceRepository: inMemoryResourceRepository, + resourceRepository: new InMemoryResourceRepository({ + initialEntities: initialResources, + }), resourceVariableRepository: new DbResourceVariableRepository(id), policyRepository: new DbPolicyRepository(id), jobAgentRepository: new DbJobAgentRepository(id), @@ -106,9 +152,10 @@ const createRepository = async (id: string) => { export class Workspace { static async load(id: string) { + const initialResources = await getInitialResources(id); const [selectorManager, repository] = await Promise.all([ - createSelectorManager(id), - createRepository(id), + createSelectorManager(id, initialResources), + createRepository(id, initialResources), ]); const ws = new Workspace({ id, selectorManager, repository });