@heyhru/business-dms-approval 0.9.1 → 0.11.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"approvals.model.d.ts","sourceRoot":"","sources":["../src/approvals.model.ts"],"names":[],"mappings":"AAGA,UAAU,eAAe;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAgBD,wBAAsB,cAAc,CAAC,OAAO,CAAC,EAAE,eAAe,mBAO7D;AAED,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE,eAAe,sCAS5D;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,gDAEzC;AAED,UAAU,oBAAoB;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAe,EAAE,EAAE,oBAAoB,gDAEnH;AAED,wBAAgB,YAAY,CAC1B,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GAAG,IAAI,gDAG5B;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM;;GAEtC;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;GAE1E"}
1
+ {"version":3,"file":"approvals.model.d.ts","sourceRoot":"","sources":["../src/approvals.model.ts"],"names":[],"mappings":"AAGA,UAAU,eAAe;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAgBD,wBAAsB,cAAc,CAAC,OAAO,CAAC,EAAE,eAAe,mBAO7D;AAED,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE,eAAe,sCAW5D;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,gDAEzC;AAED,UAAU,oBAAoB;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAe,EAAE,EAAE,oBAAoB,gDAEnH;AAED,wBAAgB,YAAY,CAC1B,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GAAG,IAAI,gDAG5B;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM;;GAEtC;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;GAE1E"}
package/dist/index.js CHANGED
@@ -85,9 +85,11 @@ async function countApprovals(filters) {
85
85
  return Number(row?.["total"] ?? 0);
86
86
  }
87
87
  async function listApprovals(filters) {
88
- let query = `SELECT a.*, u.username AS submitter_name
88
+ let query = `SELECT a.*, u.username AS submitter_name,
89
+ ds.name AS data_source_name, ds.type AS data_source_type
89
90
  FROM approvals a
90
91
  LEFT JOIN users u ON u.id = a.submitted_by
92
+ LEFT JOIN data_sources ds ON ds.id = a.data_source_id
91
93
  WHERE 1=1`;
92
94
  const { where, params } = buildWhereParams(filters);
93
95
  query += where + " ORDER BY a.created_at DESC LIMIT ? OFFSET ?";
@@ -190,6 +192,31 @@ function approvalExecute(encryptionKey) {
190
192
  }
191
193
  };
192
194
  }
195
+ function splitStatements(sql) {
196
+ const statements = [];
197
+ let current = "";
198
+ let inSingle = false;
199
+ let inDouble = false;
200
+ for (let i = 0; i < sql.length; i++) {
201
+ const ch = sql[i];
202
+ const prev = sql[i - 1];
203
+ if (ch === "'" && !inDouble && prev !== "\\") {
204
+ inSingle = !inSingle;
205
+ } else if (ch === '"' && !inSingle && prev !== "\\") {
206
+ inDouble = !inDouble;
207
+ }
208
+ if (ch === ";" && !inSingle && !inDouble) {
209
+ const trimmed2 = current.trim();
210
+ if (trimmed2) statements.push(trimmed2);
211
+ current = "";
212
+ } else {
213
+ current += ch;
214
+ }
215
+ }
216
+ const trimmed = current.trim();
217
+ if (trimmed) statements.push(trimmed);
218
+ return statements;
219
+ }
193
220
  async function doExecuteApproval({ id, userId, ip, encryptionKey }, log) {
194
221
  const approval = await getApprovalById(id);
195
222
  if (!approval || !["approved", "execute_failed"].includes(approval["status"])) {
@@ -205,15 +232,24 @@ async function doExecuteApproval({ id, userId, ip, encryptionKey }, log) {
205
232
  return (0, import_business_dms_datasource.getPool)({ ...ds, database: ds.database ?? "" });
206
233
  })();
207
234
  if (!pool) throw new Error("Data source not found");
208
- const rows = await pool.execute(approval["sql_text"]);
209
- const result = `${rows.length} rows affected`;
235
+ const sqlText = approval["sql_text"];
236
+ const statements = splitStatements(sqlText);
237
+ let result;
238
+ if (statements.length <= 1) {
239
+ const rows = await pool.execute(sqlText);
240
+ result = `${rows.length} rows affected`;
241
+ } else {
242
+ const results = await pool.executeInTransaction(statements);
243
+ const details = results.map((r) => `${r.rowCount} rows`).join(", ");
244
+ result = `${statements.length} statements executed (${details})`;
245
+ }
210
246
  await setExecuteResult(id, "executed", result);
211
- log.info("Approval executed (id=%s, user=%s)", id, userId);
247
+ log.info("Approval executed (id=%s, user=%s, stmts=%d)", id, userId, statements.length);
212
248
  await (0, import_business_dms_audit.writeAuditLog)({
213
249
  userId,
214
250
  dataSourceId,
215
251
  action: "DML_EXECUTE",
216
- sqlText: approval["sql_text"],
252
+ sqlText,
217
253
  resultSummary: result,
218
254
  ipAddress: ip
219
255
  });
package/dist/index.mjs CHANGED
@@ -51,9 +51,11 @@ async function countApprovals(filters) {
51
51
  return Number(row?.["total"] ?? 0);
52
52
  }
53
53
  async function listApprovals(filters) {
54
- let query = `SELECT a.*, u.username AS submitter_name
54
+ let query = `SELECT a.*, u.username AS submitter_name,
55
+ ds.name AS data_source_name, ds.type AS data_source_type
55
56
  FROM approvals a
56
57
  LEFT JOIN users u ON u.id = a.submitted_by
58
+ LEFT JOIN data_sources ds ON ds.id = a.data_source_id
57
59
  WHERE 1=1`;
58
60
  const { where, params } = buildWhereParams(filters);
59
61
  query += where + " ORDER BY a.created_at DESC LIMIT ? OFFSET ?";
@@ -156,6 +158,31 @@ function approvalExecute(encryptionKey) {
156
158
  }
157
159
  };
158
160
  }
161
+ function splitStatements(sql) {
162
+ const statements = [];
163
+ let current = "";
164
+ let inSingle = false;
165
+ let inDouble = false;
166
+ for (let i = 0; i < sql.length; i++) {
167
+ const ch = sql[i];
168
+ const prev = sql[i - 1];
169
+ if (ch === "'" && !inDouble && prev !== "\\") {
170
+ inSingle = !inSingle;
171
+ } else if (ch === '"' && !inSingle && prev !== "\\") {
172
+ inDouble = !inDouble;
173
+ }
174
+ if (ch === ";" && !inSingle && !inDouble) {
175
+ const trimmed2 = current.trim();
176
+ if (trimmed2) statements.push(trimmed2);
177
+ current = "";
178
+ } else {
179
+ current += ch;
180
+ }
181
+ }
182
+ const trimmed = current.trim();
183
+ if (trimmed) statements.push(trimmed);
184
+ return statements;
185
+ }
159
186
  async function doExecuteApproval({ id, userId, ip, encryptionKey }, log) {
160
187
  const approval = await getApprovalById(id);
161
188
  if (!approval || !["approved", "execute_failed"].includes(approval["status"])) {
@@ -171,15 +198,24 @@ async function doExecuteApproval({ id, userId, ip, encryptionKey }, log) {
171
198
  return getPool({ ...ds, database: ds.database ?? "" });
172
199
  })();
173
200
  if (!pool) throw new Error("Data source not found");
174
- const rows = await pool.execute(approval["sql_text"]);
175
- const result = `${rows.length} rows affected`;
201
+ const sqlText = approval["sql_text"];
202
+ const statements = splitStatements(sqlText);
203
+ let result;
204
+ if (statements.length <= 1) {
205
+ const rows = await pool.execute(sqlText);
206
+ result = `${rows.length} rows affected`;
207
+ } else {
208
+ const results = await pool.executeInTransaction(statements);
209
+ const details = results.map((r) => `${r.rowCount} rows`).join(", ");
210
+ result = `${statements.length} statements executed (${details})`;
211
+ }
176
212
  await setExecuteResult(id, "executed", result);
177
- log.info("Approval executed (id=%s, user=%s)", id, userId);
213
+ log.info("Approval executed (id=%s, user=%s, stmts=%d)", id, userId, statements.length);
178
214
  await writeAuditLog({
179
215
  userId,
180
216
  dataSourceId,
181
217
  action: "DML_EXECUTE",
182
- sqlText: approval["sql_text"],
218
+ sqlText,
183
219
  resultSummary: result,
184
220
  ipAddress: ip
185
221
  });
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.9.1",
6
+ "version": "0.11.0",
7
7
  "description": "DMS approval workflow domain logic: service, model, sql",
8
8
  "main": "./dist/index.js",
9
9
  "module": "./dist/index.mjs",
@@ -26,9 +26,9 @@
26
26
  "clean": "rm -rf dist"
27
27
  },
28
28
  "dependencies": {
29
- "@heyhru/business-dms-audit": "0.6.2",
30
- "@heyhru/business-dms-datasource": "0.8.2",
31
- "@heyhru/server-plugin-pg": "0.7.0",
29
+ "@heyhru/business-dms-audit": "0.6.3",
30
+ "@heyhru/business-dms-datasource": "0.8.3",
31
+ "@heyhru/server-plugin-pg": "0.8.0",
32
32
  "fastify": "^5.8.4"
33
33
  },
34
34
  "devDependencies": {
@@ -36,5 +36,5 @@
36
36
  "typescript": "^6.0.2",
37
37
  "vitest": "^4.1.4"
38
38
  },
39
- "gitHead": "f6013af87a27c9ad96b0e078760bd7b3d9832730"
39
+ "gitHead": "643229b8735627837110392818e8b737a218e32b"
40
40
  }