"use strict";

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); }
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.fetchSchemaJson = void 0;
var _mssql = _interopRequireDefault(require("mssql"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": 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 _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return exports; }; var exports = {}, Op = Object.prototype, hasOwn = Op.hasOwnProperty, defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; }, $Symbol = "function" == typeof Symbol ? Symbol : {}, iteratorSymbol = $Symbol.iterator || "@@iterator", asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator", toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; function define(obj, key, value) { return Object.defineProperty(obj, key, { value: value, enumerable: !0, configurable: !0, writable: !0 }), obj[key]; } try { define({}, ""); } catch (err) { define = function define(obj, key, value) { return obj[key] = value; }; } function wrap(innerFn, outerFn, self, tryLocsList) { var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator, generator = Object.create(protoGenerator.prototype), context = new Context(tryLocsList || []); return defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) }), generator; } function tryCatch(fn, obj, arg) { try { return { type: "normal", arg: fn.call(obj, arg) }; } catch (err) { return { type: "throw", arg: err }; } } exports.wrap = wrap; var ContinueSentinel = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var IteratorPrototype = {}; define(IteratorPrototype, iteratorSymbol, function () { return this; }); var getProto = Object.getPrototypeOf, NativeIteratorPrototype = getProto && getProto(getProto(values([]))); NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype); var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype); function defineIteratorMethods(prototype) { ["next", "throw", "return"].forEach(function (method) { define(prototype, method, function (arg) { return this._invoke(method, arg); }); }); } function AsyncIterator(generator, PromiseImpl) { function invoke(method, arg, resolve, reject) { var record = tryCatch(generator[method], generator, arg); if ("throw" !== record.type) { var result = record.arg, value = result.value; return value && "object" == _typeof(value) && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) { invoke("next", value, resolve, reject); }, function (err) { invoke("throw", err, resolve, reject); }) : PromiseImpl.resolve(value).then(function (unwrapped) { result.value = unwrapped, resolve(result); }, function (error) { return invoke("throw", error, resolve, reject); }); } reject(record.arg); } var previousPromise; defineProperty(this, "_invoke", { value: function value(method, arg) { function callInvokeWithMethodAndArg() { return new PromiseImpl(function (resolve, reject) { invoke(method, arg, resolve, reject); }); } return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(innerFn, self, context) { var state = "suspendedStart"; return function (method, arg) { if ("executing" === state) throw new Error("Generator is already running"); if ("completed" === state) { if ("throw" === method) throw arg; return doneResult(); } for (context.method = method, context.arg = arg;;) { var delegate = context.delegate; if (delegate) { var delegateResult = maybeInvokeDelegate(delegate, context); if (delegateResult) { if (delegateResult === ContinueSentinel) continue; return delegateResult; } } if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) { if ("suspendedStart" === state) throw state = "completed", context.arg; context.dispatchException(context.arg); } else "return" === context.method && context.abrupt("return", context.arg); state = "executing"; var record = tryCatch(innerFn, self, context); if ("normal" === record.type) { if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue; return { value: record.arg, done: context.done }; } "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg); } }; } function maybeInvokeDelegate(delegate, context) { var methodName = context.method, method = delegate.iterator[methodName]; if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator["return"] && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel; var record = tryCatch(method, delegate.iterator, context.arg); if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel; var info = record.arg; return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel); } function pushTryEntry(locs) { var entry = { tryLoc: locs[0] }; 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry); } function resetTryEntry(entry) { var record = entry.completion || {}; record.type = "normal", delete record.arg, entry.completion = record; } function Context(tryLocsList) { this.tryEntries = [{ tryLoc: "root" }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0); } function values(iterable) { if (iterable) { var iteratorMethod = iterable[iteratorSymbol]; if (iteratorMethod) return iteratorMethod.call(iterable); if ("function" == typeof iterable.next) return iterable; if (!isNaN(iterable.length)) { var i = -1, next = function next() { for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next; return next.value = undefined, next.done = !0, next; }; return next.next = next; } } return { next: doneResult }; } function doneResult() { return { value: undefined, done: !0 }; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), defineProperty(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) { var ctor = "function" == typeof genFun && genFun.constructor; return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name)); }, exports.mark = function (genFun) { return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun; }, exports.awrap = function (arg) { return { __await: arg }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () { return this; }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) { void 0 === PromiseImpl && (PromiseImpl = Promise); var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl); return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) { return result.done ? result.value : iter.next(); }); }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () { return this; }), define(Gp, "toString", function () { return "[object Generator]"; }), exports.keys = function (val) { var object = Object(val), keys = []; for (var key in object) keys.push(key); return keys.reverse(), function next() { for (; keys.length;) { var key = keys.pop(); if (key in object) return next.value = key, next.done = !1, next; } return next.done = !0, next; }; }, exports.values = values, Context.prototype = { constructor: Context, reset: function reset(skipTempReset) { if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined); }, stop: function stop() { this.done = !0; var rootRecord = this.tryEntries[0].completion; if ("throw" === rootRecord.type) throw rootRecord.arg; return this.rval; }, dispatchException: function dispatchException(exception) { if (this.done) throw exception; var context = this; function handle(loc, caught) { return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught; } for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i], record = entry.completion; if ("root" === entry.tryLoc) return handle("end"); if (entry.tryLoc <= this.prev) { var hasCatch = hasOwn.call(entry, "catchLoc"), hasFinally = hasOwn.call(entry, "finallyLoc"); if (hasCatch && hasFinally) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } else if (hasCatch) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); } else { if (!hasFinally) throw new Error("try statement without catch or finally"); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } } } }, abrupt: function abrupt(type, arg) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) { var finallyEntry = entry; break; } } finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null); var record = finallyEntry ? finallyEntry.completion : {}; return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record); }, complete: function complete(record, afterLoc) { if ("throw" === record.type) throw record.arg; return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel; }, finish: function finish(finallyLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel; } }, "catch": function _catch(tryLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc === tryLoc) { var record = entry.completion; if ("throw" === record.type) { var thrown = record.arg; resetTryEntry(entry); } return thrown; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(iterable, resultName, nextLoc) { return this.delegate = { iterator: values(iterable), resultName: resultName, nextLoc: nextLoc }, "next" === this.method && (this.arg = undefined), ContinueSentinel; } }, exports; }
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } /* eslint-disable camelcase */
var MSSQL_DATE_TYPES = ['date', 'datetime', 'datetime2', 'smalldatetime', 'datetimeoffset', 'time'];
var getValidatedClient = /*#__PURE__*/function () {
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(connection) {
    var pool;
    return _regeneratorRuntime().wrap(function _callee$(_context) {
      while (1) switch (_context.prev = _context.next) {
        case 0:
          _context.prev = 0;
          _context.next = 3;
          return _mssql["default"].connect(connection);
        case 3:
          pool = _context.sent;
          _context.next = 6;
          return pool.request().query('SELECT 1');
        case 6:
          return _context.abrupt("return", pool);
        case 9:
          _context.prev = 9;
          _context.t0 = _context["catch"](0);
          // Log the error and handle it as per your application's requirement
          console.error('SQL connection error:', _context.t0);

          // Ensure to close any open pool in case of failure
          if (!_mssql["default"].connected) {
            _context.next = 15;
            break;
          }
          _context.next = 15;
          return _mssql["default"].close();
        case 15:
          throw _context.t0;
        case 16:
        case "end":
          return _context.stop();
      }
    }, _callee, null, [[0, 9]]);
  }));
  return function getValidatedClient(_x) {
    return _ref.apply(this, arguments);
  };
}();
var convertQueryBoolean = function convertQueryBoolean(val) {
  return val === 'YES';
};
var getFieldType = function getFieldType(data_type, default_type, character_maximum_length, numeric_precision, numeric_scale) {
  if (MSSQL_DATE_TYPES.includes(data_type)) {
    return data_type;
  }
  if (data_type === 'bit') {
    return data_type;
  }
  if (numeric_precision && numeric_scale && default_type === 'number') {
    return "".concat(data_type, "(").concat(numeric_precision, ",").concat(numeric_scale, ")");
  }
  if (character_maximum_length && character_maximum_length > 0 && default_type === 'string') {
    return "".concat(data_type, "(").concat(character_maximum_length, ")");
  }
  return data_type;
};
var getDbdefault = function getDbdefault(data_type, column_default, default_type) {
  // The regex below is used to extract the value from the default value
  // \( and \) are used to escape parentheses
  // [^()]+ is used to match any character except parentheses
  // Example: (1) => 1, ('hello') => hello, getdate()-(1) => getdate()-1
  var value = column_default.slice(1, -1).replace(/\(([^()]+)\)/g, '$1');
  return {
    type: default_type,
    value: default_type === 'string' ? value.slice(1, -1) : value // Remove the quotes for string values
  };
};

var getEnumValues = function getEnumValues(definition) {
  // Use the example below to understand the regex:
  // ([quantity]>(0))
  // ([unit_price]>(0))
  // ([status]='cancelled' OR [status]='delivered' OR [status]='shipped' OR [status]='processing' OR [status]='pending')
  // ([total_amount]>(0))
  // ([price]>(0))
  // ([stock_quantity]>=(0))
  // ([age_start]<=[age_end])
  // ([age_start]<=[age_end])
  // ([gender]='Other' OR [gender]='Female' OR [gender]='Male')
  // ([date_of_birth]<=dateadd(year,(-13),getdate()))
  // ([email] like '%_@_%._%')
  if (!definition) return null;
  var values = definition.match(/\[([^\]]+)\]='([^']+)'/g); // Extracting the enum values when the definition contains ]='
  if (!values) return null;
  var enumValues = values.map(function (value) {
    var enumValue = value.split("]='")[1];
    return {
      name: enumValue.slice(0, -1)
    };
  });
  return enumValues;
};
var generateField = function generateField(row) {
  var column_name = row.column_name,
    data_type = row.data_type,
    character_maximum_length = row.character_maximum_length,
    numeric_precision = row.numeric_precision,
    numeric_scale = row.numeric_scale,
    identity_increment = row.identity_increment,
    is_nullable = row.is_nullable,
    column_default = row.column_default,
    default_type = row.default_type,
    column_comment = row.column_comment;
  var dbdefault = column_default && default_type !== 'increment' ? getDbdefault(data_type, column_default, default_type) : null;
  var fieldType = {
    type_name: getFieldType(data_type, default_type, character_maximum_length, numeric_precision, numeric_scale),
    schemaname: null
  };
  return {
    name: column_name,
    type: fieldType,
    dbdefault: dbdefault,
    not_null: !convertQueryBoolean(is_nullable),
    increment: !!identity_increment,
    note: column_comment ? {
      value: column_comment
    } : {
      value: ''
    }
  };
};
var generateTablesFieldsAndEnums = /*#__PURE__*/function () {
  var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(client) {
    var fields, enums, tablesAndFieldsSql, tablesAndFieldsResult, tables;
    return _regeneratorRuntime().wrap(function _callee2$(_context2) {
      while (1) switch (_context2.prev = _context2.next) {
        case 0:
          fields = {};
          enums = [];
          tablesAndFieldsSql = "\n    WITH tables_and_fields AS (\n        SELECT\n            s.name AS table_schema,\n            t.name AS table_name,\n            c.name AS column_name,\n            ty.name AS data_type,\n            c.max_length AS character_maximum_length,\n            c.precision AS numeric_precision,\n            c.scale AS numeric_scale,\n            c.is_identity AS identity_increment,\n            CASE\n                WHEN c.is_nullable = 1 THEN 'YES'\n                ELSE 'NO'\n            END AS is_nullable,\n            CASE\n                WHEN c.default_object_id = 0 THEN NULL\n                ELSE OBJECT_DEFINITION(c.default_object_id)\n            END AS column_default,\n            -- Fetching table comments\n            p.value AS table_comment,\n            ep.value AS column_comment\n        FROM\n            sys.tables t\n        JOIN\n            sys.schemas s ON t.schema_id = s.schema_id\n        JOIN\n            sys.columns c ON t.object_id = c.object_id\n        JOIN\n            sys.types ty ON c.user_type_id = ty.user_type_id\n        LEFT JOIN\n            sys.extended_properties p ON p.major_id = t.object_id\n                AND p.name = 'MS_Description'\n                AND p.minor_id = 0 -- Ensure minor_id is 0 for table comments\n        LEFT JOIN\n            sys.extended_properties ep ON ep.major_id = c.object_id\n                AND ep.minor_id = c.column_id\n                AND ep.name = 'MS_Description'\n        WHERE\n            t.type = 'U' -- User-defined tables\n    )\n    SELECT\n        tf.table_schema,\n        tf.table_name,\n        tf.column_name,\n        tf.data_type,\n        tf.character_maximum_length,\n        tf.numeric_precision,\n        tf.numeric_scale,\n        tf.identity_increment,\n        tf.is_nullable,\n        tf.column_default,\n        tf.table_comment,\n        tf.column_comment,\n        cc.name AS check_constraint_name, -- Adding CHECK constraint name\n        cc.definition AS check_constraint_definition, -- Adding CHECK constraint definition\n        CASE\n            WHEN tf.column_default LIKE '((%))' THEN 'number'\n            WHEN tf.column_default LIKE '(''%'')' THEN 'string'\n            ELSE 'expression'\n        END AS default_type\n    FROM\n        tables_and_fields AS tf\n    LEFT JOIN\n        sys.check_constraints cc ON cc.parent_object_id = OBJECT_ID(tf.table_schema + '.' + tf.table_name)\n        AND cc.definition LIKE '%' + tf.column_name + '%' -- Ensure the constraint references the column\n    ORDER BY\n        tf.table_schema,\n        tf.table_name,\n        tf.column_name;\n  ";
          _context2.next = 5;
          return client.query(tablesAndFieldsSql);
        case 5:
          tablesAndFieldsResult = _context2.sent;
          tables = tablesAndFieldsResult.recordset.reduce(function (acc, row) {
            var table_schema = row.table_schema,
              table_name = row.table_name,
              table_comment = row.table_comment,
              check_constraint_name = row.check_constraint_name,
              check_constraint_definition = row.check_constraint_definition;
            var key = "".concat(table_schema, ".").concat(table_name);
            if (!acc[key]) {
              acc[key] = {
                name: table_name,
                schemaName: table_schema,
                note: table_comment ? {
                  value: table_comment
                } : {
                  value: ''
                }
              };
            }
            var enumValues = getEnumValues(check_constraint_definition);
            if (enumValues) {
              enums.push({
                name: check_constraint_name,
                schemaName: table_schema,
                values: enumValues
              });
            }
            if (!fields[key]) fields[key] = [];
            var field = generateField(row);
            if (enumValues) {
              field.type = {
                type_name: check_constraint_name,
                schemaName: table_schema
              };
            }
            fields[key].push(field);
            return acc;
          }, {});
          return _context2.abrupt("return", {
            tables: Object.values(tables),
            fields: fields,
            enums: enums
          });
        case 8:
        case "end":
          return _context2.stop();
      }
    }, _callee2);
  }));
  return function generateTablesFieldsAndEnums(_x2) {
    return _ref2.apply(this, arguments);
  };
}();
var generateRefs = /*#__PURE__*/function () {
  var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(client) {
    var refs, refsListSql, refsQueryResult;
    return _regeneratorRuntime().wrap(function _callee3$(_context3) {
      while (1) switch (_context3.prev = _context3.next) {
        case 0:
          refs = [];
          refsListSql = "\n    SELECT\n      s.name AS table_schema,\n      t.name AS table_name,\n      fk.name AS fk_constraint_name,\n      STUFF((\n        SELECT ',' + c1.name\n        FROM sys.foreign_key_columns AS fkc\n        JOIN sys.columns AS c1 ON fkc.parent_object_id = c1.object_id AND fkc.parent_column_id = c1.column_id\n        WHERE fkc.constraint_object_id = fk.object_id\n        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS column_names,\n      s2.name AS foreign_table_schema,\n      t2.name AS foreign_table_name,\n      STUFF((\n        SELECT ',' + c2.name\n        FROM sys.foreign_key_columns AS fkc\n        JOIN sys.columns AS c2 ON fkc.referenced_object_id = c2.object_id AND fkc.referenced_column_id = c2.column_id\n        WHERE fkc.constraint_object_id = fk.object_id\n        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS foreign_column_names,\n      fk.type_desc AS constraint_type,\n      fk.delete_referential_action_desc AS on_delete,\n      fk.update_referential_action_desc AS on_update\n    FROM sys.foreign_keys AS fk\n    JOIN sys.tables AS t ON fk.parent_object_id = t.object_id\n    JOIN sys.schemas AS s ON t.schema_id = s.schema_id\n    JOIN sys.tables AS t2 ON fk.referenced_object_id = t2.object_id\n    JOIN sys.schemas AS s2 ON t2.schema_id = s2.schema_id\n    WHERE s.name NOT IN ('sys', 'information_schema')\n    ORDER BY\n      s.name,\n      t.name;\n  ";
          _context3.next = 4;
          return client.query(refsListSql);
        case 4:
          refsQueryResult = _context3.sent;
          refsQueryResult.recordset.forEach(function (refRow) {
            var table_schema = refRow.table_schema,
              fk_constraint_name = refRow.fk_constraint_name,
              table_name = refRow.table_name,
              column_names = refRow.column_names,
              foreign_table_schema = refRow.foreign_table_schema,
              foreign_table_name = refRow.foreign_table_name,
              foreign_column_names = refRow.foreign_column_names,
              on_delete = refRow.on_delete,
              on_update = refRow.on_update;
            var ep1 = {
              tableName: table_name,
              schemaName: table_schema,
              fieldNames: column_names.split(','),
              relation: '*'
            };
            var ep2 = {
              tableName: foreign_table_name,
              schemaName: foreign_table_schema,
              fieldNames: foreign_column_names.split(','),
              relation: '1'
            };
            refs.push({
              name: fk_constraint_name,
              endpoints: [ep1, ep2],
              onDelete: on_delete === 'NO_ACTION' ? null : on_delete,
              onUpdate: on_update === 'NO_ACTION' ? null : on_update
            });
          });
          return _context3.abrupt("return", refs);
        case 7:
        case "end":
          return _context3.stop();
      }
    }, _callee3);
  }));
  return function generateRefs(_x3) {
    return _ref3.apply(this, arguments);
  };
}();
var generateIndexes = /*#__PURE__*/function () {
  var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(client) {
    var indexListSql, indexListResult, _indexListResult$reco, outOfLineConstraints, inlineConstraints, indexes, tableConstraints;
    return _regeneratorRuntime().wrap(function _callee4$(_context4) {
      while (1) switch (_context4.prev = _context4.next) {
        case 0:
          indexListSql = "\n    WITH user_tables AS (\n      SELECT\n        TABLE_SCHEMA,\n        TABLE_NAME\n      FROM\n        INFORMATION_SCHEMA.TABLES\n      WHERE\n        TABLE_TYPE = 'BASE TABLE'  -- Ensure we are only getting base tables\n        AND TABLE_NAME NOT LIKE 'dt%'\n        AND TABLE_NAME NOT LIKE 'syscs%'\n        AND TABLE_NAME NOT LIKE 'sysss%'\n        AND TABLE_NAME NOT LIKE 'sysrs%'\n        AND TABLE_NAME NOT LIKE 'sysxlgc%'\n    ),\n    index_info AS (\n      SELECT\n        OBJECT_NAME(i.object_id) AS table_name,\n        i.name AS index_name,\n        i.is_unique,\n        CASE\n          WHEN i.type = 1 THEN 1\n          ELSE 0\n        END AS is_primary,\n        i.type_desc AS index_type,\n        STUFF((\n          SELECT\n            ', ' + c.name\n          FROM\n            sys.index_columns ic\n            JOIN sys.columns c ON ic.column_id = c.column_id AND ic.object_id = c.object_id\n          WHERE\n            ic.index_id = i.index_id\n            AND ic.object_id = i.object_id\n            AND OBJECT_NAME(ic.object_id) IN (SELECT TABLE_NAME FROM user_tables)  -- Filter for user tables\n          ORDER BY\n            ic.key_ordinal\n          FOR XML PATH('')\n        ), 1, 2, '') AS columns,\n        CASE\n          WHEN i.type = 1 THEN 'PRIMARY KEY'\n          WHEN i.is_unique = 1 THEN 'UNIQUE'\n          ELSE NULL\n        END AS constraint_type\n      FROM\n        sys.indexes i\n        JOIN sys.tables t ON i.object_id = t.object_id\n      WHERE\n        t.is_ms_shipped = 0\n        AND i.type <> 0\n    )\n    SELECT\n      ut.TABLE_SCHEMA AS table_schema,\n      ut.TABLE_NAME AS table_name,\n      ii.index_name,\n      ii.is_unique,\n      ii.is_primary,\n      ii.index_type,\n      ii.columns,\n      ii.constraint_type\n    FROM\n      user_tables ut\n    LEFT JOIN\n      index_info ii ON ut.TABLE_NAME = ii.table_name\n    WHERE\n      ii.columns IS NOT NULL\n    ORDER BY\n      ut.TABLE_NAME,\n      ii.constraint_type,\n      ii.index_name;\n  ";
          _context4.next = 3;
          return client.query(indexListSql);
        case 3:
          indexListResult = _context4.sent;
          _indexListResult$reco = indexListResult.recordset.reduce(function (acc, row) {
            var constraint_type = row.constraint_type,
              columns = row.columns;
            if (columns === 'null' || columns.trim() === '') return acc;
            if (constraint_type === 'PRIMARY KEY' || constraint_type === 'UNIQUE') {
              acc.inlineConstraints.push(row);
            } else {
              acc.outOfLineConstraints.push(row);
            }
            return acc;
          }, {
            outOfLineConstraints: [],
            inlineConstraints: []
          }), outOfLineConstraints = _indexListResult$reco.outOfLineConstraints, inlineConstraints = _indexListResult$reco.inlineConstraints;
          indexes = outOfLineConstraints.reduce(function (acc, indexRow) {
            var table_schema = indexRow.table_schema,
              table_name = indexRow.table_name,
              index_name = indexRow.index_name,
              index_type = indexRow.index_type,
              columns = indexRow.columns,
              expressions = indexRow.expressions;
            var indexColumns = columns.split(',').map(function (column) {
              return {
                type: 'column',
                value: column.trim()
              };
            });
            var indexExpressions = expressions ? expressions.split(',').map(function (expression) {
              return {
                type: 'expression',
                value: expression
              };
            }) : [];
            var index = {
              name: index_name,
              type: index_type,
              columns: [].concat(_toConsumableArray(indexColumns), _toConsumableArray(indexExpressions))
            };
            var key = "".concat(table_schema, ".").concat(table_name);
            if (acc[key]) {
              acc[key].push(index);
            } else {
              acc[key] = [index];
            }
            return acc;
          }, {});
          tableConstraints = inlineConstraints.reduce(function (acc, row) {
            var table_schema = row.table_schema,
              table_name = row.table_name,
              columns = row.columns,
              constraint_type = row.constraint_type;
            var key = "".concat(table_schema, ".").concat(table_name);
            if (!acc[key]) acc[key] = {};
            var columnNames = columns.split(',').map(function (column) {
              return column.trim();
            });
            columnNames.forEach(function (columnName) {
              if (!acc[key][columnName]) acc[key][columnName] = {};
              if (constraint_type === 'PRIMARY KEY') {
                acc[key][columnName].pk = true;
              }
              if (constraint_type === 'UNIQUE' && !acc[key][columnName].pk) {
                acc[key][columnName].unique = true;
              }
            });
            return acc;
          }, {});
          return _context4.abrupt("return", {
            indexes: indexes,
            tableConstraints: tableConstraints
          });
        case 8:
        case "end":
          return _context4.stop();
      }
    }, _callee4);
  }));
  return function generateIndexes(_x4) {
    return _ref4.apply(this, arguments);
  };
}();
var fetchSchemaJson = /*#__PURE__*/function () {
  var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(connection) {
    var client, tablesFieldsAndEnumsRes, indexesRes, refsRes, res, _res$, tables, fields, enums, _res$2, indexes, tableConstraints, refs;
    return _regeneratorRuntime().wrap(function _callee5$(_context5) {
      while (1) switch (_context5.prev = _context5.next) {
        case 0:
          _context5.next = 2;
          return getValidatedClient(connection);
        case 2:
          client = _context5.sent;
          tablesFieldsAndEnumsRes = generateTablesFieldsAndEnums(client);
          indexesRes = generateIndexes(client);
          refsRes = generateRefs(client);
          _context5.next = 8;
          return Promise.all([tablesFieldsAndEnumsRes, indexesRes, refsRes]);
        case 8:
          res = _context5.sent;
          client.close();
          _res$ = res[0], tables = _res$.tables, fields = _res$.fields, enums = _res$.enums;
          _res$2 = res[1], indexes = _res$2.indexes, tableConstraints = _res$2.tableConstraints;
          refs = res[2];
          return _context5.abrupt("return", {
            tables: tables,
            fields: fields,
            enums: enums,
            refs: refs,
            indexes: indexes,
            tableConstraints: tableConstraints
          });
        case 14:
        case "end":
          return _context5.stop();
      }
    }, _callee5);
  }));
  return function fetchSchemaJson(_x5) {
    return _ref5.apply(this, arguments);
  };
}();
exports.fetchSchemaJson = fetchSchemaJson;