Files
speckle-server/packages/server/knexfile.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

118 lines
3.8 KiB
TypeScript

/* eslint-disable no-restricted-imports */
/* istanbul ignore file */
import { packageRoot } from './bootstrap.js'
import fs from 'fs'
import path from 'path'
import {
isTestEnv,
ignoreMissingMigrations,
postgresMaxConnections,
isDevOrTestEnv,
postgresConnectionAcquireTimeoutMillis,
postgresConnectionCreateTimeoutMillis,
knexAsyncStackTracesEnabled
} from '@/modules/shared/helpers/envHelper'
import { dbLogger as logger } from '@/observability/logging'
import { Knex } from 'knex'
import {
createKnexConfig,
configureKnexClient,
KnexConfigArgs,
RegionServerConfig
} from '@speckle/shared/environment/db'
function walk(dir: string) {
let results: string[] = []
const list = fs.readdirSync(dir)
list.forEach(function (file) {
const fullFile = path.join(dir, file)
const stat = fs.statSync(fullFile)
if (stat && stat.isDirectory()) {
if (file === 'migrations') results.push(fullFile)
else results = results.concat(walk(fullFile))
}
})
return results
}
// Always read migrations from /dist, otherwise we risk the same migration being applied twice
// once with the .ts extension and the 2nd time with the .js one
// The only exception is when running tests in the test DB, cause the stakes are way lower there and we always
// run them through ts-node anyway, so it doesn't make sense forcing the app to be built
const migrationModulesDir = path.resolve(
packageRoot,
isTestEnv() ? './modules' : './dist/modules'
)
const migrationDirsExist = fs.existsSync(migrationModulesDir)
if (!migrationDirsExist && !ignoreMissingMigrations()) {
throw new Error('App must be built into /dist, to enable work with migrations')
}
const migrationDirs = migrationDirsExist ? walk(migrationModulesDir) : []
// this is for readability, many users struggle to set the postgres connection uri
// in the env variables. This way its a bit easier to understand, also backward compatible.
const env = process.env
let connectionUri
if (env.POSTGRES_USER && env.POSTGRES_PASSWORD) {
connectionUri = `postgres://${encodeURIComponent(
env.POSTGRES_USER
)}:${encodeURIComponent(env.POSTGRES_PASSWORD)}@${
env.POSTGRES_URL
}/${encodeURIComponent(env.POSTGRES_DB as string)}`
} else {
connectionUri = env.POSTGRES_URL
}
// NOTE: fixes time pagination, breaks graphql DateTime parsing :/
// The pg driver (& knex?) parses dates for us and it breaks precision. This
// disables any date parsing and we guarantee values are returned as strings.
// const types = require('pg').types
// const TIMESTAMPTZ_OID = 1184
// const TIMESTAMP_OID = 1114
// types.setTypeParser(TIMESTAMPTZ_OID, (val) => val)
// types.setTypeParser(TIMESTAMP_OID, (val) => val)
// Another NOTE:
// this is why the new datetime columns are created like this
// table.specificType('createdAt', 'TIMESTAMPTZ(3)').defaultTo(knex.fn.now())
const configArgs: KnexConfigArgs = {
migrationDirs,
isTestEnv: isTestEnv(),
isDevOrTestEnv: isDevOrTestEnv(),
applicationName: 'speckle_server',
logger,
maxConnections: postgresMaxConnections(),
connectionAcquireTimeoutMillis: postgresConnectionAcquireTimeoutMillis(),
connectionCreateTimeoutMillis: postgresConnectionCreateTimeoutMillis(),
asyncStackTraces: knexAsyncStackTracesEnabled()
}
const config: Record<string, Knex.Config> = {
test: {
...createKnexConfig({
connectionString: connectionUri || 'postgres://127.0.0.1/speckle2_test',
...configArgs
})
},
development: {
...createKnexConfig({
connectionString: connectionUri || 'postgres://127.0.0.1/speckle2_dev',
...configArgs
})
},
production: {
...createKnexConfig({
connectionString: connectionUri,
...configArgs
})
}
}
export const configureClient = (config: Pick<RegionServerConfig, 'postgres'>) => {
return configureKnexClient(config, configArgs)
}
export default config