165 lines
5.2 KiB
JavaScript
165 lines
5.2 KiB
JavaScript
import mongoose from 'mongoose';
|
|
import fieldToSchemaMap from './fieldToSchemaMap';
|
|
import localizationPlugin from '../../localization/localization.plugin';
|
|
import autopopulate from '../autopopulate.plugin';
|
|
import validateCollection from '../../utilities/validateCollection';
|
|
import {schemaBaseFields} from './schemaBaseFields';
|
|
import passwordResetConfig from '../../auth/passwordResets/passwordReset.config';
|
|
import paginate from '../paginate.plugin';
|
|
import buildQueryPlugin from '../buildQuery.plugin';
|
|
import validateGlobal from '../../utilities/validateGlobal';
|
|
|
|
class SchemaLoader {
|
|
|
|
blockSchema;
|
|
contentBlocks = {};
|
|
collections = {};
|
|
globals = {};
|
|
globalModel = {};
|
|
|
|
/**
|
|
* Sets up schema and models using payload config
|
|
* @param config
|
|
* @param config.collections
|
|
* @param config.globals
|
|
* @param config.contentBlocks
|
|
*/
|
|
constructor(config) {
|
|
this.blockSchema = new mongoose.Schema({},
|
|
{discriminatorKey: 'blockType', _id: false});
|
|
|
|
this.blockSchemaLoader(config);
|
|
this.collectionSchemaLoader(config);
|
|
this.globalSchemaLoader(config);
|
|
}
|
|
|
|
blockSchemaLoader = config => {
|
|
Object.values(config.contentBlocks).forEach(blockConfig => {
|
|
// TODO: any kind of validation for blocks?
|
|
const fields = {};
|
|
|
|
const flexibleSchema = {};
|
|
blockConfig.fields.forEach(field => {
|
|
const fieldSchema = fieldToSchemaMap[field.type];
|
|
if (fieldSchema) fields[field.name] = fieldSchema(field, this.blockSchema);
|
|
if (field.type === 'flexible') {
|
|
flexibleSchema[field.name] = field;
|
|
}
|
|
});
|
|
// TODO: instead of making the model with all the fields, create a separate model
|
|
// replace block schema with a ref to the new model type
|
|
|
|
const Schema = new mongoose.Schema(fields)
|
|
.plugin(localizationPlugin, config.localization)
|
|
.plugin(autopopulate);
|
|
|
|
const Model = mongoose.model(blockConfig.slug, Schema);
|
|
|
|
const RefSchema = new mongoose.Schema(
|
|
{
|
|
relation: {
|
|
type: mongoose.Schema.Types.ObjectId,
|
|
autopopulate: true,
|
|
ref: blockConfig.slug,
|
|
}
|
|
}
|
|
);
|
|
|
|
Object.values(flexibleSchema).forEach(flexible => {
|
|
flexible.blocks.forEach(blockType => {
|
|
Schema
|
|
.path(flexible.name)
|
|
.discriminator(blockType, RefSchema)
|
|
});
|
|
});
|
|
|
|
this.contentBlocks[blockConfig.slug] = {
|
|
config: blockConfig,
|
|
schema: Schema,
|
|
refSchema: RefSchema,
|
|
model: Model
|
|
};
|
|
});
|
|
};
|
|
|
|
collectionSchemaLoader = config => {
|
|
Object.values(config.collections).forEach(collectionConfig => {
|
|
|
|
validateCollection(collectionConfig, this.collections);
|
|
this.collections[collectionConfig.labels.singular] = collectionConfig;
|
|
const fields = {...schemaBaseFields};
|
|
|
|
// authentication
|
|
if (config.auth && config.auth.passwordResets) {
|
|
config.fields.push(...passwordResetConfig.fields);
|
|
}
|
|
|
|
const flexibleSchema = {};
|
|
collectionConfig.fields.forEach(field => {
|
|
const fieldSchema = fieldToSchemaMap[field.type];
|
|
if (fieldSchema) fields[field.name] = fieldSchema(field, this.blockSchema);
|
|
if (field.type === 'flexible') {
|
|
flexibleSchema[field.name] = field;
|
|
}
|
|
});
|
|
|
|
const Schema = new mongoose.Schema(fields, {timestamps: collectionConfig.timestamps});
|
|
|
|
Schema.plugin(paginate);
|
|
Schema.plugin(buildQueryPlugin);
|
|
Schema.plugin(localizationPlugin, config.localization);
|
|
Schema.plugin(autopopulate);
|
|
|
|
Object.values(flexibleSchema).forEach(flexible => {
|
|
flexible.blocks.forEach(blockType => {
|
|
Schema.path(flexible.name)
|
|
.discriminator(blockType, this.contentBlocks[blockType].refSchema)
|
|
});
|
|
});
|
|
|
|
if (collectionConfig.plugins) {
|
|
collectionConfig.plugins.forEach(plugin => {
|
|
Schema.plugin(plugin.plugin, plugin.options);
|
|
});
|
|
}
|
|
|
|
this.collections[collectionConfig.labels.singular] = {
|
|
config: collectionConfig,
|
|
model: mongoose.model(collectionConfig.labels.singular, Schema)
|
|
};
|
|
});
|
|
};
|
|
|
|
globalSchemaLoader = config => {
|
|
let globalSchemaGroups = {};
|
|
const globalFields = {};
|
|
Object.values(config.globals).forEach(globalConfig => {
|
|
validateGlobal(globalConfig, this.globals);
|
|
this.globals[globalConfig.label] = config;
|
|
globalFields[globalConfig.slug] = {};
|
|
|
|
globalConfig.fields.forEach(field => {
|
|
const fieldSchema = fieldToSchemaMap[field.type];
|
|
if (fieldSchema) globalFields[globalConfig.slug][field.name] = fieldSchema(field, this.blockSchema);
|
|
});
|
|
globalSchemaGroups[config.slug] = new mongoose.Schema(globalFields[config.slug], {_id: false});
|
|
});
|
|
|
|
if (config.globals) {
|
|
this.globalModel = mongoose.model(
|
|
'global',
|
|
new mongoose.Schema({...globalSchemaGroups, timestamps: false})
|
|
.plugin(localizationPlugin, config.localization)
|
|
.plugin(autopopulate)
|
|
);
|
|
}
|
|
};
|
|
|
|
flexibleSchemaLoader = () => {
|
|
// TODO: move reusable parts from block, collection and global schema functions
|
|
return {};
|
|
}
|
|
}
|
|
|
|
module.exports = SchemaLoader;
|