UNPKG

@dbml/core

Version:
453 lines (444 loc) 23.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _lodash = _interopRequireDefault(require("lodash")); var _utils = require("./utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); 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 = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } var OracleExporter = /*#__PURE__*/function () { function OracleExporter() { _classCallCheck(this, OracleExporter); } _createClass(OracleExporter, null, [{ key: "buildSchemaToTableNameSetMap", value: function buildSchemaToTableNameSetMap(model) { var schemaToTableNameSetMap = new Map(); _lodash["default"].forEach(model.tables, function (table) { var schema = model.schemas[table.schemaId]; var tableSet = schemaToTableNameSetMap.get(schema.name); if (!tableSet) { schemaToTableNameSetMap.set(schema.name, new Set([table.name])); return; } tableSet.add(table.name); }); return schemaToTableNameSetMap; } }, { key: "buildTableNameWithSchema", value: function buildTableNameWithSchema(model, schema, table) { return "".concat((0, _utils.shouldPrintSchema)(schema, model) ? "".concat((0, _utils.escapeObjectName)(schema.name, 'oracle'), ".") : '').concat((0, _utils.escapeObjectName)(table.name, 'oracle')); } }, { key: "exportSchema", value: function exportSchema(schemaName) { // According to Oracle, CREATE SCHEMA statement does not actually create a schema and it automatically creates a schema when we create a user // Learn more: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CREATE-SCHEMA.html#GUID-2D154F9C-9E2B-4A09-B658-2EA5B99AC838__GUID-CC0A5080-2AF3-4460-AB2B-DEA6C79519BA return "CREATE USER ".concat((0, _utils.escapeObjectName)(schemaName, 'oracle'), "\n") + 'NO AUTHENTICATION\n' + 'DEFAULT TABLESPACE system\n' + 'TEMPORARY TABLESPACE temp\n' + 'QUOTA UNLIMITED ON system;\n'; } }, { key: "getFieldLines", value: function getFieldLines(tableId, model) { var table = model.tables[tableId]; var lines = table.fieldIds.map(function (fieldId) { var field = model.fields[fieldId]; var fieldName = (0, _utils.escapeObjectName)(field.name, 'oracle'); var line = fieldName; if (field.enumId) { var _enum = model.enums[field.enumId]; var enumValues = _enum.valueIds.map(function (valueId) { var value = model.enumValues[valueId]; return "'".concat(value.name, "'"); }); var enumString = enumValues.join(', '); line += " nvarchar2(255) NOT NULL CHECK (".concat(fieldName, " IN (").concat(enumString, "))"); } else { line += " ".concat(field.type.type_name); } var cloneField = _objectSpread({}, field); if (cloneField.increment) { line += ' GENERATED AS IDENTITY'; // in oracle, increment means using identity. If a clause includes identity, we must ignore not null + default value cloneField.dbdefault = null; cloneField.not_null = false; } if (cloneField.unique) { line += ' UNIQUE'; } if (cloneField.pk) { line += ' PRIMARY KEY'; } if (cloneField.not_null) { line += ' NOT NULL'; } if (cloneField.dbdefault) { if (cloneField.dbdefault.type === 'string') { line += " DEFAULT '".concat(cloneField.dbdefault.value, "'"); } else { line += " DEFAULT ".concat(cloneField.dbdefault.value); } } return line; }); return lines; } }, { key: "getCompositePKs", value: function getCompositePKs(tableId, model) { var table = model.tables[tableId]; var compositePkIds = table.indexIds ? table.indexIds.filter(function (indexId) { return model.indexes[indexId].pk; }) : []; var lines = compositePkIds.map(function (keyId) { var key = model.indexes[keyId]; var line = 'PRIMARY KEY'; var columnArr = []; key.columnIds.forEach(function (columnId) { var column = model.indexColumns[columnId]; var columnStr = ''; if (column.type === 'expression') { columnStr = "(".concat(column.value, ")"); } else { columnStr = "\"".concat(column.value, "\""); } columnArr.push(columnStr); }); line += " (".concat(columnArr.join(', '), ")"); return line; }); return lines; } }, { key: "getTableContents", value: function getTableContents(tableIds, model) { var _this = this; var tableContentArr = tableIds.map(function (tableId) { var fieldContents = _this.getFieldLines(tableId, model); var compositePKs = _this.getCompositePKs(tableId, model); return { tableId: tableId, fieldContents: fieldContents, compositePKs: compositePKs }; }); return tableContentArr; } }, { key: "exportTables", value: function exportTables(tableIds, model) { var _this2 = this; var tableContentList = this.getTableContents(tableIds, model); var tableStrs = tableContentList.map(function (tableContent) { var content = [].concat(_toConsumableArray(tableContent.fieldContents), _toConsumableArray(tableContent.compositePKs)); var table = model.tables[tableContent.tableId]; var schema = model.schemas[table.schemaId]; var tableName = _this2.buildTableNameWithSchema(model, schema, table); var contentString = content.map(function (line) { return " ".concat(line); }).join(',\n'); var tableStr = "CREATE TABLE ".concat(tableName, " (\n").concat(contentString, "\n);\n"); return tableStr; }); return tableStrs; } }, { key: "buildReferenceFieldNamesString", value: function buildReferenceFieldNamesString(fieldIds, model) { var fieldNames = fieldIds.map(function (fieldId) { return "\"".concat(model.fields[fieldId].name, "\""); }).join(', '); return "(".concat(fieldNames, ")"); } }, { key: "buildTableManyToMany", value: function buildTableManyToMany(firstTableFieldsMap, secondTableFieldsMap, tableName) { var line = "CREATE TABLE ".concat(tableName, " (\n"); firstTableFieldsMap.forEach(function (fieldType, fieldName) { line += " \"".concat(fieldName, "\" ").concat(fieldType, ",\n"); }); secondTableFieldsMap.forEach(function (fieldType, fieldName) { line += " \"".concat(fieldName, "\" ").concat(fieldType, ",\n"); }); var key1s = _toConsumableArray(firstTableFieldsMap.keys()).join('`, `'); var key2s = _toConsumableArray(secondTableFieldsMap.keys()).join('`, `'); line += " PRIMARY KEY (\"".concat(key1s, "\", \"").concat(key2s, "\")\n);\n"); return line; } }, { key: "buildForeignKeyManyToMany", value: function buildForeignKeyManyToMany(foreignEndpointTableName, foreignEndpointFields, refEndpointTableName, refEndpointFieldsString) { var foreignEndpointFieldsString = _toConsumableArray(foreignEndpointFields.keys()).join('`, `'); var line = "ALTER TABLE ".concat(foreignEndpointTableName, " ADD FOREIGN KEY (\"").concat(foreignEndpointFieldsString, "\") REFERENCES ").concat(refEndpointTableName, " ").concat(refEndpointFieldsString, ";\n"); return line; } }, { key: "exportReferencesAndNewTablesIfExists", value: function exportReferencesAndNewTablesIfExists(refIds, model, usedTableNameMap) { var _this3 = this; var result = { refs: [], tables: [] }; refIds.forEach(function (refId) { var ref = model.refs[refId]; // find the one relation in one-to-xxx or xxx-to-one relationship var refOneIndex = ref.endpointIds.findIndex(function (endpointId) { return model.endpoints[endpointId].relation === '1'; }); var refEndpointIndex = refOneIndex === -1 ? 0 : refOneIndex; // refEndpointIndex could be 0 or 1, so use 1 - refEndpointIndex will take the remained index var foreignEndpointId = ref.endpointIds[1 - refEndpointIndex]; var foreignEndpoint = model.endpoints[foreignEndpointId]; var foreignEndpointField = model.fields[foreignEndpoint.fieldIds[0]]; var foreignEndpointTable = model.tables[foreignEndpointField.tableId]; var foreignEndpointSchema = model.schemas[foreignEndpointTable.schemaId]; var foreignEndpointFieldNameString = _this3.buildReferenceFieldNamesString(foreignEndpoint.fieldIds, model); var refEndpointId = ref.endpointIds[refEndpointIndex]; var refEndpoint = model.endpoints[refEndpointId]; var refEndpointField = model.fields[refEndpoint.fieldIds[0]]; var refEndpointTable = model.tables[refEndpointField.tableId]; var refEndpointSchema = model.schemas[refEndpointTable.schemaId]; var refEndpointFieldNameString = _this3.buildReferenceFieldNamesString(refEndpoint.fieldIds, model); if (refOneIndex !== -1) { var foreignTableName = _this3.buildTableNameWithSchema(model, foreignEndpointSchema, foreignEndpointTable); var line = "ALTER TABLE ".concat(foreignTableName, " ADD"); if (ref.name) { line += " CONSTRAINT ".concat((0, _utils.escapeObjectName)(ref.name, 'oracle')); } var refTableName = _this3.buildTableNameWithSchema(model, refEndpointSchema, refEndpointTable); line += " FOREIGN KEY ".concat(foreignEndpointFieldNameString, " REFERENCES ").concat(refTableName, " ").concat(refEndpointFieldNameString); if (ref.onDelete) { line += " ON DELETE ".concat(ref.onDelete.toUpperCase()); } line += ';\n'; result.refs.push(line); return; } // many to many relationship var firstTableFieldsMap = (0, _utils.buildJunctionFields1)(refEndpoint.fieldIds, model); var secondTableFieldsMap = (0, _utils.buildJunctionFields2)(foreignEndpoint.fieldIds, model, firstTableFieldsMap); var newTableName = (0, _utils.buildUniqueTableName)(refEndpointSchema, refEndpointTable.name, foreignEndpointTable.name, usedTableNameMap); var tableNameSet = usedTableNameMap.get(refEndpointSchema); if (!tableNameSet) { usedTableNameMap.set(refEndpointSchema, new Set([newTableName])); } else { tableNameSet.add(newTableName); } var escapedNewTableName = "".concat((0, _utils.shouldPrintSchema)(refEndpointSchema, model) ? "\"".concat(refEndpointSchema.name, "\".") : '', "\"").concat(newTableName, "\""); result.tables.push(_this3.buildTableManyToMany(firstTableFieldsMap, secondTableFieldsMap, escapedNewTableName)); var firstTableName = _this3.buildTableNameWithSchema(model, refEndpointSchema, refEndpointTable); result.refs.push(_this3.buildForeignKeyManyToMany(escapedNewTableName, firstTableFieldsMap, firstTableName, refEndpointFieldNameString)); var secondTableName = _this3.buildTableNameWithSchema(model, foreignEndpointSchema, foreignEndpointTable); result.refs.push(_this3.buildForeignKeyManyToMany(escapedNewTableName, secondTableFieldsMap, secondTableName, foreignEndpointFieldNameString)); }); return result; } }, { key: "exportReferenceGrants", value: function exportReferenceGrants(model, refIds) { var _this4 = this; // only default schema -> ignore it if (Object.keys(model.schemas).length <= 1) { return []; } var tableNameList = []; refIds.forEach(function (refId) { var ref = model.refs[refId]; // find the one relation in one - many, many - one, one - one relationship var refOneIndex = ref.endpointIds.findIndex(function (endpointId) { return model.endpoints[endpointId].relation === '1'; }); var refEndpointIndex = refOneIndex === -1 ? 0 : refOneIndex; var refEndpointId = ref.endpointIds[refEndpointIndex]; var refEndpoint = model.endpoints[refEndpointId]; var refEndpointField = model.fields[refEndpoint.fieldIds[0]]; var refEndpointTable = model.tables[refEndpointField.tableId]; var refEndpointSchema = model.schemas[refEndpointTable.schemaId]; // refEndpointIndex could be 0 or 1, so use 1 - refEndpointIndex will take the remained index var foreignEndpointId = ref.endpointIds[1 - refEndpointIndex]; var foreignEndpoint = model.endpoints[foreignEndpointId]; var foreignEndpointField = model.fields[foreignEndpoint.fieldIds[0]]; var foreignEndpointTable = model.tables[foreignEndpointField.tableId]; var foreignEndpointSchema = model.schemas[foreignEndpointTable.schemaId]; // reference in the same schema if (refEndpointSchema.name === foreignEndpointSchema.name) { tableNameList.push(''); return; } var refTableName = _this4.buildTableNameWithSchema(model, refEndpointSchema, refEndpointTable); // refTableName is always needed to be grant tableNameList.push(refTableName); // one - many, many - one, one - one relationship if (refOneIndex !== -1) { return; } var foreignTableName = _this4.buildTableNameWithSchema(model, foreignEndpointSchema, foreignEndpointTable); tableNameList.push(foreignTableName); }); var tableToGrantList = tableNameList // remove duplicate .filter(function (table, index) { return table && tableNameList.indexOf(table) === index; }) // map into grant statement .map(function (table) { return "GRANT REFERENCES ON ".concat(table, " TO PUBLIC;\n"); }); return tableToGrantList; } }, { key: "exportIndexes", value: function exportIndexes(indexIds, model) { var _this5 = this; // exclude composite pk index var indexArr = indexIds.filter(function (indexId) { return !model.indexes[indexId].pk; }).map(function (indexId) { var index = model.indexes[indexId]; var table = model.tables[index.tableId]; var schema = model.schemas[table.schemaId]; var line = 'CREATE'; // ignore dbml index type: b-tree, hash if (index.unique) { line += ' UNIQUE'; } line += ' INDEX'; if (index.name) { line += " ".concat((0, _utils.escapeObjectName)(index.name, 'oracle')); } var tableName = _this5.buildTableNameWithSchema(model, schema, table); line += " ON ".concat(tableName); var columnArr = []; index.columnIds.forEach(function (columnId) { var column = model.indexColumns[columnId]; var columnStr = ''; if (column.type === 'expression') { columnStr = "".concat(column.value); } else { columnStr = "\"".concat(column.value, "\""); } columnArr.push(columnStr); }); var columnString = columnArr.join(', '); line += " (".concat(columnString, ");\n"); return line; }); return indexArr; } }, { key: "exportComments", value: function exportComments(comments, model) { var _this6 = this; var commentArr = comments.map(function (comment) { var line = 'COMMENT ON'; var table = model.tables[comment.tableId]; var schema = model.schemas[table.schemaId]; var tableName = _this6.buildTableNameWithSchema(model, schema, table); switch (comment.type) { case 'table': { line += " TABLE ".concat(tableName, " IS '").concat(table.note.replace(/'/g, "''"), "'"); break; } case 'column': { var field = model.fields[comment.fieldId]; line += " COLUMN ".concat(tableName, ".").concat((0, _utils.escapeObjectName)(field.name, 'oracle'), " IS '").concat(field.note.replace(/'/g, "''"), "'"); break; } default: break; } line += ';\n'; return line; }); return commentArr; } }, { key: "export", value: function _export(model) { var _this7 = this; var database = model.database['1']; var schemaToTableNameSetMap = this.buildSchemaToTableNameSetMap(model); var statements = database.schemaIds.reduce(function (prevStatements, schemaId) { var schema = model.schemas[schemaId]; var tableIds = schema.tableIds, refIds = schema.refIds; if ((0, _utils.shouldPrintSchema)(schema, model)) { prevStatements.schemas.push(_this7.exportSchema(schema.name)); } if (!_lodash["default"].isEmpty(tableIds)) { var _prevStatements$table; (_prevStatements$table = prevStatements.tables).push.apply(_prevStatements$table, _toConsumableArray(_this7.exportTables(tableIds, model))); } var indexIds = _lodash["default"].flatten(tableIds.map(function (tableId) { return model.tables[tableId].indexIds; })); if (!_lodash["default"].isEmpty(indexIds)) { var _prevStatements$index; (_prevStatements$index = prevStatements.indexes).push.apply(_prevStatements$index, _toConsumableArray(_this7.exportIndexes(indexIds, model))); } var commentNodes = _lodash["default"].flatten(tableIds.map(function (tableId) { var _model$tables$tableId = model.tables[tableId], fieldIds = _model$tables$tableId.fieldIds, note = _model$tables$tableId.note; var fieldObjects = fieldIds.filter(function (fieldId) { return model.fields[fieldId].note; }).map(function (fieldId) { return { type: 'column', fieldId: fieldId, tableId: tableId }; }); return note ? [{ type: 'table', tableId: tableId }].concat(fieldObjects) : fieldObjects; })); if (!_lodash["default"].isEmpty(commentNodes)) { var _prevStatements$comme; (_prevStatements$comme = prevStatements.comments).push.apply(_prevStatements$comme, _toConsumableArray(_this7.exportComments(commentNodes, model))); } if (!_lodash["default"].isEmpty(refIds)) { var _prevStatements$table2, _prevStatements$refs, _prevStatements$refer; var _this7$exportReferenc = _this7.exportReferencesAndNewTablesIfExists(refIds, model, schemaToTableNameSetMap), refs = _this7$exportReferenc.refs, manyToManyTables = _this7$exportReferenc.tables; (_prevStatements$table2 = prevStatements.tables).push.apply(_prevStatements$table2, _toConsumableArray(manyToManyTables)); (_prevStatements$refs = prevStatements.refs).push.apply(_prevStatements$refs, _toConsumableArray(refs)); (_prevStatements$refer = prevStatements.referenceGrants).push.apply(_prevStatements$refer, _toConsumableArray(_this7.exportReferenceGrants(model, refIds))); } return prevStatements; }, { schemas: [], tables: [], indexes: [], comments: [], referenceGrants: [], refs: [] }); var res = _lodash["default"].concat(statements.schemas, statements.tables, statements.indexes, statements.comments, statements.referenceGrants, statements.refs).join('\n'); return res; } }]); return OracleExporter; }(); var _default = OracleExporter; exports["default"] = _default;