UNPKG

shyft

Version:

Model driven GraphQL API framework

549 lines (548 loc) 27 kB
"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;