diff --git a/packages/server/modules/automate/domain/operations.ts b/packages/server/modules/automate/domain/operations.ts index 1c9be6aa8..3c267d5a0 100644 --- a/packages/server/modules/automate/domain/operations.ts +++ b/packages/server/modules/automate/domain/operations.ts @@ -7,6 +7,8 @@ import { InsertableAutomationRevision } from '@/modules/automate/repositories/au import { AuthCodePayload } from '@/modules/automate/services/authCode' import { ProjectAutomationCreateInput } from '@/modules/core/graph/generated/graphql' import { ContextResourceAccessRules } from '@/modules/core/helpers/token' +import { Nullable } from '@speckle/shared' +import { SetRequired } from 'type-fest' export type StoreAutomation = ( automation: AutomationRecord @@ -20,6 +22,20 @@ export type StoreAutomationRevision = ( revision: InsertableAutomationRevision ) => Promise +export type GetAutomations = (params: { + automationIds: string[] + projectId?: string +}) => Promise + +export type GetAutomation = (params: { + automationId: string + projectId?: string +}) => Promise> + +export type UpdateAutomation = ( + automation: SetRequired, 'id'> +) => Promise + export type CreateStoredAuthCode = ( params: Omit ) => Promise diff --git a/packages/server/modules/automate/graph/resolvers/automate.ts b/packages/server/modules/automate/graph/resolvers/automate.ts index 885a6c566..3243e2b28 100644 --- a/packages/server/modules/automate/graph/resolvers/automate.ts +++ b/packages/server/modules/automate/graph/resolvers/automate.ts @@ -11,7 +11,7 @@ import { } from '@/modules/automate/clients/executionEngine' import { GetProjectAutomationsParams, - getAutomation, + getAutomationFactory, getAutomationRunsItems, getAutomationRunsTotalCount, getAutomationTriggerDefinitions, @@ -24,8 +24,8 @@ import { storeAutomationFactory, storeAutomationRevisionFactory, storeAutomationTokenFactory, + updateAutomationFactory, updateAutomationRun, - updateAutomation as updateDbAutomation, upsertAutomationFunctionRun } from '@/modules/automate/repositories/automations' import { @@ -33,7 +33,7 @@ import { createAutomationRevision, createTestAutomationFactory, getAutomationsStatus, - updateAutomation + validateAndUpdateAutomationFactory } from '@/modules/automate/services/automationManagement' import { AuthCodePayloadAction, @@ -111,6 +111,8 @@ const { FF_AUTOMATE_MODULE_ENABLED } = getFeatureFlags() const storeAutomation = storeAutomationFactory({ db }) const storeAutomationToken = storeAutomationTokenFactory({ db }) const storeAutomationRevision = storeAutomationRevisionFactory({ db }) +const getAutomation = getAutomationFactory({ db }) +const updateDbAutomation = updateAutomationFactory({ db }) export = (FF_AUTOMATE_MODULE_ENABLED ? { @@ -481,7 +483,7 @@ export = (FF_AUTOMATE_MODULE_ENABLED ).automation }, async update(parent, { input }, ctx) { - const update = updateAutomation({ + const update = validateAndUpdateAutomationFactory({ getAutomation, updateAutomation: updateDbAutomation }) diff --git a/packages/server/modules/automate/index.ts b/packages/server/modules/automate/index.ts index b67cd5d2f..2a7c33efd 100644 --- a/packages/server/modules/automate/index.ts +++ b/packages/server/modules/automate/index.ts @@ -9,9 +9,9 @@ import { getActiveTriggerDefinitions, getAutomationRunFullTriggers, getFullAutomationRevisionMetadata, - getAutomation, getAutomationRevision, - getFullAutomationRunById + getFullAutomationRunById, + getAutomationFactory } from '@/modules/automate/repositories/automations' import { Scopes } from '@speckle/shared' import { registerOrUpdateScopeFactory } from '@/modules/shared/repositories/scopes' @@ -80,6 +80,7 @@ const initializeEventListeners = () => { getCommit, getFullAutomationRunById }) + const getAutomation = getAutomationFactory({ db }) const quitters = [ VersionsEmitter.listen( diff --git a/packages/server/modules/automate/repositories/automations.ts b/packages/server/modules/automate/repositories/automations.ts index 0dc323e16..89ceeefb9 100644 --- a/packages/server/modules/automate/repositories/automations.ts +++ b/packages/server/modules/automate/repositories/automations.ts @@ -1,7 +1,10 @@ import { + GetAutomation, + GetAutomations, StoreAutomation, StoreAutomationRevision, - StoreAutomationToken + StoreAutomationToken, + UpdateAutomation } from '@/modules/automate/domain/operations' import { AutomationRecord, @@ -409,47 +412,49 @@ export async function getAutomationToken( return token || null } -export async function getAutomations(params: { - automationIds: string[] - projectId?: string -}) { - const { automationIds, projectId } = params - if (!automationIds.length) return [] +export const getAutomationsFactory = + (deps: { db: Knex }): GetAutomations => + async (params: { automationIds: string[]; projectId?: string }) => { + const { automationIds, projectId } = params + if (!automationIds.length) return [] - const q = Automations.knex() - .select() - .whereIn(Automations.col.id, automationIds) + const q = tables + .automations(deps.db) + .select() + .whereIn(Automations.col.id, automationIds) - if (projectId?.length) { - q.andWhere(Automations.col.projectId, projectId) + if (projectId?.length) { + q.andWhere(Automations.col.projectId, projectId) + } + + return await q } - return await q -} +export const getAutomationFactory = + (deps: { db: Knex }): GetAutomation => + async (params: { automationId: string; projectId?: string }) => { + const { automationId, projectId } = params + return ( + ( + await getAutomationsFactory(deps)({ automationIds: [automationId], projectId }) + )?.[0] || null + ) + } -export async function getAutomation(params: { - automationId: string - projectId?: string -}): Promise> { - const { automationId, projectId } = params - return ( - (await getAutomations({ automationIds: [automationId], projectId }))?.[0] || null - ) -} +export const updateAutomationFactory = + (deps: { db: Knex }): UpdateAutomation => + async (automation: SetRequired, 'id'>) => { + const [ret] = await tables + .automations(deps.db) + .where(Automations.col.id, automation.id) + .update({ + ...pick(automation, Automations.withoutTablePrefix.cols), + [Automations.withoutTablePrefix.col.updatedAt]: new Date() + }) + .returning('*') -export async function updateAutomation( - automation: SetRequired, 'id'> -) { - const [ret] = await Automations.knex() - .where(Automations.col.id, automation.id) - .update({ - ...pick(automation, Automations.withoutTablePrefix.cols), - [Automations.withoutTablePrefix.col.updatedAt]: new Date() - }) - .returning('*') - - return ret -} + return ret + } export async function getAutomationTriggerDefinitions< T extends AutomationTriggerType = AutomationTriggerType diff --git a/packages/server/modules/automate/services/automationManagement.ts b/packages/server/modules/automate/services/automationManagement.ts index e68cad003..b44330087 100644 --- a/packages/server/modules/automate/services/automationManagement.ts +++ b/packages/server/modules/automate/services/automationManagement.ts @@ -2,9 +2,7 @@ import { InsertableAutomationRevision, InsertableAutomationRevisionFunction, InsertableAutomationRevisionTrigger, - getAutomation, - getLatestVersionAutomationRuns, - updateAutomation as updateDbAutomation + getLatestVersionAutomationRuns } from '@/modules/automate/repositories/automations' import { getServerOrigin } from '@/modules/shared/helpers/envHelper' import cryptoRandomString from 'crypto-random-string' @@ -51,10 +49,12 @@ import { validateAutomationName } from '@/modules/automate/utils/automationConfi import { CreateAutomation, CreateStoredAuthCode, + GetAutomation, GetEncryptionKeyPair, StoreAutomation, StoreAutomationRevision, - StoreAutomationToken + StoreAutomationToken, + UpdateAutomation } from '@/modules/automate/domain/operations' export type CreateAutomationDeps = { @@ -243,13 +243,13 @@ export const createTestAutomationFactory = return automationRecord } -export type UpdateAutomationDeps = { - getAutomation: typeof getAutomation - updateAutomation: typeof updateDbAutomation +export type ValidateAndUpdateAutomationDeps = { + getAutomation: GetAutomation + updateAutomation: UpdateAutomation } -export const updateAutomation = - (deps: UpdateAutomationDeps) => +export const validateAndUpdateAutomationFactory = + (deps: ValidateAndUpdateAutomationDeps) => async (params: { input: ProjectAutomationUpdateInput userId: string @@ -383,7 +383,7 @@ const validateNewRevisionFunctions = } export type CreateAutomationRevisionDeps = { - getAutomation: typeof getAutomation + getAutomation: GetAutomation storeAutomationRevision: StoreAutomationRevision getEncryptionKeyPair: GetEncryptionKeyPair getFunctionInputDecryptor: ReturnType diff --git a/packages/server/modules/automate/services/trigger.ts b/packages/server/modules/automate/services/trigger.ts index 471b20768..58913d040 100644 --- a/packages/server/modules/automate/services/trigger.ts +++ b/packages/server/modules/automate/services/trigger.ts @@ -1,7 +1,6 @@ import { InsertableAutomationRun, getActiveTriggerDefinitions, - getAutomation, getFullAutomationRevisionMetadata, getAutomationToken, getAutomationTriggerDefinitions, @@ -43,10 +42,13 @@ import { automateLogger } from '@/logging/logging' import { getFunctionInputDecryptor } from '@/modules/automate/services/encryption' import { LibsodiumEncryptionError } from '@/modules/shared/errors/encryption' import { AutomateRunsEmitter } from '@/modules/automate/events/runs' -import { GetEncryptionKeyPairFor } from '@/modules/automate/domain/operations' +import { + GetAutomation, + GetEncryptionKeyPairFor +} from '@/modules/automate/domain/operations' export type OnModelVersionCreateDeps = { - getAutomation: typeof getAutomation + getAutomation: GetAutomation getAutomationRevision: typeof getAutomationRevision getTriggers: typeof getActiveTriggerDefinitions triggerFunction: ReturnType @@ -440,7 +442,7 @@ async function composeTriggerData(params: { export type ManuallyTriggerAutomationDeps = { getAutomationTriggerDefinitions: typeof getAutomationTriggerDefinitions - getAutomation: typeof getAutomation + getAutomation: GetAutomation getBranchLatestCommits: typeof getBranchLatestCommits triggerFunction: ReturnType } @@ -512,7 +514,7 @@ export const manuallyTriggerAutomation = } export type CreateTestAutomationRunDeps = { - getAutomation: typeof getAutomation + getAutomation: GetAutomation getLatestAutomationRevision: typeof getLatestAutomationRevision getFullAutomationRevisionMetadata: typeof getFullAutomationRevisionMetadata } & CreateAutomationRunDataDeps diff --git a/packages/server/modules/automate/tests/automations.spec.ts b/packages/server/modules/automate/tests/automations.spec.ts index 6260cab83..f29432abc 100644 --- a/packages/server/modules/automate/tests/automations.spec.ts +++ b/packages/server/modules/automate/tests/automations.spec.ts @@ -3,10 +3,10 @@ import { AutomationUpdateError } from '@/modules/automate/errors/management' import { - getAutomation, - updateAutomation as updateDbAutomation + getAutomationFactory, + updateAutomationFactory } from '@/modules/automate/repositories/automations' -import { updateAutomation } from '@/modules/automate/services/automationManagement' +import { validateAndUpdateAutomationFactory } from '@/modules/automate/services/automationManagement' import { AuthCodePayloadAction, createStoredAuthCodeFactory @@ -42,6 +42,7 @@ import { Automate, Roles } from '@speckle/shared' import { expect } from 'chai' import { times } from 'lodash' import { getFeatureFlags } from '@/modules/shared/helpers/envHelper' +import { db } from '@/db/knex' /** * TODO: Extra test ideas @@ -52,7 +53,9 @@ import { getFeatureFlags } from '@/modules/shared/helpers/envHelper' const { FF_AUTOMATE_MODULE_ENABLED } = getFeatureFlags() const buildAutomationUpdate = () => { - const update = updateAutomation({ + const getAutomation = getAutomationFactory({ db }) + const updateDbAutomation = updateAutomationFactory({ db }) + const update = validateAndUpdateAutomationFactory({ getAutomation, updateAutomation: updateDbAutomation }) diff --git a/packages/server/modules/automate/tests/trigger.spec.ts b/packages/server/modules/automate/tests/trigger.spec.ts index 80dc2ecb1..2510890b4 100644 --- a/packages/server/modules/automate/tests/trigger.spec.ts +++ b/packages/server/modules/automate/tests/trigger.spec.ts @@ -33,18 +33,18 @@ import { import { createTestCommit } from '@/test/speckle-helpers/commitHelper' import { InsertableAutomationRun, - getAutomation, getFullAutomationRunById, getAutomationTriggerDefinitions, getFunctionRun, - updateAutomation, updateAutomationRevision, updateAutomationRun, upsertAutomationRun, upsertAutomationFunctionRun, storeAutomationFactory, storeAutomationTokenFactory, - storeAutomationRevisionFactory + storeAutomationRevisionFactory, + getAutomationFactory, + updateAutomationFactory } from '@/modules/automate/repositories/automations' import { beforeEachContext, truncateTables } from '@/test/hooks' import { Automate } from '@speckle/shared' @@ -78,6 +78,8 @@ const { FF_AUTOMATE_MODULE_ENABLED } = getFeatureFlags() const storeAutomation = storeAutomationFactory({ db }) const storeAutomationToken = storeAutomationTokenFactory({ db }) const storeAutomationRevision = storeAutomationRevisionFactory({ db }) +const getAutomation = getAutomationFactory({ db }) +const updateAutomation = updateAutomationFactory({ db }) ;(FF_AUTOMATE_MODULE_ENABLED ? describe : describe.skip)( 'Automate triggers @automate', diff --git a/packages/server/modules/core/loaders.ts b/packages/server/modules/core/loaders.ts index 859402df2..2ba89850a 100644 --- a/packages/server/modules/core/loaders.ts +++ b/packages/server/modules/core/loaders.ts @@ -63,7 +63,7 @@ import { import { getAutomationRevisions, getAutomationRunsTriggers, - getAutomations, + getAutomationsFactory, getFunctionAutomationCounts, getLatestAutomationRevisions, getRevisionsFunctions, @@ -90,6 +90,7 @@ const simpleTupleCacheKey = (key: [string, string]) => `${key[0]}:${key[1]}` const getStreamPendingModels = getStreamPendingModelsFactory({ db }) const getAppScopes = getAppScopesFactory({ db }) +const getAutomations = getAutomationsFactory({ db }) /** * TODO: Lazy load DataLoaders to reduce memory usage