2023-07-19 16:35:50 +02:00
|
|
|
import type { Knex } from 'knex';
|
|
|
|
|
|
|
|
import { Dialect, getDialect } from './dialects';
|
|
|
|
import { createSchemaProvider } from './schema';
|
2023-09-12 16:26:42 +02:00
|
|
|
import { createMetadata, Metadata } from './metadata';
|
2023-07-19 16:35:50 +02:00
|
|
|
import { createEntityManager } from './entity-manager';
|
|
|
|
import { createMigrationsProvider } from './migrations';
|
|
|
|
import { createLifecyclesProvider } from './lifecycles';
|
|
|
|
import { createConnection } from './connection';
|
|
|
|
import * as errors from './errors';
|
2023-09-12 13:26:59 +02:00
|
|
|
import { Callback, transactionCtx } from './transaction-context';
|
2021-06-17 16:17:15 +02:00
|
|
|
|
|
|
|
// TODO: move back into strapi
|
2023-07-19 16:35:50 +02:00
|
|
|
import { transformContentTypes } from './utils/content-types';
|
|
|
|
import { validateDatabase } from './validations';
|
2023-09-20 11:46:13 +02:00
|
|
|
import { Model } from './types';
|
2023-07-19 16:35:50 +02:00
|
|
|
|
|
|
|
interface Settings {
|
|
|
|
forceMigration?: boolean;
|
|
|
|
runMigrations?: boolean;
|
|
|
|
[key: string]: unknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface DatabaseConfig {
|
|
|
|
connection: Knex.Config;
|
2023-09-12 21:47:42 +02:00
|
|
|
settings: Settings;
|
2023-09-20 11:46:13 +02:00
|
|
|
models: Model[];
|
2023-07-19 16:35:50 +02:00
|
|
|
}
|
2021-05-10 15:36:09 +02:00
|
|
|
|
|
|
|
class Database {
|
2023-07-19 16:35:50 +02:00
|
|
|
connection: Knex;
|
|
|
|
|
|
|
|
dialect: Dialect;
|
|
|
|
|
|
|
|
config: DatabaseConfig;
|
|
|
|
|
2023-09-12 16:26:42 +02:00
|
|
|
metadata: Metadata;
|
2023-07-19 16:35:50 +02:00
|
|
|
|
2023-09-14 17:35:36 +02:00
|
|
|
schema: ReturnType<typeof createSchemaProvider>;
|
2023-07-19 16:35:50 +02:00
|
|
|
|
2023-09-14 17:35:36 +02:00
|
|
|
migrations: ReturnType<typeof createMigrationsProvider>;
|
2023-07-19 16:35:50 +02:00
|
|
|
|
2023-09-14 17:35:36 +02:00
|
|
|
lifecycles: ReturnType<typeof createLifecyclesProvider>;
|
2023-07-19 16:35:50 +02:00
|
|
|
|
2023-09-14 17:35:36 +02:00
|
|
|
entityManager: ReturnType<typeof createEntityManager>;
|
2023-07-19 16:35:50 +02:00
|
|
|
|
|
|
|
static transformContentTypes: typeof transformContentTypes;
|
|
|
|
|
|
|
|
static init: (config: DatabaseConfig) => Promise<Database>;
|
|
|
|
|
|
|
|
constructor(config: DatabaseConfig) {
|
2021-06-02 15:53:22 +02:00
|
|
|
this.metadata = createMetadata(config.models);
|
2021-05-18 10:16:03 +02:00
|
|
|
|
2021-11-10 19:42:03 +01:00
|
|
|
this.config = {
|
2023-09-12 21:47:42 +02:00
|
|
|
...config,
|
2021-11-10 19:42:03 +01:00
|
|
|
settings: {
|
2021-11-15 09:41:00 +01:00
|
|
|
forceMigration: true,
|
2022-12-13 19:30:55 +00:00
|
|
|
runMigrations: true,
|
2023-09-12 21:47:42 +02:00
|
|
|
...(config.settings ?? {}),
|
2021-11-10 19:42:03 +01:00
|
|
|
},
|
|
|
|
};
|
2021-09-13 12:03:12 +02:00
|
|
|
|
2021-06-28 12:34:29 +02:00
|
|
|
this.dialect = getDialect(this);
|
2021-09-13 12:03:12 +02:00
|
|
|
this.dialect.configure();
|
|
|
|
|
2021-11-10 19:42:03 +01:00
|
|
|
this.connection = createConnection(this.config.connection);
|
2021-09-13 12:03:12 +02:00
|
|
|
|
|
|
|
this.dialect.initialize();
|
2021-05-18 10:16:03 +02:00
|
|
|
|
2021-08-04 17:47:38 +02:00
|
|
|
this.schema = createSchemaProvider(this);
|
2021-05-10 15:36:09 +02:00
|
|
|
|
2021-09-20 19:15:50 +02:00
|
|
|
this.migrations = createMigrationsProvider(this);
|
|
|
|
this.lifecycles = createLifecyclesProvider(this);
|
|
|
|
|
2021-06-17 16:17:15 +02:00
|
|
|
this.entityManager = createEntityManager(this);
|
2021-05-10 15:36:09 +02:00
|
|
|
}
|
2021-05-17 16:34:19 +02:00
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
query(uid: string) {
|
2021-06-22 17:13:11 +02:00
|
|
|
if (!this.metadata.has(uid)) {
|
|
|
|
throw new Error(`Model ${uid} not found`);
|
|
|
|
}
|
|
|
|
|
2021-06-17 16:17:15 +02:00
|
|
|
return this.entityManager.getRepository(uid);
|
|
|
|
}
|
|
|
|
|
2023-04-12 18:42:43 +02:00
|
|
|
inTransaction() {
|
|
|
|
return !!transactionCtx.get();
|
|
|
|
}
|
|
|
|
|
2023-09-12 21:47:42 +02:00
|
|
|
async transaction(): Promise<{
|
|
|
|
commit: () => Promise<void>;
|
|
|
|
rollback: () => Promise<void>;
|
|
|
|
get: () => Knex.Transaction;
|
|
|
|
}>;
|
2023-09-12 13:26:59 +02:00
|
|
|
async transaction(cb?: Callback) {
|
2023-01-13 12:23:30 +02:00
|
|
|
const notNestedTransaction = !transactionCtx.get();
|
2023-09-12 13:26:59 +02:00
|
|
|
const trx = notNestedTransaction
|
|
|
|
? await this.connection.transaction()
|
|
|
|
: (transactionCtx.get() as Knex.Transaction);
|
2023-01-23 18:43:14 +02:00
|
|
|
|
|
|
|
async function commit() {
|
|
|
|
if (notNestedTransaction) {
|
2023-05-18 12:57:47 +02:00
|
|
|
await transactionCtx.commit(trx);
|
2023-01-23 18:43:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function rollback() {
|
|
|
|
if (notNestedTransaction) {
|
2023-05-18 12:57:47 +02:00
|
|
|
await transactionCtx.rollback(trx);
|
2023-01-23 18:43:14 +02:00
|
|
|
}
|
|
|
|
}
|
2023-04-11 16:10:24 +02:00
|
|
|
|
2022-09-12 15:24:53 +02:00
|
|
|
if (!cb) {
|
2023-05-18 12:57:47 +02:00
|
|
|
return { commit, rollback, get: () => trx };
|
2022-09-12 15:24:53 +02:00
|
|
|
}
|
|
|
|
|
2023-01-24 14:39:24 +02:00
|
|
|
return transactionCtx.run(trx, async () => {
|
2022-09-12 15:24:53 +02:00
|
|
|
try {
|
2023-05-18 12:57:47 +02:00
|
|
|
const callbackParams = {
|
|
|
|
trx,
|
|
|
|
commit,
|
|
|
|
rollback,
|
|
|
|
onCommit: transactionCtx.onCommit,
|
|
|
|
onRollback: transactionCtx.onRollback,
|
|
|
|
};
|
2023-01-24 14:39:24 +02:00
|
|
|
const res = await cb(callbackParams);
|
2023-01-23 18:43:14 +02:00
|
|
|
await commit();
|
2022-09-12 15:24:53 +02:00
|
|
|
return res;
|
|
|
|
} catch (error) {
|
2023-01-23 18:43:14 +02:00
|
|
|
await rollback();
|
2022-09-12 15:24:53 +02:00
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-12 21:47:42 +02:00
|
|
|
getSchemaName(): string | undefined {
|
2023-07-19 16:35:50 +02:00
|
|
|
return this.connection.client.connectionSettings.schema;
|
|
|
|
}
|
|
|
|
|
|
|
|
getConnection(): Knex;
|
2023-09-12 21:47:42 +02:00
|
|
|
getConnection(tableName?: string): Knex.QueryBuilder;
|
2023-07-19 16:35:50 +02:00
|
|
|
getConnection(tableName?: string): Knex | Knex.QueryBuilder {
|
|
|
|
const schema = this.getSchemaName();
|
2021-11-10 19:42:03 +01:00
|
|
|
const connection = tableName ? this.connection(tableName) : this.connection;
|
|
|
|
return schema ? connection.withSchema(schema) : connection;
|
|
|
|
}
|
|
|
|
|
|
|
|
getSchemaConnection(trx = this.connection) {
|
2023-07-19 16:35:50 +02:00
|
|
|
const schema = this.getSchemaName();
|
2021-11-10 19:42:03 +01:00
|
|
|
return schema ? trx.schema.withSchema(schema) : trx.schema;
|
|
|
|
}
|
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
queryBuilder(uid: string) {
|
2021-09-13 12:03:12 +02:00
|
|
|
return this.entityManager.createQueryBuilder(uid);
|
|
|
|
}
|
|
|
|
|
2021-06-17 16:17:15 +02:00
|
|
|
async destroy() {
|
2021-08-04 17:47:38 +02:00
|
|
|
await this.lifecycles.clear();
|
2021-06-17 16:17:15 +02:00
|
|
|
await this.connection.destroy();
|
2021-05-17 16:34:19 +02:00
|
|
|
}
|
2021-05-10 15:36:09 +02:00
|
|
|
}
|
2019-09-20 12:44:24 +02:00
|
|
|
|
2021-07-01 14:32:50 +02:00
|
|
|
// TODO: move into strapi
|
2021-06-17 16:17:15 +02:00
|
|
|
Database.transformContentTypes = transformContentTypes;
|
2023-07-19 16:35:50 +02:00
|
|
|
Database.init = async (config: DatabaseConfig) => {
|
2022-12-20 10:17:38 +01:00
|
|
|
const db = new Database(config);
|
2023-01-02 11:28:48 +01:00
|
|
|
await validateDatabase(db);
|
2022-12-20 10:17:38 +01:00
|
|
|
return db;
|
|
|
|
};
|
2021-06-17 16:17:15 +02:00
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
export { Database, errors };
|