@dbml/core
Version:
> TODO: description
453 lines (444 loc) • 23.8 kB
JavaScript
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;
;