mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Don't initialize database on file require (#6003)
This commit is contained in:
@@ -1,76 +1,98 @@
|
||||
import SchemaInspector from '@directus/schema';
|
||||
import dotenv from 'dotenv';
|
||||
import { knex, Knex } from 'knex';
|
||||
import path from 'path';
|
||||
import { performance } from 'perf_hooks';
|
||||
import env from '../env';
|
||||
import logger from '../logger';
|
||||
import { getConfigFromEnv } from '../utils/get-config-from-env';
|
||||
import { validateEnv } from '../utils/validate-env';
|
||||
|
||||
dotenv.config({ path: path.resolve(__dirname, '../../', '.env') });
|
||||
let database: Knex | null = null;
|
||||
let inspector: ReturnType<typeof SchemaInspector> | null = null;
|
||||
|
||||
const connectionConfig: Record<string, any> = getConfigFromEnv('DB_', [
|
||||
'DB_CLIENT',
|
||||
'DB_SEARCH_PATH',
|
||||
'DB_CONNECTION_STRING',
|
||||
'DB_POOL',
|
||||
]);
|
||||
|
||||
const poolConfig = getConfigFromEnv('DB_POOL');
|
||||
|
||||
const requiredKeys = ['DB_CLIENT'];
|
||||
|
||||
if (env.DB_CLIENT && env.DB_CLIENT === 'sqlite3') {
|
||||
requiredKeys.push('DB_FILENAME');
|
||||
} else if (env.DB_CLIENT && env.DB_CLIENT === 'oracledb') {
|
||||
requiredKeys.push('DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING');
|
||||
} else {
|
||||
if (env.DB_CLIENT === 'pg') {
|
||||
if (!env.DB_CONNECTION_STRING) {
|
||||
requiredKeys.push('DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USER');
|
||||
}
|
||||
} else {
|
||||
requiredKeys.push('DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USER', 'DB_PASSWORD');
|
||||
export default function getDatabase() {
|
||||
if (database) {
|
||||
return database;
|
||||
}
|
||||
}
|
||||
|
||||
validateEnv(requiredKeys);
|
||||
const connectionConfig: Record<string, any> = getConfigFromEnv('DB_', [
|
||||
'DB_CLIENT',
|
||||
'DB_SEARCH_PATH',
|
||||
'DB_CONNECTION_STRING',
|
||||
'DB_POOL',
|
||||
]);
|
||||
|
||||
const knexConfig: Knex.Config = {
|
||||
client: env.DB_CLIENT,
|
||||
searchPath: env.DB_SEARCH_PATH,
|
||||
connection: env.DB_CONNECTION_STRING || connectionConfig,
|
||||
log: {
|
||||
warn: (msg) => logger.warn(msg),
|
||||
error: (msg) => logger.error(msg),
|
||||
deprecate: (msg) => logger.info(msg),
|
||||
debug: (msg) => logger.debug(msg),
|
||||
},
|
||||
pool: poolConfig,
|
||||
};
|
||||
const poolConfig = getConfigFromEnv('DB_POOL');
|
||||
|
||||
if (env.DB_CLIENT === 'sqlite3') {
|
||||
knexConfig.useNullAsDefault = true;
|
||||
poolConfig.afterCreate = (conn: any, cb: any) => {
|
||||
conn.run('PRAGMA foreign_keys = ON', cb);
|
||||
const requiredEnvVars = ['DB_CLIENT'];
|
||||
|
||||
if (env.DB_CLIENT && env.DB_CLIENT === 'sqlite3') {
|
||||
requiredEnvVars.push('DB_FILENAME');
|
||||
} else if (env.DB_CLIENT && env.DB_CLIENT === 'oracledb') {
|
||||
requiredEnvVars.push('DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING');
|
||||
} else {
|
||||
if (env.DB_CLIENT === 'pg') {
|
||||
if (!env.DB_CONNECTION_STRING) {
|
||||
requiredEnvVars.push('DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USER');
|
||||
}
|
||||
} else {
|
||||
requiredEnvVars.push('DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USER', 'DB_PASSWORD');
|
||||
}
|
||||
}
|
||||
|
||||
validateEnv(requiredEnvVars);
|
||||
|
||||
const knexConfig: Knex.Config = {
|
||||
client: env.DB_CLIENT,
|
||||
searchPath: env.DB_SEARCH_PATH,
|
||||
connection: env.DB_CONNECTION_STRING || connectionConfig,
|
||||
log: {
|
||||
warn: (msg) => logger.warn(msg),
|
||||
error: (msg) => logger.error(msg),
|
||||
deprecate: (msg) => logger.info(msg),
|
||||
debug: (msg) => logger.debug(msg),
|
||||
},
|
||||
pool: poolConfig,
|
||||
};
|
||||
|
||||
if (env.DB_CLIENT === 'sqlite3') {
|
||||
knexConfig.useNullAsDefault = true;
|
||||
poolConfig.afterCreate = (conn: any, cb: any) => {
|
||||
conn.run('PRAGMA foreign_keys = ON', cb);
|
||||
};
|
||||
}
|
||||
|
||||
database = knex(knexConfig);
|
||||
|
||||
const times: Record<string, number> = {};
|
||||
|
||||
database
|
||||
.on('query', (queryInfo) => {
|
||||
times[queryInfo.__knexUid] = performance.now();
|
||||
})
|
||||
.on('query-response', (response, queryInfo) => {
|
||||
const delta = performance.now() - times[queryInfo.__knexUid];
|
||||
logger.trace(`[${delta.toFixed(3)}ms] ${queryInfo.sql} [${queryInfo.bindings.join(', ')}]`);
|
||||
delete times[queryInfo.__knexUid];
|
||||
});
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
const database = knex(knexConfig);
|
||||
export function getSchemaInspector() {
|
||||
if (inspector) {
|
||||
return inspector;
|
||||
}
|
||||
|
||||
const times: Record<string, number> = {};
|
||||
const database = getDatabase();
|
||||
|
||||
database
|
||||
.on('query', (queryInfo) => {
|
||||
times[queryInfo.__knexUid] = performance.now();
|
||||
})
|
||||
.on('query-response', (response, queryInfo) => {
|
||||
const delta = performance.now() - times[queryInfo.__knexUid];
|
||||
logger.trace(`[${delta.toFixed(3)}ms] ${queryInfo.sql} [${queryInfo.bindings.join(', ')}]`);
|
||||
});
|
||||
inspector = SchemaInspector(database);
|
||||
|
||||
return inspector;
|
||||
}
|
||||
|
||||
export async function hasDatabaseConnection(): Promise<boolean> {
|
||||
const database = getDatabase();
|
||||
|
||||
try {
|
||||
if (env.DB_CLIENT === 'oracledb') {
|
||||
await database.raw('select 1 from DUAL');
|
||||
@@ -93,13 +115,11 @@ export async function validateDBConnection(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
export const schemaInspector = SchemaInspector(database);
|
||||
|
||||
export async function isInstalled(): Promise<boolean> {
|
||||
const inspector = getSchemaInspector();
|
||||
|
||||
// The existence of a directus_collections table alone isn't a "proper" check to see if everything
|
||||
// is installed correctly of course, but it's safe enough to assume that this collection only
|
||||
// exists when using the installer CLI.
|
||||
return await schemaInspector.hasTable('directus_collections');
|
||||
return await inspector.hasTable('directus_collections');
|
||||
}
|
||||
|
||||
export default database;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Knex } from 'knex';
|
||||
import SchemaInspector from 'knex-schema-inspector';
|
||||
import { schemaInspector } from '..';
|
||||
import logger from '../../logger';
|
||||
import { RelationMeta } from '../../types';
|
||||
|
||||
@@ -22,8 +21,8 @@ export async function up(knex: Knex): Promise<void> {
|
||||
for (const constraint of constraintsToAdd) {
|
||||
if (!constraint.one_collection) continue;
|
||||
|
||||
const currentPrimaryKeyField = await schemaInspector.primary(constraint.many_collection);
|
||||
const relatedPrimaryKeyField = await schemaInspector.primary(constraint.one_collection);
|
||||
const currentPrimaryKeyField = await inspector.primary(constraint.many_collection);
|
||||
const relatedPrimaryKeyField = await inspector.primary(constraint.one_collection);
|
||||
if (!currentPrimaryKeyField || !relatedPrimaryKeyField) continue;
|
||||
|
||||
const rowsWithIllegalFKValues = await knex
|
||||
@@ -67,8 +66,8 @@ export async function up(knex: Knex): Promise<void> {
|
||||
// to `unsigned`, but defaults `.integer()` to `int`. This means that created m2o fields
|
||||
// have the wrong type. This step will force the m2o `int` field into `unsigned`, but only
|
||||
// if both types are integers, and only if we go from `int` to `int unsigned`.
|
||||
const columnInfo = await schemaInspector.columnInfo(constraint.many_collection, constraint.many_field);
|
||||
const relatedColumnInfo = await schemaInspector.columnInfo(constraint.one_collection!, relatedPrimaryKeyField);
|
||||
const columnInfo = await inspector.columnInfo(constraint.many_collection, constraint.many_field);
|
||||
const relatedColumnInfo = await inspector.columnInfo(constraint.one_collection!, relatedPrimaryKeyField);
|
||||
|
||||
try {
|
||||
await knex.schema.alterTable(constraint.many_collection, (table) => {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Item, Query, SchemaOverview } from '../types';
|
||||
import { AST, FieldNode, NestedCollectionNode } from '../types/ast';
|
||||
import applyQuery from '../utils/apply-query';
|
||||
import { toArray } from '../utils/to-array';
|
||||
import database from './index';
|
||||
import getDatabase from './index';
|
||||
|
||||
type RunASTOptions = {
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ export default async function runAST(
|
||||
): Promise<null | Item | Item[]> {
|
||||
const ast = cloneDeep(originalAST);
|
||||
|
||||
const knex = options?.knex || database;
|
||||
const knex = options?.knex || getDatabase();
|
||||
|
||||
if (ast.type === 'm2a') {
|
||||
const results: { [collection: string]: null | Item | Item[] } = {};
|
||||
|
||||
Reference in New Issue
Block a user