shyft
Version:
Model driven GraphQL API framework
549 lines (548 loc) • 27 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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isEntity = exports.Entity = void 0;
var util_1 = require("../util");
var constants_1 = require("../constants");
var Index_1 = require("../index/Index");
var Mutation_1 = require("../mutation/Mutation");
var Permission_1 = require("../permission/Permission");
var Subscription_1 = require("../subscription/Subscription");
var DataType_1 = require("../datatype/DataType");
var StorageType_1 = require("../storage/StorageType");
var StorageTypeNull_1 = require("../storage/StorageTypeNull");
var ComplexDataType_1 = require("../datatype/ComplexDataType");
var systemAttributes_1 = require("./systemAttributes");
var _ = __importStar(require("lodash"));
var filter_1 = require("../filter");
var Entity = /** @class */ (function () {
function Entity(setup) {
util_1.passOrThrow(util_1.isMap(setup), function () { return 'Entity requires a setup object'; });
var name = setup.name, description = setup.description, attributes = setup.attributes, storageType = setup.storageType, isUserEntity = setup.isUserEntity, includeTimeTracking = setup.includeTimeTracking, includeUserTracking = setup.includeUserTracking, preProcessor = setup.preProcessor, postProcessor = setup.postProcessor, meta = setup.meta;
Object.keys(setup).map(function (prop) {
util_1.passOrThrow(constants_1.entityPropertiesWhitelist.includes(prop), function () { return "Invalid setup property '" + prop + "' in entity '" + name + "'"; });
});
util_1.passOrThrow(name, function () { return 'Missing entity name'; });
util_1.passOrThrow(description, function () { return "Missing description for entity '" + name + "'"; });
util_1.passOrThrow(util_1.isMap(attributes) || util_1.isFunction(attributes), function () {
return "'attributes' for entity '" + name + "' needs to be a map of attributes or a function returning a map of attributes";
});
this.setup = setup;
this.name = name;
this.description = description;
this.isUserEntity = !!isUserEntity;
this.includeTimeTracking = !!includeTimeTracking;
this.includeUserTracking = !!includeUserTracking;
this._primaryAttribute = null;
this.referencedByEntities = [];
this.meta = meta;
if (preProcessor) {
util_1.passOrThrow(util_1.isFunction(preProcessor), function () { return "preProcessor of entity '" + name + "' needs to be a valid function"; });
this.preProcessor = preProcessor;
}
if (postProcessor) {
util_1.passOrThrow(util_1.isFunction(postProcessor), function () { return "postProcessor of entity '" + name + "' needs to be a valid function"; });
this.postProcessor = postProcessor;
}
if (storageType) {
util_1.passOrThrow(StorageType_1.isStorageType(storageType), function () {
return "Entity '" + name + "' needs a valid storage type (defaults to 'StorageTypeNull')";
});
}
else {
this.storageType = StorageTypeNull_1.StorageTypeNull;
this.isFallbackStorageType = true;
this._exposeStorageAccess();
}
}
Entity.prototype._injectStorageTypeBySchema = function (storageType) {
var _this = this;
util_1.passOrThrow(StorageType_1.isStorageType(storageType), function () { return "Provided storage type to entity '" + _this.name + "' is invalid"; });
if (this.isFallbackStorageType) {
this.storageType = storageType;
this._exposeStorageAccess();
}
};
Entity.prototype._exposeStorageAccess = function () {
this.findOne = this.storageType.findOne;
this.find = this.storageType.find;
};
Entity.prototype._injectDefaultPermissionsBySchema = function (defaultPermissions) {
util_1.passOrThrow(util_1.isMap(defaultPermissions), function () { return 'Provided defaultPermissions is invalid'; });
if (!this.permissions) {
this.permissions = {};
}
this.defaultPermissions = defaultPermissions;
};
Entity.prototype.getAttributes = function () {
if (this.attributes) {
return this.attributes;
}
var ret = (this.attributes = this.processAttributeMap());
return ret;
};
Entity.prototype.processIndexes = function () {
return Index_1.processEntityIndexes(this, this.setup.indexes || []);
};
Entity.prototype.getIndexes = function () {
if (this.indexes) {
return this.indexes;
}
this.getAttributes();
this.indexes = this.processIndexes();
return this.indexes;
};
Entity.prototype._processMutations = function () {
var mutations;
if (!this.setup.mutations) {
mutations = Object.values(this.getDefaultMutations());
}
else {
mutations =
typeof this.setup.mutations === 'function'
? this.setup.mutations(this.getDefaultMutations())
: this.setup.mutations;
}
return Mutation_1.processEntityMutations(this, mutations);
};
Entity.prototype.getMutations = function () {
if (this.mutations) {
return this.mutations;
}
this.getStates();
this.mutations = this._processMutations();
return this.mutations;
};
Entity.prototype.getMutationByName = function (name) {
var mutations = this.getMutations();
return mutations
? mutations.find(function (mutation) { return String(mutation) === name; })
: null;
};
Entity.prototype.processStates = function () {
var _this = this;
if (this.setup.states) {
var states_1 = this.setup.states;
util_1.passOrThrow(util_1.isMap(states_1), function () {
return "Entity '" + _this.name + "' states definition needs to be a map of state names and their unique ID";
});
var stateNames = Object.keys(states_1);
var uniqueIds_1 = [];
stateNames.map(function (stateName) {
var stateId = states_1[stateName];
uniqueIds_1.push(stateId);
util_1.passOrThrow(constants_1.stateNameRegex.test(stateName), function () {
return "Invalid state name '" + stateName + "' in entity '" + _this.name + "' (Regex: /" + constants_1.STATE_NAME_PATTERN + "/)";
});
util_1.passOrThrow(stateId === parseInt(String(stateId), 10) && stateId > 0, function () {
return "State '" + stateName + "' in entity '" + _this.name + "' has an invalid unique ID (needs to be a positive integer)";
});
});
util_1.passOrThrow(uniqueIds_1.length === _.uniq(uniqueIds_1).length, function () {
return "Each state defined in entity '" + _this.name + "' needs to have a unique ID";
});
return states_1;
}
return null;
};
Entity.prototype._getDefaultSubscriptions = function () {
var _this = this;
var nonSystemAttributeNames = [];
util_1.mapOverProperties(this.getAttributes(), function (attribute, attributeName) {
if (!attribute.isSystemAttribute) {
nonSystemAttributeNames.push(attributeName);
}
});
var subscriptions = {};
Subscription_1.defaultEntitySubscription.map(function (defaultSubscription) {
var key = defaultSubscription.name + "Subscription";
subscriptions[key] = new Subscription_1.Subscription({
name: defaultSubscription.name,
type: defaultSubscription.type,
description: defaultSubscription.description(_this.name),
attributes: nonSystemAttributeNames,
});
});
return subscriptions;
};
Entity.prototype._processSubscriptions = function () {
var subscriptions;
if (!this.setup.subscriptions) {
subscriptions = Object.values(this._getDefaultSubscriptions());
}
else {
subscriptions = util_1.isFunction(this.setup.subscriptions)
? this.setup.subscriptions(this._getDefaultSubscriptions())
: this.setup.subscriptions;
}
return Subscription_1.processEntitySubscriptions(this, subscriptions);
};
Entity.prototype.getSubscriptions = function () {
if (this.subscriptions) {
return this.subscriptions;
}
this.subscriptions = this._processSubscriptions();
return this.subscriptions;
};
Entity.prototype.getSubscriptionByName = function (name) {
var subscriptions = this.getSubscriptions();
return subscriptions
? subscriptions.find(function (subscription) { return String(subscription) === name; })
: null;
};
Entity.prototype.getStates = function () {
if (!this.setup.states || this.states) {
return this.states;
}
this.states = this.processStates();
return this.states;
};
Entity.prototype.hasStates = function () {
return !!this.getStates();
};
Entity.prototype._collectSystemAttributes = function (attributeMap) {
var _this = this;
var list = [];
if (!this.getPrimaryAttribute()) {
var name = systemAttributes_1.systemAttributePrimary.name;
this._checkSystemAttributeNameCollision(attributeMap, name);
attributeMap[name] = systemAttributes_1.systemAttributePrimary;
list.push(name);
}
if (this.includeTimeTracking) {
systemAttributes_1.systemAttributesTimeTracking.map(function (attribute) {
var name = attribute.name;
_this._checkSystemAttributeNameCollision(attributeMap, name);
attributeMap[name] = attribute;
list.push(name);
});
}
if (this.includeUserTracking && !this.isUserEntity) {
systemAttributes_1.systemAttributesUserTracking.map(function (attribute) {
var name = attribute.name;
_this._checkSystemAttributeNameCollision(attributeMap, name);
attributeMap[name] = attribute;
list.push(name);
});
}
if (this.hasStates()) {
var name = systemAttributes_1.systemAttributeState.name;
this._checkSystemAttributeNameCollision(attributeMap, name);
attributeMap[name] = systemAttributes_1.systemAttributeState;
list.push(name);
}
var attributeNames = Object.keys(attributeMap);
var i18nAttributeNames = attributeNames.filter(function (attributeName) { return attributeMap[attributeName].i18n; });
if (i18nAttributeNames.length) {
var name = systemAttributes_1.systemAttributeI18n.name;
this._checkSystemAttributeNameCollision(attributeMap, name);
attributeMap[name] = systemAttributes_1.systemAttributeI18n;
list.push(name);
}
return list;
};
Entity.prototype._checkSystemAttributeNameCollision = function (attributeMap, attributeName) {
var _this = this;
util_1.passOrThrow(!attributeMap[attributeName], function () {
return "Attribute name collision with system attribute '" + attributeName + "' in entity '" + _this.name + "'";
});
};
Entity.prototype.processAttribute = function (rawAttribute, attributeName) {
var _this = this;
util_1.passOrThrow(constants_1.attributeNameRegex.test(attributeName), function () {
return "Invalid attribute name '" + attributeName + "' in entity '" + _this.name + "' (Regex: /" + constants_1.ATTRIBUTE_NAME_PATTERN + "/)";
});
Object.keys(rawAttribute).map(function (prop) {
util_1.passOrThrow(constants_1.attributePropertiesWhitelist.includes(prop), function () {
return "Invalid attribute property '" + prop + "' in entity '" + _this.name + "' (use 'meta' for custom data)";
});
});
var attribute = __assign(__assign({}, rawAttribute), { primary: !!rawAttribute.primary, unique: !!rawAttribute.primary, required: !!rawAttribute.required || !!rawAttribute.primary, hidden: !!rawAttribute.hidden, index: !!rawAttribute.index, i18n: !!rawAttribute.i18n, mutationInput: !!rawAttribute.mutationInput, name: attributeName });
util_1.passOrThrow(attribute.description, function () { return "Missing description for '" + _this.name + "." + attributeName + "'"; });
if (util_1.isFunction(attribute.type)) {
var dataTypeBuilder = attribute.type;
attribute.type = dataTypeBuilder({
setup: attribute,
entity: this,
});
}
util_1.passOrThrow(DataType_1.isDataType(attribute.type) ||
attribute.type instanceof Entity ||
ComplexDataType_1.isComplexDataType(attribute.type), function () {
return "'" + _this.name + "." + attributeName + "' has invalid data type '" + String(attribute.type) + "'";
});
if (attribute.i18n) {
util_1.passOrThrow(DataType_1.isDataType(attribute.type), function () {
return "'" + _this.name + "." + attributeName + "' cannot be translatable as it is not a simple data type";
});
util_1.passOrThrow(!attribute.unique, function () {
return "'" + _this.name + "." + attributeName + "' cannot be translatable as it has a uniqueness constraint";
});
}
if (DataType_1.isDataType(attribute.type)) {
var attributeType = attribute.type;
if (attributeType.enforceRequired) {
attribute.required = true;
}
if (attributeType.defaultValue) {
attribute.defaultValue = attributeType.defaultValue;
}
if (attributeType.enforceIndex) {
attribute.index = true;
}
}
if (attribute.targetAttributesMap) {
util_1.passOrThrow(attribute.type instanceof Entity, function () {
return "'" + _this.name + "." + attributeName + "' cannot have a targetAttributesMap as it is not a reference";
});
util_1.passOrThrow(util_1.isMap(attribute.targetAttributesMap), function () {
return "targetAttributesMap for '" + _this.name + "." + attributeName + "' needs to be a map";
});
var localAttributeNames = Object.keys(attribute.targetAttributesMap);
localAttributeNames.map(function (localAttributeName) {
var targetAttribute = attribute.targetAttributesMap[localAttributeName];
util_1.passOrThrow(util_1.isMap(targetAttribute) &&
targetAttribute.name &&
targetAttribute.type, function () {
return "targetAttributesMap for '" + _this.name + "." + attributeName + "' needs to be a map between local and target attributes";
});
// check if attribute is found in target entity
attribute.type.referenceAttribute(targetAttribute.name);
});
}
if (attribute.primary) {
util_1.passOrThrow(!this._primaryAttribute, function () {
return "'" + _this.name + "." + attributeName + "' cannot be set as primary attribute," +
("'" + _this._primaryAttribute.name + "' is already the primary attribute");
});
util_1.passOrThrow(DataType_1.isDataType(attribute.type), function () {
return "Primary attribute '" + _this.name + "." + attributeName + "' has invalid data type '" + String(attribute.type) + "'";
});
attribute.isSystemAttribute = true;
this._primaryAttribute = attribute;
}
util_1.passOrThrow(!attribute.resolve || util_1.isFunction(attribute.resolve), function () { return "'" + _this.name + "." + attributeName + "' has an invalid resolve function'"; });
util_1.passOrThrow(!attribute.defaultValue || util_1.isFunction(attribute.defaultValue), function () {
return "'" + _this.name + "." + attributeName + "' has an invalid defaultValue function'";
});
util_1.passOrThrow(!attribute.validate || util_1.isFunction(attribute.validate), function () { return "'" + _this.name + "." + attributeName + "' has an invalid validate function'"; });
util_1.passOrThrow(!attribute.serialize || util_1.isFunction(attribute.serialize), function () {
return "'" + _this.name + "." + attributeName + "' has an invalid serialize function'";
});
return attribute;
};
Entity.prototype.processAttributeMap = function () {
var _this = this;
// if it's a function, resolve it to get that map
var attributeMap = typeof this.setup.attributes === 'object'
? __assign({}, this.setup.attributes) : this.setup.attributes();
util_1.passOrThrow(util_1.isMap(attributeMap), function () {
return "Attribute definition function for entity '" + _this.name + "' does not return a map";
});
var attributeNames = Object.keys(attributeMap);
util_1.passOrThrow(attributeNames.length > 0, function () { return "Entity '" + _this.name + "' has no attributes defined"; });
var resultAttributes = {};
attributeNames.forEach(function (attributeName) {
resultAttributes[attributeName] = _this.processAttribute(attributeMap[attributeName], attributeName);
});
attributeNames.forEach(function (attributeName) {
var attribute = resultAttributes[attributeName];
if (attribute.targetAttributesMap) {
var localAttributeNames = Object.keys(attribute.targetAttributesMap);
localAttributeNames.map(function (localAttributeName) {
util_1.passOrThrow(resultAttributes[localAttributeName], function () {
return "Unknown local attribute '" + localAttributeName + "' used in targetAttributesMap " +
("for '" + _this.name + "." + attributeName + "'");
});
});
}
});
var systemAttributeNames = this._collectSystemAttributes(attributeMap);
systemAttributeNames.forEach(function (attributeName) {
resultAttributes[attributeName] = _this.processAttribute(attributeMap[attributeName], attributeName);
resultAttributes[attributeName].isSystemAttribute = true;
});
var rankedResultAttributes = {};
Object.keys(resultAttributes).map(function (attributeName) {
var attribute = resultAttributes[attributeName];
if (attribute.primary) {
rankedResultAttributes[attributeName] = attribute;
}
});
Object.keys(resultAttributes).map(function (attributeName) {
var attribute = resultAttributes[attributeName];
if (!attribute.primary) {
rankedResultAttributes[attributeName] = attribute;
}
});
return rankedResultAttributes;
};
Entity.prototype.getPrimaryAttribute = function () {
return this._primaryAttribute;
};
Entity.prototype.referenceAttribute = function (attributeName) {
var _this = this;
var attributes = this.getAttributes();
util_1.passOrThrow(attributes[attributeName], function () {
return "Cannot reference attribute '" + _this.name + "." + attributeName + "' as it does not exist";
});
return attributes[attributeName];
};
Entity.prototype.getI18nAttributeNames = function () {
var attributes = this.getAttributes();
var attributeNames = Object.keys(attributes);
var i18nAttributeNames = attributeNames.filter(function (attributeName) { return attributes[attributeName].i18n; });
return i18nAttributeNames.length ? i18nAttributeNames : null;
};
Entity.prototype.getDefaultMutations = function () {
var _this = this;
var nonSystemAttributeNames = [];
util_1.mapOverProperties(this.getAttributes(), function (attribute, attributeName) {
if (!attribute.isSystemAttribute) {
nonSystemAttributeNames.push(attributeName);
}
});
var mutations = {};
Mutation_1.defaultEntityMutations.map(function (defaultMutation) {
var key = defaultMutation.name + "Mutation";
mutations[key] = new Mutation_1.Mutation({
name: defaultMutation.name,
type: defaultMutation.type,
description: defaultMutation.description(_this.name),
attributes: nonSystemAttributeNames,
});
});
return mutations;
};
Entity.prototype.processPermissions = function () {
if (this.setup.permissions) {
var permissions = typeof this.setup.permissions === 'function'
? this.setup.permissions()
: this.setup.permissions;
return Permission_1.processEntityPermissions(this, permissions, this.defaultPermissions);
}
else if (this.defaultPermissions) {
return Permission_1.processEntityPermissions(this, {}, this.defaultPermissions);
}
return null;
};
Entity.prototype._generatePermissionDescriptions = function () {
var _this = this;
if (this.permissions) {
if (this.permissions.find) {
this.descriptionPermissionsFind = Permission_1.generatePermissionDescription(this.permissions.find);
}
if (this.permissions.read) {
this.descriptionPermissionsRead = Permission_1.generatePermissionDescription(this.permissions.read);
}
if (this.permissions.mutations && this.mutations) {
this.mutations.map(function (mutation) {
var mutationName = mutation.name;
var permission = _this.permissions.mutations[mutationName];
if (permission) {
var descriptionPermissions = Permission_1.generatePermissionDescription(permission);
if (descriptionPermissions) {
mutation.description += descriptionPermissions;
}
}
});
}
if (this.permissions.subscriptions && this.subscriptions) {
this.subscriptions.map(function (subscription) {
var subscriptionName = subscription.name;
var permission = _this.permissions.subscriptions[subscriptionName];
if (permission) {
var descriptionPermissions = Permission_1.generatePermissionDescription(permission);
if (descriptionPermissions) {
subscription.description += descriptionPermissions;
}
}
});
}
}
};
Entity.prototype._processPreFilters = function (preFilters) {
return preFilters ? filter_1.processPreFilters(this, preFilters) : null;
};
Entity.prototype.getPreFilters = function () {
if (this.preFilters) {
return this.preFilters;
}
if (typeof this.setup.preFilters === 'function') {
this.setup.preFilters = this.setup.preFilters();
}
this.preFilters = this._processPreFilters(this.setup.preFilters);
return this.preFilters;
};
Entity.prototype.getPermissions = function () {
if (!this.setup.permissions && !this.defaultPermissions) {
return this.permissions;
}
this.getMutations();
this.getSubscriptions();
this.permissions = this.processPermissions();
this._generatePermissionDescriptions();
return this.permissions;
};
Entity.prototype.referencedBy = function (sourceEntityName, sourceAttributeName) {
var _this = this;
util_1.passOrThrow(sourceEntityName, function () { return "Entity '" + _this.name + "' expects an entity to be referenced by"; });
util_1.passOrThrow(sourceAttributeName, function () {
return "Entity '" + _this.name + "' expects a source attribute to be referenced by";
});
var found = false;
this.referencedByEntities.map(function (entry) {
if (entry.sourceEntityName === sourceEntityName &&
entry.sourceAttributeName === sourceAttributeName) {
found = true;
}
});
if (!found) {
this.referencedByEntities.push({
sourceEntityName: sourceEntityName,
sourceAttributeName: sourceAttributeName,
});
}
};
Entity.prototype.getStorageType = function () {
return this.storageType;
};
Entity.prototype.toString = function () {
return this.name;
};
return Entity;
}());
exports.Entity = Entity;
var isEntity = function (obj) {
return obj instanceof Entity;
};
exports.isEntity = isEntity;