@scalars/grapi-mongodb
Version:
The mongodb package of Grapi
485 lines (484 loc) • 30 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.MongodbData = void 0;
var grapi_1 = require("@scalars/grapi");
var lodash_1 = require("./lodash");
var MongodbData = (function () {
function MongodbData(db, collectionName) {
this.transformMutation = function (mutation, set) {
if (set === void 0) { set = false; }
var payload = set ? { $set: mutation.getData() } : mutation.getData();
mutation.getArrayOperations().forEach(function (operation) {
var _a, _b;
var fieldName = operation.fieldName, operator = operation.operator, value = operation.value;
if (operator == grapi_1.ArrayOperator.set) {
if (set) {
payload.$set[fieldName] = value;
}
else {
payload[fieldName] = value;
}
}
else if (operator == grapi_1.ArrayOperator.add) {
payload.$addToSet = __assign(__assign({}, payload.$addToSet), (_a = {}, _a[fieldName] = { $each: value }, _a));
}
else if (operator == grapi_1.ArrayOperator.remove) {
payload.$pull = __assign(__assign({}, payload.$pull), (_b = {}, _b[fieldName] = { $in: value }, _b));
}
});
return payload;
};
this.db = db;
this.collectionName = collectionName;
}
MongodbData.prototype.findInCollection = function (filterQuery, orderBy) {
if (orderBy === void 0) { orderBy = {}; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4, this.db.collection(this.collectionName)
.find(filterQuery)
.sort(orderBy)
.project({ _id: 0 })
.toArray()];
case 1: return [2, _a.sent()];
}
});
});
};
MongodbData.prototype.findRecursive = function (where, orderBy, data) {
if (data === void 0) { data = []; }
return __awaiter(this, void 0, void 0, function () {
var iteration;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
iteration = 0;
return [4, grapi_1.iterateWhereFilter(where, function (whereFilter, operator) { return __awaiter(_this, void 0, void 0, function () {
var _a, baseFilters_1, relationFilters_3, filters, filterQuery, baseFiltersOrAnd_1, whereFiltersOrAnd, dataCollection, _i, relationFilters_1, itemWhere, _b, _c, _d, relationFilters_2, itemWhere;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
if (!(operator === grapi_1.WhereOperator.relation)) return [3, 5];
if (!(lodash_1.isEmpty(data) && iteration === 0)) return [3, 2];
return [4, this.findInCollection({}, orderBy)];
case 1:
_a = _e.sent();
return [3, 3];
case 2:
_a = data;
_e.label = 3;
case 3:
data = _a;
return [4, this.executeRelationFilters(whereFilter, data)];
case 4:
data = _e.sent();
return [3, 17];
case 5:
baseFilters_1 = [];
relationFilters_3 = [];
if (operator === grapi_1.Operator.and || operator === grapi_1.Operator.or) {
lodash_1.forEach(whereFilter, function (item) {
if (lodash_1.findKey(item, 'relation')) {
relationFilters_3.push(item);
}
else {
baseFilters_1.push(item);
}
});
}
if (!(lodash_1.isEmpty(baseFilters_1) === false || operator === grapi_1.WhereOperator.base || lodash_1.isEmpty(whereFilter))) return [3, 7];
filters = lodash_1.isEmpty(baseFilters_1) ? whereFilter : baseFilters_1;
filterQuery = this.whereToFilterQuery(filters, operator);
return [4, this.findInCollection(filterQuery, orderBy)];
case 6:
data = _e.sent();
iteration = iteration + 1;
_e.label = 7;
case 7:
if (!(lodash_1.isEmpty(relationFilters_3) === false)) return [3, 17];
baseFiltersOrAnd_1 = [];
lodash_1.forEach(relationFilters_3, function (item) {
lodash_1.forEach(item, function (value, key) {
var _a;
if (!lodash_1.get(value, 'relation')) {
delete item[key];
baseFiltersOrAnd_1.push((_a = {}, _a[key] = value, _a));
}
});
});
baseFiltersOrAnd_1 = lodash_1.uniqWith(baseFiltersOrAnd_1, lodash_1.isEqual);
whereFiltersOrAnd = this.whereToFilterQuery(baseFiltersOrAnd_1, operator);
return [4, this.findInCollection(whereFiltersOrAnd)];
case 8:
dataCollection = _e.sent();
if (!(operator === grapi_1.Operator.or)) return [3, 13];
_i = 0, relationFilters_1 = relationFilters_3;
_e.label = 9;
case 9:
if (!(_i < relationFilters_1.length)) return [3, 12];
itemWhere = relationFilters_1[_i];
_b = lodash_1.concat;
_c = [data];
return [4, this.executeRelationFilters(itemWhere, dataCollection)];
case 10:
data = _b.apply(void 0, _c.concat([_e.sent()]));
_e.label = 11;
case 11:
_i++;
return [3, 9];
case 12:
data = lodash_1.uniqWith(lodash_1.compact(data), lodash_1.isEqual);
return [3, 17];
case 13:
data = lodash_1.isEmpty(data) && iteration === 0 ? dataCollection : data;
_d = 0, relationFilters_2 = relationFilters_3;
_e.label = 14;
case 14:
if (!(_d < relationFilters_2.length)) return [3, 17];
itemWhere = relationFilters_2[_d];
return [4, this.executeRelationFilters(itemWhere, data)];
case 15:
data = _e.sent();
_e.label = 16;
case 16:
_d++;
return [3, 14];
case 17: return [2];
}
});
}); })];
case 1:
_a.sent();
return [2, data];
}
});
});
};
MongodbData.prototype.executeRelationFilters = function (where, data, filtered) {
if (filtered === void 0) { filtered = []; }
return __awaiter(this, void 0, void 0, function () {
var _loop_1, _i, data_1, item, state_1;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_loop_1 = function (item) {
var filter;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4, grapi_1.iterateRelationsWhere(where, function (relationWhere) { return __awaiter(_this, void 0, void 0, function () {
var relation, relations, filters, targetKey, _a, list, ship, source, target, filter, foreignKey, relationData, isManyToMany, foreignKeyValue, filterWhere, totalRelationData, recursive, _b, itemId_1, key, relationData, filterId, status_1, filters_1, recursiveFilter;
var _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
relation = relationWhere.relation;
relations = {};
lodash_1.forEach(relationWhere.filters || {}, function (value, key) {
if (value.relation) {
relations[key] = value;
}
});
filters = relationWhere.filters, targetKey = relationWhere.targetKey;
_a = relation || {}, list = _a.list, ship = _a.ship, source = _a.source, target = _a.target, filter = _a.filter, foreignKey = _a.foreignKey;
if (!list) return [3, 14];
relationData = void 0;
isManyToMany = ship === grapi_1.RelationShip.ManyToMany;
foreignKeyValue = foreignKey || lodash_1.toLower(source) + "Id";
if (!isManyToMany) return [3, 2];
return [4, this.filterManyFromManyRelation(lodash_1.toLower(source), lodash_1.toLower(target), item.id, targetKey, grapi_1.iterateBaseFilter(filters))];
case 1:
relationData = _d.sent();
relationData = lodash_1.compact(relationData);
return [3, 4];
case 2: return [4, this.findManyRelation(foreignKeyValue, item.id, targetKey, filters)];
case 3:
relationData = _d.sent();
_d.label = 4;
case 4:
filterWhere = void 0;
if (!(filter === "some")) return [3, 5];
filterWhere = !lodash_1.isEmpty(relationData);
return [3, 11];
case 5:
if (!(filter === "none")) return [3, 6];
filterWhere = lodash_1.isEmpty(relationData);
return [3, 11];
case 6:
totalRelationData = [];
if (!isManyToMany) return [3, 8];
return [4, this.filterManyFromManyRelation(lodash_1.toLower(source), lodash_1.toLower(target), item.id, targetKey, {})];
case 7:
totalRelationData = _d.sent();
return [3, 10];
case 8: return [4, this.findManyRelation(foreignKeyValue, item.id, targetKey, filters)];
case 9:
totalRelationData = _d.sent();
_d.label = 10;
case 10:
filterWhere = totalRelationData.length === relationData.length;
_d.label = 11;
case 11:
if (!(filterWhere && lodash_1.isEmpty(relations) === false)) return [3, 13];
return [4, this.executeRelationFilters(relations, relationData)];
case 12:
recursive = _d.sent();
return [2, lodash_1.isEmpty(recursive) === false];
case 13: return [2, filterWhere];
case 14:
_b = grapi_1.getRelationItemKeyId(item, relation), itemId_1 = _b.itemId, key = _b.key;
relationData = void 0;
if (!itemId_1) return [3, 16];
filterId = lodash_1.get(relationWhere, 'filters.id');
if (filterId) {
status_1 = false;
grapi_1.iterateWhere({ id: filterId }, function (field, op, value) {
switch (op) {
case grapi_1.Operator.eq:
status_1 = itemId_1 === value;
break;
case grapi_1.Operator.neq:
status_1 = itemId_1 !== value;
break;
}
});
return [2, status_1];
}
filters_1 = lodash_1.assign((_c = {}, _c[key] = { eq: itemId_1 }, _c), relationWhere.filters);
return [4, this.findOneRelation(relationWhere.targetKey, grapi_1.iterateBaseFilter(filters_1))];
case 15:
relationData = _d.sent();
_d.label = 16;
case 16:
if (!(relationData && lodash_1.isEmpty(relations) === false)) return [3, 18];
return [4, this.executeRelationFilters(relations, [relationData])];
case 17:
recursiveFilter = _d.sent();
return [2, lodash_1.isEmpty(recursiveFilter) === false];
case 18: return [2, relationData !== null];
}
});
}); })];
case 1:
filter = _b.sent();
if (filter === undefined) {
return [2, { value: data }];
}
if (filter) {
filtered.push(item);
}
return [2];
}
});
};
_i = 0, data_1 = data;
_a.label = 1;
case 1:
if (!(_i < data_1.length)) return [3, 4];
item = data_1[_i];
return [5, _loop_1(item)];
case 2:
state_1 = _a.sent();
if (typeof state_1 === "object")
return [2, state_1.value];
_a.label = 3;
case 3:
_i++;
return [3, 1];
case 4: return [2, filtered];
}
});
});
};
MongodbData.prototype.findOneRelation = function (colectionName, where) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4, this.db.collection(colectionName).findOne(this.whereToFilterQuery(where))];
case 1: return [2, _a.sent()];
}
});
});
};
MongodbData.prototype.findManyRelation = function (foreignKey, foreignId, collectionName, where) {
return __awaiter(this, void 0, void 0, function () {
var filterQuery;
var _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
filterQuery = this.whereToFilterQuery(__assign(__assign({}, where), (_a = {}, _a[foreignKey] = (_b = {}, _b[grapi_1.Operator.eq] = foreignId, _b), _a)));
return [4, this.db.collection(collectionName)
.find(filterQuery)
.project({ _id: 0 })
.toArray()];
case 1: return [2, _c.sent()];
}
});
});
};
MongodbData.prototype.filterManyFromManyRelation = function (sourceSideName, targetSideName, sourceSideId, collection, where) {
return __awaiter(this, void 0, void 0, function () {
var relationTableName, relationData, relationIds;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
relationTableName = "_" + sourceSideName + "_" + targetSideName;
return [4, this.db.collection(relationTableName).findOne({ sourceSideId: sourceSideId })];
case 1:
relationData = _a.sent();
relationIds = lodash_1.get(relationData, "targetSideIds", []);
return [4, Promise.all(relationIds.map(function (id) {
var currentWhere = __assign({}, where);
if (!lodash_1.has(currentWhere, "id.eq")) {
currentWhere.id = { eq: id };
}
else if (!lodash_1.includes(relationIds, lodash_1.get(currentWhere, "id.eq"))) {
return null;
}
return _this.findOneRelation(collection, currentWhere);
}))];
case 2: return [2, _a.sent()];
}
});
});
};
MongodbData.prototype.whereToFilterQuery = function (where, operator) {
var _this = this;
if (operator === void 0) { operator = undefined; }
var filterQuery = {};
var whereCallback = function (field, operator, value) {
switch (operator) {
case grapi_1.Operator.eq:
filterQuery[field] = value;
break;
case grapi_1.Operator.contains:
filterQuery[field] = new RegExp(".*" + value + ".*", "i");
break;
case grapi_1.Operator.notcontains:
filterQuery[field] = new RegExp("^((?!" + value + ").)*$", "i");
break;
case grapi_1.Operator.neq:
filterQuery[field] = { $ne: value };
break;
case grapi_1.Operator.gt:
filterQuery[field] = { $gt: value };
break;
case grapi_1.Operator.gte:
filterQuery[field] = { $gte: value };
break;
case grapi_1.Operator.lt:
filterQuery[field] = { $lt: value };
break;
case grapi_1.Operator.lte:
filterQuery[field] = { $lte: value };
break;
case grapi_1.Operator["in"]:
filterQuery[field] = { $in: value };
break;
case grapi_1.Operator.all:
filterQuery[field] = { $all: value };
break;
case grapi_1.Operator.notIn:
filterQuery[field] = { $nin: value };
break;
case grapi_1.Operator.between:
filterQuery[field] = { $gte: value.from, $lte: value.to };
break;
case grapi_1.Operator.object:
lodash_1.assign(filterQuery, value);
break;
}
};
if (lodash_1.isEmpty(where) === false && (operator === grapi_1.Operator.or || operator === grapi_1.Operator.and)) {
var filtersQuery_1 = [];
lodash_1.forEach(where, function (whereItem) {
if (lodash_1.isEmpty(whereItem) === false) {
var _a = _this.findRecursiveOperator(whereItem), operator_1 = _a.operator, filters = _a.filters;
if (operator_1) {
filtersQuery_1.push(_this.whereToFilterQuery(filters, operator_1));
}
else {
filtersQuery_1.push(_this.whereToFilterQuery(whereItem));
}
}
});
filterQuery["$" + lodash_1.toLower(operator)] = filtersQuery_1;
}
else {
grapi_1.iterateWhere(where, whereCallback);
}
return filterQuery;
};
MongodbData.prototype.findRecursiveOperator = function (where) {
if (lodash_1.get(where, grapi_1.Operator.or)) {
return { operator: grapi_1.Operator.or, filters: lodash_1.get(where, grapi_1.Operator.or) };
}
else if (lodash_1.get(where, grapi_1.Operator.and)) {
return { operator: grapi_1.Operator.and, filters: lodash_1.get(where, grapi_1.Operator.and) };
}
return {};
};
MongodbData.prototype.handleMongoDbError = function (error) {
if (error.code === 11000) {
var keyValues = lodash_1.values(error.keyValue).join(' ');
throw new Error("Constraint unique value \"" + keyValues + "\" duplicate on " + lodash_1.capitalize(this.collectionName) + " model");
}
else if (error.code === 121) {
throw new Error("Document failed validation on " + lodash_1.capitalize(this.collectionName) + " model, review types or required values in data");
}
throw new Error("" + error.message);
};
return MongodbData;
}());
exports.MongodbData = MongodbData;