strapi/packages/strapi-database/lib/database-manager.js
Pierre Noël 053714c7be refacto
Signed-off-by: Pierre Noël <pierre.noel@strapi.io>
2020-03-30 12:50:48 +02:00

184 lines
4.9 KiB
JavaScript

'use strict';
const _ = require('lodash');
const requireConnector = require('./require-connector');
const { createQuery } = require('./queries');
class DatabaseManager {
constructor(strapi) {
this.strapi = strapi;
this.initialized = false;
this.queries = new Map();
this.connectors = new Map();
this.models = new Map();
}
// Check if all collection names are unique
checkForDuplicates() {
const createErrorMessage = (
collectionA,
collectionB
) => `Duplicated collection name: \`${collectionA.collectionName}\`.
The same collection name can't be used for two different models.
First found in ${collectionA.origin} \`${collectionA.apiOrPluginName}\`, model \`${collectionA.modelName}\`.
Second found in ${collectionB.origin} \`${collectionB.apiOrPluginName}\`, model \`${collectionB.modelName}\`.`;
const collections = [];
_.forIn(this.strapi.admin.models, (model, modelName) => {
collections.push({
origin: 'Strapi internal',
collectionName: model.collectionName || `${modelName}`.toLocaleLowerCase(),
apiOrPluginName: 'admin',
modelName,
});
});
_.forIn(this.strapi.api, (api, apiName) => {
_.forIn(api.models, (model, modelName) => {
collections.push({
origin: 'API',
collectionName: model.collectionName || `${modelName}`.toLocaleLowerCase(),
apiOrPluginName: apiName,
modelName,
});
});
});
_.forIn(this.strapi.plugins, (plugin, pluginName) => {
_.forIn(plugin.models, (model, modelName) => {
collections.push({
origin: 'Plugin',
collectionName: model.collectionName || `${modelName}`.toLocaleLowerCase(),
apiOrPluginName: pluginName,
modelName,
});
});
});
collections.forEach((collectionA, indexA) => {
const similarCollectionFound = collections
.slice(indexA + 1)
.find(colB => colB.collectionName === collectionA.collectionName);
if (similarCollectionFound) {
strapi.stopWithError(new Error(createErrorMessage(collectionA, similarCollectionFound)));
}
});
}
async initialize() {
if (this.initialized === true) {
throw new Error('Database manager already initialized');
}
this.initialized = true;
const connectorsToInitialize = [];
for (const connection of Object.values(this.strapi.config.connections)) {
const { connector } = connection;
if (!connectorsToInitialize.includes(connector)) {
connectorsToInitialize.push(connector);
}
}
this.checkForDuplicates();
for (const connectorToInitialize of connectorsToInitialize) {
const connector = requireConnector(connectorToInitialize)(strapi);
this.connectors.set(connectorToInitialize, connector);
await connector.initialize();
}
this.initializeModelsMap();
return this;
}
initializeModelsMap() {
Object.keys(this.strapi.models).forEach(modelKey => {
const model = this.strapi.models[modelKey];
this.models.set(model.uid, model);
});
Object.keys(this.strapi.admin.models).forEach(modelKey => {
const model = this.strapi.admin.models[modelKey];
this.models.set(model.uid, model);
});
Object.keys(this.strapi.plugins).forEach(pluginKey => {
Object.keys(this.strapi.plugins[pluginKey].models).forEach(modelKey => {
const model = this.strapi.plugins[pluginKey].models[modelKey];
this.models.set(model.uid, model);
});
});
}
query(entity, plugin) {
if (!entity) {
throw new Error(`argument entity is required`);
}
const normalizedName = entity.toLowerCase();
// get by uid or name / plugin
const model = this.models.has(entity)
? this.models.get(entity)
: this.getModel(normalizedName, plugin);
if (!model) {
throw new Error(`The model ${entity} can't be found.`);
}
if (this.queries.has(model.uid)) {
return this.queries.get(model.uid);
}
const connectorQuery = this.connectors
.get(model.orm)
.queries({ model, modelKey: model.modelName, strapi });
const query = createQuery({
connectorQuery,
model,
});
this.queries.set(model.uid, query);
return query;
}
getModel(name, plugin) {
const key = _.toLower(name);
if (this.models.has(key)) return this.models.get(key);
if (plugin === 'admin') {
return _.get(strapi.admin, ['models', key]);
}
return (
_.get(strapi.plugins, [plugin, 'models', key]) ||
_.get(strapi, ['models', key]) ||
_.get(strapi, ['components', key])
);
}
getModelByCollectionName(collectionName) {
return Array.from(this.models.values()).find(model => {
return model.collectionName === collectionName;
});
}
}
function createDatabaseManager(strapi) {
return new DatabaseManager(strapi);
}
module.exports = {
createDatabaseManager,
};