Files
speckle-server/packages/server/modules/shared/command.ts
T
Kristaps Fabians Geikins bde148f286 chore(server): migrating fully to ESM (#5042)
* wip

* some extra fixes

* stuff kinda works?

* need to figure out mocks

* need to figure out mocks

* fix db listener

* gqlgen fix

* minor gqlgen watch adjustment

* lint fixes

* delete old codegen file

* converting migrations to ESM

* getModuleDIrectory

* vitest sort of works

* added back ts-vitest

* resolve gql double load

* fixing test timeout configs

* TSC lint fix

* fix automate tests

* moar debugging

* debugging

* more debugging

* codegen update

* server works

* yargs migrated

* chore(server): getting rid of global mocks for Server ESM (#5046)

* got rid of email mock

* got rid of comment mocks

* got rid of multi region mocks

* got rid of stripe mock

* admin override mock updated

* removed final mock

* fixing import.meta.resolve calls

* another import.meta.resolve fix

* added requested test

* nyc ESM fix

* removed unneeded deps + linting

* yarn lock forgot to commit

* tryna fix flakyness

* email capture util fix

* sendEmail fix

* fix TSX check

* sender transporter fix + CR comments

* merge main fix

* test fixx

* circleci fix

* gqlgen bigint fix

* error formatter fix

* more error formatting improvements

* esmloader added to Dockerfile

* more dockerfile fixes

* bg jobs fix
2025-07-14 10:26:19 +03:00

123 lines
3.2 KiB
TypeScript

import { mainDb } from '@/db/knex'
import { withTransaction } from '@/modules/shared/helpers/dbHelper'
import {
EmitArg,
EventBus,
EventBusEmit,
getEventBus
} from '@/modules/shared/services/eventBus'
import { withOperationLogging } from '@/observability/domain/businessLogging'
import { MaybeAsync } from '@speckle/shared'
import { Knex } from 'knex'
import { isBoolean } from 'lodash-es'
import { Logger } from 'pino'
/**
* @deprecated asOperation does this and more. Also many usages of commandFactory are broken
* in the sense that they're not actually using the transaction correctly
*/
export const commandFactory =
<TOperation extends (...args: Parameters<TOperation>) => ReturnType<TOperation>>({
db,
eventBus,
operationFactory
}: {
db: Knex
eventBus?: EventBus
operationFactory: (arg: { db: Knex; trx: Knex; emit: EventBusEmit }) => TOperation
}) =>
async (...args: Parameters<TOperation>): Promise<Awaited<ReturnType<TOperation>>> => {
const events: EmitArg[] = []
const emit: EventBusEmit = async ({ eventName, payload }) => {
events.push({ eventName, payload })
}
const trx = await db.transaction()
try {
const result = await operationFactory({ db, trx, emit })(...args)
await trx.commit()
if (eventBus) {
for (const event of events) {
await eventBus.emit(event)
}
}
return result as Awaited<ReturnType<TOperation>>
} catch (err) {
trx.rollback()
throw err
}
}
/**
* Adds logging & transaction support to an operation
*/
export const asOperation = async <T>(
operation: (args: { db: Knex; emit: EventBusEmit }) => MaybeAsync<T>,
params: {
name: string
logger: Logger
description?: string
/**
* Defaults to main DB
*/
db?: Knex
/**
* Defaults to main event bus
*/
eventBus?: EventBus
/**
* Whether to treat the operation as a transaction. That makes the injected DB a knex transaction
* and also collects eventBus events to be emitted at the end of the operation.
*
* Can be a bool or an obj describing how the trx should be set up
*/
transaction?:
| boolean
| {
db: true // db trx can't be turned off, only the eventBus trx can
eventBus: boolean
}
}
): Promise<T> => {
const {
db = mainDb,
eventBus = getEventBus(),
logger,
name,
description,
transaction
} = params
return await withOperationLogging(
async () => {
if (!transaction) {
return await operation({ db, emit: eventBus.emit })
}
const events: EmitArg[] = []
const emit: EventBusEmit = async ({ eventName, payload }) => {
events.push({ eventName, payload })
}
const trxRet = await withTransaction(
async ({ trx }) => {
const useEmitTrx = isBoolean(transaction) ? transaction : transaction.eventBus
return await operation({ db: trx, emit: useEmitTrx ? emit : eventBus.emit })
},
{ db }
)
for (const event of events) {
await eventBus.emit(event)
}
return trxRet
},
{
logger,
operationName: name,
operationDescription: description
}
)
}