158 lines
4.7 KiB
JavaScript
Raw Normal View History

2019-09-20 12:44:24 +02:00
'use strict';
2021-06-17 16:17:15 +02:00
const { getDialect } = require('./dialects');
2021-05-18 10:16:03 +02:00
const createSchemaProvider = require('./schema');
const createMetadata = require('./metadata');
2021-06-17 16:17:15 +02:00
const { createEntityManager } = require('./entity-manager');
2021-09-20 19:15:50 +02:00
const { createMigrationsProvider } = require('./migrations');
const { createLifecyclesProvider } = require('./lifecycles');
2022-03-23 10:37:12 +01:00
const createConnection = require('./connection');
2021-10-20 17:30:05 +02:00
const errors = require('./errors');
2021-06-17 16:17:15 +02:00
// TODO: move back into strapi
const { transformContentTypes } = require('./utils/content-types');
const { getJoinTableName } = require('./metadata/relations');
const types = require('./types');
2021-05-10 15:36:09 +02:00
class Database {
constructor(config) {
2021-06-02 15:53:22 +02:00
this.metadata = createMetadata(config.models);
2021-05-18 10:16:03 +02:00
this.config = {
connection: {},
settings: {
2021-11-15 09:41:00 +01:00
forceMigration: true,
},
...config,
};
2021-06-28 12:34:29 +02:00
this.dialect = getDialect(this);
this.dialect.configure();
this.connection = createConnection(this.config.connection);
this.dialect.initialize();
2021-05-18 10:16:03 +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
2021-05-18 10:16:03 +02:00
query(uid) {
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);
}
getConnection(tableName) {
const schema = this.connection.getSchemaName();
const connection = tableName ? this.connection(tableName) : this.connection;
return schema ? connection.withSchema(schema) : connection;
}
getSchemaConnection(trx = this.connection) {
const schema = this.connection.getSchemaName();
return schema ? trx.schema.withSchema(schema) : trx.schema;
}
2022-05-18 19:00:43 +02:00
transaction() {
return this.connection.transaction();
}
queryBuilder(uid) {
return this.entityManager.createQueryBuilder(uid);
}
2021-06-17 16:17:15 +02:00
async destroy() {
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
const getLinks = ({ db }) => {
const relationsToUpdate = {};
db.metadata.forEach((contentType) => {
const attributes = contentType.attributes;
// For each relation type, add the joinTable name to tablesToUpdate
Object.values(attributes).forEach((attribute) => {
if (!types.isRelation(attribute.type)) return;
if (attribute.inversedBy) {
const invRelation = db.metadata.get(attribute.target).attributes[attribute.inversedBy];
// Both relations use inversedBy
if (invRelation?.inversedBy) {
relationsToUpdate[attribute.joinTable.name] = {
relation: attribute,
invRelation,
};
}
}
});
});
return Object.values(relationsToUpdate);
};
2021-07-01 14:32:50 +02:00
// TODO: move into strapi
2021-06-17 16:17:15 +02:00
Database.transformContentTypes = transformContentTypes;
Database.init = async (config) => {
const db = new Database(config);
// TODO: Create validations folder for this.
const links = getLinks({ db });
const errorList = [];
for (const { relation, invRelation } of links) {
// Generate the join table name based on the relation target
// table and attribute name.
const joinTableName = getJoinTableName(
db.metadata.get(relation.target).tableName,
relation.inversedBy
);
const contentType = db.metadata.get(invRelation.target);
const invContentType = db.metadata.get(relation.target);
// If both sides use inversedBy
if (relation.inversedBy && invRelation.inversedBy) {
// If the generated join table name is the same as the one assigned in relation.joinTable,
// relation is on the inversed side of the bidirectional relation.
// and the other is on the owner side.
if (joinTableName === relation.joinTable.name) {
errorList.push(
`Error on attribute "${invRelation.inversedBy}" in model "${invContentType.tableName}"(${invContentType.uid}):` +
` One of the sides of the relationship must be the owning side. You should use mappedBy` +
` instead of inversedBy in the relation "${invRelation.inversedBy}".`
);
} else {
errorList.push(
`Error on attribute "${relation.inversedBy}" in model "${contentType.tableName}"(${contentType.uid}):` +
` One of the sides of the relationship must be the owning side. You should use mappedBy` +
` instead of inversedBy in the relation "${relation.inversedBy}".`
);
}
}
}
if (errorList.length > 0) {
errorList.forEach((error) => strapi.log.error(error));
throw new Error('There are errors in some of your models. Please check the logs above.');
}
return db;
};
2021-06-17 16:17:15 +02:00
2019-09-20 12:44:24 +02:00
module.exports = {
2021-05-10 15:36:09 +02:00
Database,
2021-10-20 17:30:05 +02:00
errors,
2019-09-20 12:44:24 +02:00
};