drapcode-utility 2.3.3 → 2.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -115,7 +115,7 @@ const decryptFile = async (encryptedFilePath, key, iv) => {
115
115
  };
116
116
  exports.decryptFile = decryptFile;
117
117
  const handleExtraString = (key, append = true) => {
118
- if (!key || key === "undefined")
118
+ if (!key || key === "undefined" || typeof key === "undefined")
119
119
  return key;
120
120
  if (append) {
121
121
  const prefix = crypto_1.default.randomBytes(2).toString("hex");
@@ -1,4 +1,4 @@
1
- import { PageContent, WebhookContent, ExternalApiContent, CustomComponentContent, CustomMappingContent, TaskContent, EventContent, SnippetContent, LocalizationContent, PluginContent, DevApiContent, TemplateContent, CollectionContent } from "./file-util";
1
+ import { PageContent, WebhookContent, ExternalApiContent, CustomComponentContent, CustomMappingContent, TaskContent, EventContent, SnippetContent, LocalizationContent, PluginContent, DevApiContent, TemplateContent, CollectionContent, ExternalDbContent } from "./file-util";
2
2
  /**
3
3
  * Page Related
4
4
  */
@@ -77,3 +77,9 @@ export declare const saveTemplates: (projectId: string, templates: TemplateConte
77
77
  export declare const loadCollections: (projectId: string) => CollectionContent[];
78
78
  export declare const loadCollection: (projectId: string, uuid: string) => CollectionContent | null;
79
79
  export declare const saveCollections: (projectId: string, collections: CollectionContent[]) => void;
80
+ /**
81
+ * External DB Related
82
+ */
83
+ export declare const loadExternalDbs: (projectId: string) => ExternalDbContent[];
84
+ export declare const loadExternalDb: (projectId: string, uuid: string) => ExternalDbContent | null;
85
+ export declare const saveExternalDbs: (projectId: string, externalDbs: ExternalDbContent[]) => void;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.saveCollections = exports.loadCollection = exports.loadCollections = exports.saveTemplates = exports.loadTemplate = exports.loadTemplates = exports.saveDevAPIs = exports.loadDevAPI = exports.loadDevAPIs = exports.savePlugins = exports.loadPlugin = exports.loadPlugins = exports.saveLocalizations = exports.loadLocalization = exports.loadLocalizations = exports.saveSnippets = exports.loadSnippet = exports.loadSnippets = exports.saveEvents = exports.loadEvent = exports.loadEvents = exports.saveTasks = exports.loadTask = exports.loadTasks = exports.saveCustomMappings = exports.loadCustomMapping = exports.loadCustomMappings = exports.saveCustomComponents = exports.loadCustomComponent = exports.loadCustomComponents = exports.saveExternalApis = exports.loadExternalApi = exports.loadExternalApis = exports.saveWebhooks = exports.loadWebhook = exports.loadWebhooks = exports.saveProjectPages = exports.loadPage = exports.loadPages = void 0;
6
+ exports.saveExternalDbs = exports.loadExternalDb = exports.loadExternalDbs = exports.saveCollections = exports.loadCollection = exports.loadCollections = exports.saveTemplates = exports.loadTemplate = exports.loadTemplates = exports.saveDevAPIs = exports.loadDevAPI = exports.loadDevAPIs = exports.savePlugins = exports.loadPlugin = exports.loadPlugins = exports.saveLocalizations = exports.loadLocalization = exports.loadLocalizations = exports.saveSnippets = exports.loadSnippet = exports.loadSnippets = exports.saveEvents = exports.loadEvent = exports.loadEvents = exports.saveTasks = exports.loadTask = exports.loadTasks = exports.saveCustomMappings = exports.loadCustomMapping = exports.loadCustomMappings = exports.saveCustomComponents = exports.loadCustomComponent = exports.loadCustomComponents = exports.saveExternalApis = exports.loadExternalApi = exports.loadExternalApis = exports.saveWebhooks = exports.loadWebhook = exports.loadWebhooks = exports.saveProjectPages = exports.loadPage = exports.loadPages = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const file_util_1 = require("./file-util");
9
9
  /**
@@ -218,3 +218,18 @@ const saveCollections = (projectId, collections) => {
218
218
  });
219
219
  };
220
220
  exports.saveCollections = saveCollections;
221
+ /**
222
+ * External DB Related
223
+ */
224
+ const loadExternalDbs = (projectId) => {
225
+ return (0, file_util_1.loadJsonFilesFromSubfolder)(projectId, "external-dbs");
226
+ };
227
+ exports.loadExternalDbs = loadExternalDbs;
228
+ const loadExternalDb = (projectId, uuid) => {
229
+ return (0, file_util_1.loadSingleJsonFromSubfolder)(projectId, "external-dbs", uuid);
230
+ };
231
+ exports.loadExternalDb = loadExternalDb;
232
+ const saveExternalDbs = (projectId, externalDbs) => {
233
+ (0, file_util_1.saveEntities)(projectId, "external-dbs", externalDbs, (extDb) => extDb.uuid);
234
+ };
235
+ exports.saveExternalDbs = saveExternalDbs;
@@ -43,6 +43,9 @@ export interface CollectionContent extends FileContent {
43
43
  uuid: string;
44
44
  collectionName: string;
45
45
  }
46
+ export interface ExternalDbContent extends FileContent {
47
+ uuid: string;
48
+ }
46
49
  export declare const checkFolder: (folderPath: string) => void;
47
50
  export declare const verifyProjectSettingFolder: (projectId: string) => boolean;
48
51
  export declare const readFile: (filePath: string) => FileContent | null;
@@ -1,4 +1,4 @@
1
- export declare const callCurlRequest: (setting: any, user?: any, tenant?: any, userSetting?: any, subTenant?: any, data?: any, timeout?: number, timeoutMessage?: string, envConstants?: {}, downloadBytes?: boolean, requestDataType?: string, wrapJsonDataInArray?: boolean, projectId?: string, dataTransferObject?: any, isRawJSON?: boolean, browserStorageData?: any) => Promise<{
1
+ export declare const callCurlRequest: (setting: any, user?: any, tenant?: any, userSetting?: any, subTenant?: any, data?: any, timeout?: number, timeoutMessage?: string, envConstants?: {}, downloadBytes?: boolean, requestDataType?: string, wrapJsonDataInArray?: boolean, projectId?: string, dataTransferObject?: any, isRawJSON?: boolean, browserStorageData?: any, dtoExternalAPI?: any) => Promise<{
2
2
  data: any;
3
3
  status: number;
4
4
  success: boolean;
@@ -7,15 +7,14 @@ exports.callCurlRequest = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const util_1 = require("./util");
9
9
  const drapcode_logger_1 = require("drapcode-logger");
10
+ const drapcode_constant_1 = require("drapcode-constant");
10
11
  var FormData = require("form-data");
11
12
  var fs = require("fs");
12
13
  const qs = require("qs");
13
- const callCurlRequest = async (setting, user = {}, tenant = {}, userSetting = {}, subTenant = {}, data = {}, timeout = 0, timeoutMessage = "", envConstants = {}, downloadBytes = false, requestDataType = "", wrapJsonDataInArray = false, projectId = "", dataTransferObject = {}, isRawJSON = false, browserStorageData = {}) => {
14
+ const callCurlRequest = async (setting, user = {}, tenant = {}, userSetting = {}, subTenant = {}, data = {}, timeout = 0, timeoutMessage = "", envConstants = {}, downloadBytes = false, requestDataType = "", wrapJsonDataInArray = false, projectId = "", dataTransferObject = {}, isRawJSON = false, browserStorageData = {}, dtoExternalAPI = {}) => {
14
15
  let { url, params, methodType, authType, requestHeader, accessToken, headers = [], isMultipart, files, awsSignPluginConfig = null, body } = setting;
15
16
  const { bodyRawJSONUrlEncoded, bodyDataFrom } = body || {};
16
- const { sessionValue, sessionFormValue,
17
- // sessionStorageData: sessionStorageValue,
18
- localStorageData: localStorageValue, cookiesData: cookiesValue, } = browserStorageData || {};
17
+ const { sessionValue, sessionFormValue, localStorageData: localStorageValue, cookiesData: cookiesValue, } = browserStorageData || {};
19
18
  drapcode_logger_1.logger.info(`STEP 1 Replacing placeholder key values...`, {
20
19
  label: projectId,
21
20
  });
@@ -122,7 +121,6 @@ const callCurlRequest = async (setting, user = {}, tenant = {}, userSetting = {}
122
121
  }
123
122
  try {
124
123
  let result = null;
125
- // console.log("🚀 ~ callCurlRequest ~ isRawJSON:", isRawJSON, "~ bodyRawJSONUrlEncoded:", bodyRawJSONUrlEncoded, "~ bodyDataFrom:", bodyDataFrom, "~ requestDataType:", requestDataType)
126
124
  drapcode_logger_1.logger.info(`** isRawJSON: ${isRawJSON}, ~ bodyRawJSONUrlEncoded: ${bodyRawJSONUrlEncoded}, ~ bodyDataFrom: ${bodyDataFrom}, ~ requestDataType: ${requestDataType}`, { label: projectId });
127
125
  if (isRawJSON) {
128
126
  if (bodyDataFrom === "RAW_JSON" && bodyRawJSONUrlEncoded) {
@@ -140,7 +138,18 @@ const callCurlRequest = async (setting, user = {}, tenant = {}, userSetting = {}
140
138
  if (requestDataType === "NO_BODY_DATA")
141
139
  data = {};
142
140
  }
143
- result = await makeAxiosCall(projectId, methodType, url, headerValue, data, timeout, wrapJsonDataInArray, awsSignPluginConfig);
141
+ const isTypeMySQL = dtoExternalAPI?.dtoExternalApiType === drapcode_constant_1.MYSQL &&
142
+ dtoExternalAPI?.dtoExternalDbId;
143
+ drapcode_logger_1.logger.info(`** isTypeMySQL: ${isTypeMySQL}`, { label: projectId });
144
+ if (isTypeMySQL) {
145
+ const { dtoExternalDb, dtoSearchString } = dtoExternalAPI;
146
+ const { setting: extDbSetting } = dtoExternalDb;
147
+ data["searchQuery"] = dtoSearchString;
148
+ result = await makeMySqlCall(projectId, data, extDbSetting);
149
+ }
150
+ else {
151
+ result = await makeAxiosCall(projectId, methodType, url, headerValue, data, timeout, wrapJsonDataInArray, awsSignPluginConfig);
152
+ }
144
153
  drapcode_logger_1.logger.info(`result.headers: ${result?.headers}`, { label: projectId });
145
154
  if (!result) {
146
155
  const errorMessage = "No Response from Server";
@@ -266,3 +275,69 @@ const makeAxiosCall = async (projectId, methodType, url, axiosConfig, data, time
266
275
  return error;
267
276
  }
268
277
  };
278
+ const makeMySqlCall = async (projectId, data, extDbSetting) => {
279
+ const allowedOps = ["select", "insert", "update", "delete"];
280
+ let result = "";
281
+ try {
282
+ const { sql: sqlQuery, params: sqlParams = [], pagination: sqlPagination, sort: sqlSort, searchQuery } = data || {};
283
+ if (!sqlQuery || !sqlQuery.trim()) {
284
+ return { status: 400, error: "SQL Query is empty" };
285
+ }
286
+ const operation = sqlQuery.trim().split(/\s+/)[0].toLowerCase();
287
+ if (!allowedOps.includes(operation)) {
288
+ return { status: 403, error: "Only SELECT, INSERT, UPDATE, DELETE operations are allowed." };
289
+ }
290
+ let finalSql = sqlQuery.trim();
291
+ const values = [...sqlParams];
292
+ // Add WHERE clause if needed
293
+ const hasWhere = finalSql.toLowerCase().includes("where");
294
+ if (searchQuery && !hasWhere) {
295
+ finalSql += (0, util_1.buildWhereClause)(searchQuery);
296
+ }
297
+ // Add ORDER BY clause
298
+ finalSql += (0, util_1.buildOrderByClause)(sqlSort);
299
+ // Add LIMIT/OFFSET clause
300
+ finalSql += (0, util_1.buildLimitOffsetClause)(sqlPagination, values);
301
+ const { mysqlDbHostUrl, mysqlDbUser, mysqlDbPassword, mysqlDbName, mysqlDbPort } = extDbSetting || {};
302
+ const mysqlDBConfig = {
303
+ host: mysqlDbHostUrl,
304
+ user: mysqlDbUser,
305
+ password: mysqlDbPassword,
306
+ database: mysqlDbName,
307
+ port: mysqlDbPort,
308
+ };
309
+ console.log(`==> Final MySQL data for projectID: ${projectId}:>> `, data, " with finalSql:>> ", finalSql, " and values:>> ", values);
310
+ const connection = await (0, util_1.createMySqlConnection)(mysqlDBConfig);
311
+ try {
312
+ const [rows] = await connection.execute(finalSql, values);
313
+ let total = null;
314
+ if (sqlPagination?.getTotal) {
315
+ total = await (0, util_1.getTotalRecords)(connection, sqlQuery, sqlParams);
316
+ }
317
+ result = {
318
+ status: 200,
319
+ success: true,
320
+ data: {
321
+ content: rows,
322
+ totalRecords: total,
323
+ returned: Array.isArray(rows) ? rows.length : 0
324
+ },
325
+ totalRecords: total,
326
+ returned: Array.isArray(rows) ? rows.length : 0,
327
+ };
328
+ }
329
+ catch (err) {
330
+ console.error(`==> MySQL projectID: ${projectId} ~ err:`, err);
331
+ return { status: 500, error: err };
332
+ }
333
+ finally {
334
+ await connection.end();
335
+ console.log(`==> MySQL projectID: ${projectId} ~ Connection cleanup!`);
336
+ }
337
+ return result;
338
+ }
339
+ catch (error) {
340
+ console.error(`==> MySQL projectID: ${projectId} ~ error:`, error);
341
+ return { status: 500, error };
342
+ }
343
+ };
@@ -155,4 +155,21 @@ type responseDataType = {
155
155
  data: any;
156
156
  };
157
157
  export declare const getAwsSignature: (axiosConfig: any, awsSignPluginConfig: any) => Promise<responseDataType>;
158
+ export declare const createMySqlConnection: (config: any) => Promise<any>;
159
+ /**
160
+ * Helper to parse search query string into SQL WHERE clause
161
+ */
162
+ export declare const buildWhereClause: (searchQuery: string) => string;
163
+ /**
164
+ * Helper to build ORDER BY clause
165
+ */
166
+ export declare const buildOrderByClause: (sqlSort: any) => string;
167
+ /**
168
+ * Helper to build LIMIT/OFFSET clause and update values array
169
+ */
170
+ export declare const buildLimitOffsetClause: (sqlPagination: any, values: any[]) => string;
171
+ /**
172
+ * Helper to get total record count for pagination
173
+ */
174
+ export declare const getTotalRecords: (connection: any, sqlQuery: string, sqlParams: any[]) => Promise<number | null>;
158
175
  export {};
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.multiply = exports.average = exports.substraction = exports.addition = exports.validateNumbers = exports.checkAndConvertNumber = exports.evaluateCustomSentence = exports.strJoin = exports.markdownToHtml = exports.substr = exports.truncate = exports.titleCase = exports.trim = exports.slugify = exports.upperCase = exports.lowerCase = exports.capitalize = exports.replaceUnderscoreWithSlash = exports.replaceSlashWithUnderscore = exports.toggleConsoleLogs = exports.validateUrl = exports.validateData = exports.fillDefaultValues = exports.replaceValueFromSource = exports.processFieldsInclude = exports.removeMongoDbId = exports.replaceTransferObjectValueIntoExpression = exports.unflattenObject = exports.parseValueFromData = exports.parseJsonString = exports.replaceDataValueIntoExpression = exports.formatCustomCSSClasses = exports.validateAlphanumericString = exports.convertItemToArray = exports.arraysEqual = exports.checkAndCompareValue = exports.restructureData = exports.formatCollectionAndFieldName = exports.cleanCollectionAndFieldName = exports.getSpecialCharectorReplacedExpression = exports.validateUuidString = exports.validateEmail = exports.dynamicSort = exports.isObject = exports.isEmptyObject = exports.isEmpty = exports.clearSpaceAndReformat = exports.camelize = exports.validateString = exports.nonFindQuery = void 0;
7
- exports.getAwsSignature = exports.replaceValuesFromRequestMapping = exports.replaceValuesFromObjArr = exports.checkFieldValueType = exports.getPrimaryFieldNameOfDataSource = exports.getFieldSchemaForDataSourcePrimaryId = exports.getMappingObjKey = exports.getItemDataForArrayFields = exports.getFileObjectList = exports.getFindQuery = exports.mergeObjects = exports.dateDifference = exports.formatDate = exports.evaluateJSLogic = exports.evaluateCurrency = exports.evaluateExpression = exports.divide = void 0;
7
+ exports.getTotalRecords = exports.buildLimitOffsetClause = exports.buildOrderByClause = exports.buildWhereClause = exports.createMySqlConnection = exports.getAwsSignature = exports.replaceValuesFromRequestMapping = exports.replaceValuesFromObjArr = exports.checkFieldValueType = exports.getPrimaryFieldNameOfDataSource = exports.getFieldSchemaForDataSourcePrimaryId = exports.getMappingObjKey = exports.getItemDataForArrayFields = exports.getFileObjectList = exports.getFindQuery = exports.mergeObjects = exports.dateDifference = exports.formatDate = exports.evaluateJSLogic = exports.evaluateCurrency = exports.evaluateExpression = exports.divide = void 0;
8
8
  const drapcode_constant_1 = require("drapcode-constant");
9
9
  const lodash_1 = __importDefault(require("lodash"));
10
10
  const showdown_1 = __importDefault(require("showdown"));
@@ -17,6 +17,7 @@ const moment_1 = __importDefault(require("moment"));
17
17
  const mime_types_1 = __importDefault(require("mime-types"));
18
18
  const uuid_2 = require("uuid");
19
19
  const aws4_1 = require("aws4");
20
+ const mysql = require('mysql2/promise');
20
21
  exports.nonFindQuery = ["COUNT", "SUM", "AVG", "MIN", "MAX"];
21
22
  // Constants
22
23
  const DERIVED_FIELD_EXCLUDES = [
@@ -149,7 +150,9 @@ const dynamicSort = (property) => {
149
150
  if (!aValue ||
150
151
  !bValue ||
151
152
  aValue === "undefined" ||
152
- bValue === "undefined") {
153
+ bValue === "undefined" ||
154
+ typeof aValue === "undefined" ||
155
+ typeof bValue === "undefined") {
153
156
  return 0;
154
157
  }
155
158
  if (typeof aValue === "number" || typeof bValue === "number") {
@@ -1222,3 +1225,67 @@ const getAwsSignature = async (axiosConfig, awsSignPluginConfig) => {
1222
1225
  return response;
1223
1226
  };
1224
1227
  exports.getAwsSignature = getAwsSignature;
1228
+ const createMySqlConnection = async (config) => {
1229
+ try {
1230
+ const { host, user, password, database, port } = config || {};
1231
+ const connection = await mysql.createConnection({
1232
+ host: host,
1233
+ user: user,
1234
+ password: password,
1235
+ database: database,
1236
+ port: port,
1237
+ });
1238
+ const [rows] = await connection.execute('select ?+? as sum', [2, 2]);
1239
+ console.log('==> MySQL createMySqlConnection ~ Testing connection...', rows);
1240
+ return connection;
1241
+ }
1242
+ catch (error) {
1243
+ console.error("==> MySQL createMySqlConnection ~ error:", error);
1244
+ throw error;
1245
+ }
1246
+ };
1247
+ exports.createMySqlConnection = createMySqlConnection;
1248
+ /**
1249
+ * Helper to parse search query string into SQL WHERE clause
1250
+ */
1251
+ const buildWhereClause = (searchQuery) => {
1252
+ if (!searchQuery)
1253
+ return "";
1254
+ const params = searchQuery.split("&").map((pair) => {
1255
+ const [key, value] = pair.split("=");
1256
+ return `${decodeURIComponent(key)}="${decodeURIComponent(value)}"`;
1257
+ });
1258
+ return params.length ? ` WHERE ${params.join(" AND ")}` : "";
1259
+ };
1260
+ exports.buildWhereClause = buildWhereClause;
1261
+ /**
1262
+ * Helper to build ORDER BY clause
1263
+ */
1264
+ const buildOrderByClause = (sqlSort) => {
1265
+ if (sqlSort?.column && sqlSort?.order) {
1266
+ const order = sqlSort.order.toUpperCase() === "DESC" ? "DESC" : "ASC";
1267
+ return ` ORDER BY \`${sqlSort.column}\` ${order}`;
1268
+ }
1269
+ return "";
1270
+ };
1271
+ exports.buildOrderByClause = buildOrderByClause;
1272
+ /**
1273
+ * Helper to build LIMIT/OFFSET clause and update values array
1274
+ */
1275
+ const buildLimitOffsetClause = (sqlPagination, values) => {
1276
+ if (sqlPagination?.limit && sqlPagination?.offset !== undefined) {
1277
+ values.push(parseInt(sqlPagination.limit), parseInt(sqlPagination.offset));
1278
+ return " LIMIT ? OFFSET ?";
1279
+ }
1280
+ return "";
1281
+ };
1282
+ exports.buildLimitOffsetClause = buildLimitOffsetClause;
1283
+ /**
1284
+ * Helper to get total record count for pagination
1285
+ */
1286
+ const getTotalRecords = async (connection, sqlQuery, sqlParams) => {
1287
+ const countSql = `SELECT COUNT(*) as total FROM (${sqlQuery}) as count_table`;
1288
+ const [countRows] = await connection.execute(countSql, sqlParams);
1289
+ return countRows[0]?.total ?? null;
1290
+ };
1291
+ exports.getTotalRecords = getTotalRecords;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drapcode-utility",
3
- "version": "2.3.3",
3
+ "version": "2.3.5",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -26,8 +26,8 @@
26
26
  "@types/mime-types": "^2.1.4",
27
27
  "@types/uuid": "^9.0.8",
28
28
  "del-cli": "^5.0.0",
29
- "typescript": "^5.3.3",
30
- "ts-loader": "^9.5.1"
29
+ "ts-loader": "^9.5.1",
30
+ "typescript": "^5.3.3"
31
31
  },
32
32
  "dependencies": {
33
33
  "@aws-sdk/client-kms": "^3.540.0",
@@ -42,9 +42,9 @@
42
42
  "axios": "^1.1.2",
43
43
  "date-fns": "^4.1.0",
44
44
  "dompurify": "^3.1.7",
45
- "drapcode-constant": "^1.9.3",
45
+ "drapcode-constant": "^1.9.5",
46
46
  "drapcode-logger": "^1.3.5",
47
- "drapcode-redis": "^1.3.11",
47
+ "drapcode-redis": "^1.3.13",
48
48
  "exiftool-vendored": "^28.2.1",
49
49
  "express": "^4.17.1",
50
50
  "gm": "^1.25.0",
@@ -53,6 +53,7 @@
53
53
  "mathjs": "^14.4.0",
54
54
  "mime-types": "^2.1.35",
55
55
  "moment": "^2.29.0",
56
+ "mysql2": "^3.14.5",
56
57
  "numeral": "^2.0.6",
57
58
  "showdown": "^2.1.0",
58
59
  "svgo": "^3.3.2",