UNPKG

shyft-storage-connector

Version:
711 lines (580 loc) 25.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getConnection = exports.disconnectStorage = exports.connectStorage = exports.installStorageScripts = exports.generateMockData = exports.loadModels = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _StorageTypePostgres = _interopRequireDefault(require("./StorageTypePostgres")); var _lodash = _interopRequireDefault(require("lodash")); var _toposort = _interopRequireDefault(require("toposort")); var _util = require("./util"); var _shyft = require("shyft"); var _jsonShaper = require("json-shaper"); var _typeorm = require("typeorm"); var _StoragePostgresConfiguration = require("./StoragePostgresConfiguration"); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } var filterOperatorMap = { $ne: '$ne', $in: '$in', $notIn: '$not_in', $lt: '$lt', $lte: '$lte', $gt: '$gt', $gte: '$gte', $startsWith: '$starts_with', $contains: '$contains', $endsWith: '$ends_with', $notStartsWith: '$not_starts_with', $notContains: '$not_contains', $notEndsWith: '$not_ends_with', $includes: '$includes', $notIncludes: '$not_includes', $isNull: '$is_null', $noResult: '$noResult', $not: '$not', $or: '$or', $and: '$and' }; var loadModels = function loadModels(configuration) { if (!(0, _shyft.isConfiguration)(configuration)) { throw new Error('Invalid configuration object provided to loadModels()'); } var schema = configuration.getSchema(); var storageConfiguration = configuration.getStorageConfiguration(); if (!(0, _StoragePostgresConfiguration.isStoragePostgresConfiguration)(storageConfiguration)) { throw new Error('Invalid storage configuration object provided to loadModels()'); } _StorageTypePostgres["default"].setStorageConfiguration(storageConfiguration); var modelRegistry = {}; _lodash["default"].map(schema.getEntities(), function (entity, entityName) { if (String(entity.storageType) !== String(_StorageTypePostgres["default"])) { return; } var attributes = {}; var references = []; var dataShaperMap = {}; var filterShaperMap = {}; var foreignKeyIndices = []; var Skeleton = function Skeleton() {}; Object.defineProperty(Skeleton, 'name', { value: entityName }); _lodash["default"].map(entity.getAttributes(), function (attribute) { // skip for computed values if (attribute.resolve) { return; } // skip for mutation inputs if (attribute.mutationInput) { return; } var attributeName = attribute.name; var storageAttributeName; if (attribute.meta && attribute.meta.storageAttributeName) { storageAttributeName = attribute.meta.storageAttributeName; } else if ((0, _shyft.isViewEntity)(entity)) { storageAttributeName = attribute.name; } else { storageAttributeName = _lodash["default"].snakeCase(attribute.name); } dataShaperMap[attributeName] = storageAttributeName; filterShaperMap[attributeName] = attributeName; var storageDataType; // it's a reference if ((0, _shyft.isEntity)(attribute.type) || (0, _shyft.isShadowEntity)(attribute.type)) { var primaryAttribute = attribute.type.getPrimaryAttribute(); storageDataType = _StorageTypePostgres["default"].convertToStorageDataType(primaryAttribute.type); var targetEntityName = attribute.type.name; if (attribute.targetAttributesMap) { // TODO: check composite foreign keys support (0, _shyft.mapOverProperties)(attribute.targetAttributesMap, function (targetAttribute, sourceAttributeName) { references.push({ sourceAttributeName: sourceAttributeName, targetAttributeName: targetAttribute.name, targetEntityName: targetEntityName }); }); } else { references.push({ sourceAttributeName: attributeName, targetAttributeName: primaryAttribute.name, targetEntityName: targetEntityName }); var foreignKeyIndexName = (0, _util.generateIndexName)(_lodash["default"].snakeCase(entityName), [_lodash["default"].snakeCase(attributeName)], 'key'); var unique = false; // checking if there is a defined index for the foreign key if (entity.indexes) { var definedForeignKeyIndex = entity.indexes.filter(function (index) { return _lodash["default"].isEqual(index.attributes, [attributeName]); }); if (definedForeignKeyIndex && definedForeignKeyIndex.length > 0) { unique = definedForeignKeyIndex[0].type === _shyft.INDEX_UNIQUE; } } (0, _typeorm.Index)(foreignKeyIndexName, [attributeName], { unique: unique })(Skeleton); foreignKeyIndices.push(foreignKeyIndexName); } (0, _typeorm.ManyToOne)(function () { return modelRegistry[targetEntityName].model; }, { onDelete: 'CASCADE' })(Skeleton.prototype, storageAttributeName); (0, _typeorm.JoinColumn)({ name: storageAttributeName, cascadeAll: true })(Skeleton.prototype, storageAttributeName); } // it's a regular attribute else { storageDataType = _StorageTypePostgres["default"].convertToStorageDataType(attribute.type); } attributes[attributeName] = { name: storageAttributeName, type: storageDataType.nativeDataType, primary: attribute.primary, nullable: !attribute.required }; if (attribute.primary) { var primaryGenerator = storageDataType.name === 'StorageDataTypeUUID' ? 'uuid' : 'increment'; (0, _typeorm.PrimaryGeneratedColumn)(primaryGenerator, attributes[attributeName])(Skeleton.prototype, attributeName); } else if ((0, _shyft.isEntity)(entity) || (0, _shyft.isShadowEntity)(entity)) { (0, _typeorm.Column)(attributes[attributeName])(Skeleton.prototype, attributeName); } else if ((0, _shyft.isViewEntity)(entity)) { (0, _typeorm.ViewColumn)(attributes[attributeName])(Skeleton.prototype, attributeName); } }); var constraints = { unique: {} }; if (entity.indexes) { entity.indexes.map(function (index) { if (index.type === _shyft.INDEX_UNIQUE || index.type === _shyft.INDEX_GENERIC) { var indexAttributes = index.attributes.map(_lodash["default"].snakeCase); var indexName = (0, _util.generateIndexName)(_lodash["default"].snakeCase(entityName), indexAttributes, 'key'); var unique = index.type === _shyft.INDEX_UNIQUE; if (!foreignKeyIndices.includes(indexName)) { (0, _typeorm.Index)(indexName, index.attributes, { unique: unique })(Skeleton); } constraints.unique[indexName] = { attributes: index.attributes }; } }); } var storageTableName = _lodash["default"].snakeCase(entityName); entity.storageTableName = storageTableName; if ((0, _shyft.isEntity)(entity)) { (0, _typeorm.Entity)({ name: storageTableName })(Skeleton); } else if ((0, _shyft.isShadowEntity)(entity)) { (0, _typeorm.Entity)({ name: storageTableName, synchronize: false })(Skeleton); } else if ((0, _shyft.isViewEntity)(entity)) { (0, _typeorm.ViewEntity)({ name: storageTableName, expression: entity.viewExpression })(Skeleton); } modelRegistry[entityName] = { model: Skeleton, storageTableName: storageTableName, dataShaperMap: dataShaperMap, reverseDataShaperMap: _lodash["default"].invert(dataShaperMap), dataShaper: (0, _jsonShaper.shaper)(dataShaperMap), reverseDataShaper: (0, _jsonShaper.shaper)(_lodash["default"].invert(dataShaperMap)), filterShaper: (0, _jsonShaper.shaper)(_lodash["default"].extend(filterShaperMap, filterOperatorMap)), references: references, constraints: constraints }; }); return modelRegistry; }; exports.loadModels = loadModels; var generateMockData = /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(configuration) { var schema, languages, storageConfiguration, storageInstance, modelRegistry, edges, entities, mockInstancesMemory, dependencySortedEntityNames, e, entityName, entity, mockItemCount, i; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if ((0, _shyft.isConfiguration)(configuration)) { _context.next = 2; break; } throw new Error('Invalid configuration object provided to generateMockData()'); case 2: schema = configuration.getSchema(); languages = configuration.getLanguages(); storageConfiguration = configuration.getStorageConfiguration(); storageInstance = storageConfiguration.getStorageInstance(); modelRegistry = storageConfiguration.getStorageModels(); edges = []; entities = schema.getEntities(); mockInstancesMemory = {}; _lodash["default"].map(entities, function (entity) { _lodash["default"].map(entity.getAttributes(), function (attribute) { if ((0, _shyft.isEntity)(attribute.type)) { // skip cyclic dependencies if (entity.name === attribute.type.name) { return; } edges.push([attribute.type.name, entity.name]); } }); }); dependencySortedEntityNames = (0, _toposort["default"])(edges); // add independent entities _lodash["default"].map(entities, function (entity) { if (dependencySortedEntityNames.indexOf(entity.name) === -1) { dependencySortedEntityNames.push(entity.name); } }); e = 0; case 14: if (!(e < dependencySortedEntityNames.length)) { _context.next = 36; break; } entityName = dependencySortedEntityNames[e]; entity = entities[entityName]; if (!(String(entity.storageType) !== String(_StorageTypePostgres["default"]))) { _context.next = 19; break; } return _context.abrupt("return"); case 19: _context.prev = 19; mockItemCount = entity.meta && entity.meta.mockItemsCount >= 0 ? entity.meta.mockItemsCount : _lodash["default"].random(10, 100); i = 0; case 22: if (!(i < mockItemCount)) { _context.next = 28; break; } _context.next = 25; return generateItem(storageInstance, entity, mockInstancesMemory, modelRegistry[entityName], languages); case 25: i++; _context.next = 22; break; case 28: _context.next = 33; break; case 30: _context.prev = 30; _context.t0 = _context["catch"](19); console.error(_context.t0); case 33: e++; _context.next = 14; break; case 36: case "end": return _context.stop(); } } }, _callee, null, [[19, 30]]); })); return function generateMockData(_x) { return _ref.apply(this, arguments); }; }(); exports.generateMockData = generateMockData; var getExistingData = /*#__PURE__*/function () { var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(storageInstance, mockInstancesMemory, entity) { var entityName, storageTableName, manager, result; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: entityName = entity.name, storageTableName = entity.storageTableName; manager = storageInstance.manager; _context2.next = 4; return manager.createQueryBuilder(storageTableName, 't').select(['t.id']).getMany(); case 4: result = _context2.sent; if (result.length) { mockInstancesMemory[entityName] = result.map(function (_ref3) { var id = _ref3.id; return id; }); } else { mockInstancesMemory[entityName] = []; } case 6: case "end": return _context2.stop(); } } }, _callee2); })); return function getExistingData(_x2, _x3, _x4) { return _ref2.apply(this, arguments); }; }(); function generateItem(_x5, _x6, _x7, _x8, _x9) { return _generateItem.apply(this, arguments); } function _generateItem() { _generateItem = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(storageInstance, entity, mockInstancesMemory, model, languages) { var entityName, storageTableName, item, manager, instance, result, _entity$getPrimaryAtt, primaryAttributeName; return _regenerator["default"].wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: entityName = entity.name, storageTableName = entity.storageTableName; item = {}; _context7.next = 4; return Promise.all(_lodash["default"].map(entity.getAttributes(), /*#__PURE__*/function () { var _ref8 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(_ref7, name) { var type, primary, required, mock, mockDataGenerator; return _regenerator["default"].wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: type = _ref7.type, primary = _ref7.primary, required = _ref7.required, mock = _ref7.mock; if (!primary) { _context6.next = 3; break; } return _context6.abrupt("return"); case 3: if (required) { _context6.next = 7; break; } if (!(!entity.meta || entity.meta && !entity.meta.mockNoNulls)) { _context6.next = 7; break; } if (!(Math.random() > 0.5)) { _context6.next = 7; break; } return _context6.abrupt("return"); case 7: if (!(0, _shyft.isEntity)(type)) { _context6.next = 12; break; } if (mockInstancesMemory[type.name]) { _context6.next = 11; break; } _context6.next = 11; return getExistingData(storageInstance, mockInstancesMemory, type); case 11: item[name] = _lodash["default"].sample(mockInstancesMemory[type.name]); case 12: if ((0, _shyft.isComplexDataType)(type)) { // TODO: generate mocks based on complex types item[name] = {}; } else { mockDataGenerator = mock || type.mock; if (mockDataGenerator) { item[name] = mockDataGenerator(entity, name, model, languages); } } case 13: case "end": return _context6.stop(); } } }, _callee6); })); return function (_x12, _x13) { return _ref8.apply(this, arguments); }; }())); case 4: manager = storageInstance.manager; _context7.next = 7; return manager.createQueryBuilder().insert().into(storageTableName).values(item).returning('*').execute(); case 7: result = _context7.sent; if (result.raw.length) { instance = result.raw[0]; _entity$getPrimaryAtt = entity.getPrimaryAttribute(), primaryAttributeName = _entity$getPrimaryAtt.name; mockInstancesMemory[entityName] = mockInstancesMemory[entityName] || []; mockInstancesMemory[entityName].push(instance[primaryAttributeName]); } case 9: case "end": return _context7.stop(); } } }, _callee7); })); return _generateItem.apply(this, arguments); } var installStorageScripts = /*#__PURE__*/function () { var _ref4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(configuration) { var synchronize, storageConfiguration, languages, storageInstance, manager, modelFeatures, schema, _args3 = arguments; return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: synchronize = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : false; storageConfiguration = configuration.getStorageConfiguration(); languages = configuration.getLanguages(); storageInstance = storageConfiguration.getStorageInstance(); manager = storageInstance.manager; modelFeatures = {}; schema = configuration.getSchema(); if (languages.length > 1) { modelFeatures.language = true; } _lodash["default"].forEach(schema.getEntities(), function (entity) { if (entity.getI18nAttributeNames && entity.getI18nAttributeNames()) { modelFeatures.i18n = true; } if (entity.hasStates && entity.hasStates()) { modelFeatures.state = true; } }); if (!modelFeatures.state) { _context3.next = 18; break; } _context3.next = 12; return manager.query(storageConfiguration.generateGetStateIdFunction(configuration)); case 12: _context3.next = 14; return manager.query(storageConfiguration.generateGetStateIdsFunction(configuration)); case 14: _context3.next = 16; return manager.query(storageConfiguration.generateGetStateMapFunction(configuration)); case 16: _context3.next = 18; return manager.query(storageConfiguration.generateGetStateNameFunction(configuration)); case 18: if (!modelFeatures.i18n) { _context3.next = 28; break; } _context3.next = 21; return manager.query(storageConfiguration.generateGetAttributeTranslationFunction(configuration)); case 21: _context3.next = 23; return manager.query(storageConfiguration.generateGetAttributeTranslationsFunction(configuration)); case 23: _context3.next = 25; return manager.query(storageConfiguration.generateMergeTranslationsFunction(configuration)); case 25: if (!synchronize) { _context3.next = 28; break; } _context3.next = 28; return manager.query(storageConfiguration.createI18nIndices(configuration, manager)); case 28: case "end": return _context3.stop(); } } }, _callee3); })); return function installStorageScripts(_x10) { return _ref4.apply(this, arguments); }; }(); exports.installStorageScripts = installStorageScripts; var connection; var connectStorage = /*#__PURE__*/function () { var _ref5 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(configuration) { var synchronize, dropSchema, onConnect, storageConfiguration, connectionConfig, modelRegistry, entities, loggerOptions, _args4 = arguments; return _regenerator["default"].wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: synchronize = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : false; dropSchema = _args4.length > 2 && _args4[2] !== undefined ? _args4[2] : false; onConnect = _args4.length > 3 ? _args4[3] : undefined; storageConfiguration = configuration.getStorageConfiguration(); connectionConfig = storageConfiguration.getConnectionConfig(); modelRegistry = loadModels(configuration); entities = Object.keys(modelRegistry).map(function (entityName) { return modelRegistry[entityName].model; }); _context4.next = 9; return (0, _typeorm.createConnection)(_objectSpread(_objectSpread({}, connectionConfig), {}, { type: 'postgres', synchronize: synchronize, dropSchema: dropSchema, entities: entities })); case 9: connection = _context4.sent; if (onConnect) { onConnect(connection); } storageConfiguration.setStorageInstance(connection); storageConfiguration.setStorageModels(modelRegistry); // remember logger settings and disable logger loggerOptions = connection.logger.options; connection.logger.options = false; _context4.next = 17; return installStorageScripts(configuration, synchronize); case 17: // bring back logger options connection.logger.options = loggerOptions; case 18: case "end": return _context4.stop(); } } }, _callee4); })); return function connectStorage(_x11) { return _ref5.apply(this, arguments); }; }(); exports.connectStorage = connectStorage; var disconnectStorage = /*#__PURE__*/function () { var _ref6 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5() { return _regenerator["default"].wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: if (!connection) { _context5.next = 3; break; } _context5.next = 3; return connection.close(); case 3: case "end": return _context5.stop(); } } }, _callee5); })); return function disconnectStorage() { return _ref6.apply(this, arguments); }; }(); exports.disconnectStorage = disconnectStorage; var getConnection = function getConnection() { return connection; }; exports.getConnection = getConnection;