shyft-storage-connector
Version:
Storage connector for Shyft
711 lines (580 loc) • 25.2 kB
JavaScript
;
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;