@codemask-labs/nestjs-mongodb
Version:
Nestjs Mongodb Module
207 lines • 9.77 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.getEntityDropIndexNames = exports.getEntityIndexDescriptions = exports.getEntityIndexes = exports.mergeObjectAndArray = exports.getIndexNameFromKey = exports.getEntitySchemaValidator = exports.getObjectValidator = exports.getPropertyValidator = exports.getBsonType = exports.getEntitiesFromMixedList = exports.getDefaultDataSourceOptions = exports.getConnectionString = exports.getEntityMetadata = exports.getCollectionToken = exports.getDataSourceToken = exports.getClientToken = exports.isEmpty = exports.isDataSourceOptions = void 0;
const ramda_1 = require("ramda");
const mongodb_1 = require("mongodb");
const constants_1 = require("./constants");
const metadata_1 = require("./metadata");
const enums_1 = require("./enums");
const isDataSourceOptions = (object) => (0, ramda_1.is)(Object, object) && (0, ramda_1.has)('database', object);
exports.isDataSourceOptions = isDataSourceOptions;
const isEmpty = (value) => (Array.isArray(value) ? value.length === 0 : Object.keys(value).length === 0);
exports.isEmpty = isEmpty;
const getClientToken = (connectionName) => `mongo-client:${connectionName ?? constants_1.DEFAULT_CONNECTION_NAME}`;
exports.getClientToken = getClientToken;
const getDataSourceToken = (connectionName) => `mongo-datasource:${connectionName ?? constants_1.DEFAULT_CONNECTION_NAME}`;
exports.getDataSourceToken = getDataSourceToken;
const getCollectionToken = (entity, connectionName) => `mongo-entity:${connectionName ?? constants_1.DEFAULT_CONNECTION_NAME}:${entity.name}`;
exports.getCollectionToken = getCollectionToken;
const getEntityMetadata = (entity) => metadata_1.Metadata.get(entity, constants_1.ENTITY_METADATA);
exports.getEntityMetadata = getEntityMetadata;
const getConnectionString = (options) => {
const host = options.host ?? 'localhost';
const port = options.port ?? 27017;
const auth = options.username && options.password ? `${options.username}:${options.password}@` : '';
return `mongodb://${auth}${host}:${port}/${options.database}?authSource=admin`;
};
exports.getConnectionString = getConnectionString;
const getDefaultDataSourceOptions = (options) => ({
...options,
synchronize: options.synchronize ?? true
});
exports.getDefaultDataSourceOptions = getDefaultDataSourceOptions;
const getEntitiesFromMixedList = (mixedList = []) => {
const entities = Array.isArray(mixedList) ? mixedList : Object.values(mixedList ?? {});
return entities.reduce((acc, entity) => (!metadata_1.Metadata.has(entity, constants_1.ENTITY_WATERMARK) ? acc : [...acc, entity]), []);
};
exports.getEntitiesFromMixedList = getEntitiesFromMixedList;
const getBsonType = (type) => {
switch (type) {
case String:
return enums_1.BSONType.String;
case Number:
return enums_1.BSONType.Number;
case Boolean:
return enums_1.BSONType.Bool;
case Date:
return enums_1.BSONType.Date;
case Array:
return enums_1.BSONType.Array;
case mongodb_1.ObjectId:
return enums_1.BSONType.ObjectId;
default:
return enums_1.BSONType.Object;
}
};
exports.getBsonType = getBsonType;
const getPropertyValidator = (column) => {
const bsonType = (0, exports.getBsonType)(column.type);
const isNestedEntity = metadata_1.Metadata.has(column.type, constants_1.NESTED_ENTITY_WATERMARK);
if (isNestedEntity && column.options.array) {
const metadata = metadata_1.Metadata.get(column.type, constants_1.ENTITY_METADATA);
return {
bsonType: enums_1.BSONType.Array,
additionalProperties: false,
items: (0, exports.getObjectValidator)(metadata.entityColumns)
};
}
if (isNestedEntity) {
const metadata = metadata_1.Metadata.get(column.type, constants_1.ENTITY_METADATA);
return (0, exports.getObjectValidator)(metadata.entityColumns);
}
if (column.options.array && column.options.enum) {
return {
bsonType: enums_1.BSONType.Array,
additionalProperties: false,
items: {
enum: Object.values(column.type)
}
};
}
if (column.options.enum) {
return (0, ramda_1.reject)(exports.isEmpty, {
enum: Object.values(column.options.enum)
});
}
if (column.options.array) {
return {
bsonType: enums_1.BSONType.Array,
additionalProperties: false,
items: {
bsonType
}
};
}
return (0, ramda_1.reject)(ramda_1.isNil, {
bsonType
});
};
exports.getPropertyValidator = getPropertyValidator;
const getObjectValidator = (columns) => (0, ramda_1.reject)(exports.isEmpty, columns.reduce((acc, column) => ({
bsonType: enums_1.BSONType.Object,
additionalProperties: false,
required: column.options.required ? [...(acc.required ?? []), column.propertyKey] : acc.required,
properties: {
...acc.properties,
[column.propertyKey]: (0, exports.getPropertyValidator)(column)
}
}), {}));
exports.getObjectValidator = getObjectValidator;
const getEntitySchemaValidator = (columns) => ({
$jsonSchema: (0, exports.getObjectValidator)(columns)
});
exports.getEntitySchemaValidator = getEntitySchemaValidator;
const getIndexNameFromKey = (key) => key.replace(/\.+/g, '_').toUpperCase();
exports.getIndexNameFromKey = getIndexNameFromKey;
const mergeObjectAndArray = (left, right) => {
if (Array.isArray(left) && Array.isArray(right)) {
return (0, ramda_1.concat)(left, right);
}
if ((0, ramda_1.is)(Object, left) && (0, ramda_1.is)(Object, right)) {
return (0, exports.mergeObjectAndArray)(left, right);
}
return right;
};
exports.mergeObjectAndArray = mergeObjectAndArray;
const getEntityIndexes = (metadata, stackedKeys = []) => {
const columns = metadata.entityColumns;
const createIndexOptionMap = metadata.entityOptions.index ?? {};
return columns.reduce((result, column) => {
const isNestedEntity = metadata_1.Metadata.has(column.type, constants_1.NESTED_ENTITY_WATERMARK);
if (isNestedEntity) {
const nestedEntityMetadata = metadata_1.Metadata.get(column.type, constants_1.ENTITY_METADATA);
return {
...result,
...(0, exports.getEntityIndexes)(nestedEntityMetadata, [...stackedKeys, column.propertyKey])
};
}
if ((0, ramda_1.isNil)(column.options.index)) {
return result;
}
const key = [...stackedKeys, column.propertyKey].join('.');
if ((0, ramda_1.is)(String, column.options.index)) {
const { index: indexName } = column.options;
if (!createIndexOptionMap[indexName]) {
throw new Error(`The index '${indexName}' on property '${column.propertyKey}' in [class ${column.parent.name}] has no index defined. Please add 'index[${indexName}]' in @Entity() or @NestedEntity() options.`);
}
return (0, ramda_1.mergeDeepWith)(exports.mergeObjectAndArray, result, {
[indexName]: {
keys: [key],
options: createIndexOptionMap[indexName]
}
});
}
if (Array.isArray(column.options.index)) {
const { index: indexNames } = column.options;
indexNames.forEach(indexName => {
if (!createIndexOptionMap[indexName]) {
throw new Error(`The index '${indexName}' on property '${column.propertyKey}' in [class ${column.parent.name}] has no index defined. Please add 'index[${indexName}]' in @Entity() or @NestedEntity() options.`);
}
});
return (0, ramda_1.mergeDeepWith)(exports.mergeObjectAndArray, result, indexNames.reduce((acc, indexName) => (0, ramda_1.mergeDeepWith)(exports.mergeObjectAndArray, acc, {
[indexName]: {
keys: [key],
options: createIndexOptionMap[indexName]
}
}), {}));
}
const indexName = (0, exports.getIndexNameFromKey)(key);
const { index: createIndexOptions } = column.options;
return (0, ramda_1.mergeDeepWith)(exports.mergeObjectAndArray, result, {
[indexName]: {
keys: [key],
options: createIndexOptions
}
});
}, {});
};
exports.getEntityIndexes = getEntityIndexes;
const getEntityIndexDescriptions = (entityIndexes) => Object.entries(entityIndexes).map(([name, { keys, options }]) => ({
name,
key: keys.reduce((acc, key) => ({
...acc,
[key]: 1
}), {}),
...options
}));
exports.getEntityIndexDescriptions = getEntityIndexDescriptions;
const getEntityDropIndexNames = (currentIndexDescriptions, entityIndexes) => currentIndexDescriptions.reduce((acc, { name, key: currentIndexKeys, ...currentIndexOptions }) => {
if (!name || name === '_id_') {
return acc;
}
const targetEntityIndex = entityIndexes[name];
if (!targetEntityIndex) {
return [...acc, name];
}
const differenceInKeys = (0, ramda_1.difference)(Object.keys(currentIndexKeys), targetEntityIndex.keys);
if (differenceInKeys.length) {
return [...acc, name];
}
const [differenceInOptions] = (0, ramda_1.difference)([currentIndexOptions], [targetEntityIndex.options]);
if (differenceInOptions && Object.keys(differenceInOptions).some(key => key !== 'v')) {
return [...acc, name];
}
return acc;
}, []);
exports.getEntityDropIndexNames = getEntityDropIndexNames;
//# sourceMappingURL=utils.js.map
;