@machinemetrics/mm-erp-sdk 0.1.7-beta.1 → 0.1.7-beta.3

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":"data-sync-service.d.ts","sourceRoot":"","sources":["../../../src/services/data-sync-service/data-sync-service.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,kBAAkB,GAAU,eAAe,MAAM,kBA+I7D,CAAC"}
1
+ {"version":3,"file":"data-sync-service.d.ts","sourceRoot":"","sources":["../../../src/services/data-sync-service/data-sync-service.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,kBAAkB,GAAU,eAAe,MAAM,kBA0I7D,CAAC"}
@@ -1,3 +1,4 @@
1
+ import odbc from "odbc";
1
2
  import { PsqlConfiguration } from "./configuration";
2
3
  import { ERPResponse } from "../../types/erp-types";
3
4
  type PagingParams = {
@@ -5,8 +6,10 @@ type PagingParams = {
5
6
  offset?: number;
6
7
  };
7
8
  export declare class PsqlService {
9
+ private connection;
8
10
  private config;
9
11
  constructor(config: PsqlConfiguration);
12
+ dispose(): Promise<void>;
10
13
  /**
11
14
  * Build PSQL ODBC connection string
12
15
  * CRITICAL: ServerName must use IP.PORT format (e.g., 10.4.0.11.1583)
@@ -14,7 +17,7 @@ export declare class PsqlService {
14
17
  private buildConnectionString;
15
18
  /**
16
19
  * Execute a query and return the results
17
- * Creates a fresh connection for each query to avoid handle corruption
20
+ * Interface matches SqlServerService for consistency
18
21
  *
19
22
  * @param query The SQL query to execute
20
23
  * @param params Query parameters (currently unused for PSQL read operations)
@@ -22,15 +25,25 @@ export declare class PsqlService {
22
25
  * @returns The entities fetched from the database, along with paging information
23
26
  */
24
27
  executePreparedStatement(query: string, params?: Record<string, string>, paging?: PagingParams): Promise<ERPResponse | undefined>;
28
+ /**
29
+ * Opens a connection to PSQL database
30
+ * Caches the connection so that it can be reused.
31
+ * On failure to connect, throws
32
+ */
33
+ openConnection(): Promise<odbc.Connection>;
25
34
  /**
26
35
  * Transform ODBC result set to array of Record<string, string> instances.
27
36
  * IMPORTANT: PSQL CHAR fields are often padded with spaces - we trim them
37
+ *
38
+ * @param recordset Result set from ODBC query
39
+ * @returns array of Record<string, string> instances
28
40
  */
29
41
  static recordsetToRecords(recordset: any[]): Record<string, string>[];
30
42
  /**
31
43
  * Handle ODBC errors and provide meaningful messages
32
44
  */
33
45
  private handleOdbcError;
46
+ private closeConnection;
34
47
  }
35
48
  export {};
36
49
  //# sourceMappingURL=psql-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"psql-service.d.ts","sourceRoot":"","sources":["../../../src/services/psql-erp-service/psql-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,KAAK,YAAY,GAAG;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,EAAE,iBAAiB;IASrC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAe7B;;;;;;;;OAQG;IACU,wBAAwB,CACnC,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAqEnC;;;OAGG;WACW,kBAAkB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;IAkB5E;;OAEG;IACH,OAAO,CAAC,eAAe;CA4BxB"}
1
+ {"version":3,"file":"psql-service.d.ts","sourceRoot":"","sources":["../../../src/services/psql-erp-service/psql-service.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,KAAK,YAAY,GAAG;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,WAAW;IACtB,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,EAAE,iBAAiB;IAI/B,OAAO;IAIb;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;;;;;;;OAQG;IACU,wBAAwB,CACnC,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAsDnC;;;;OAIG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;IA4BhD;;;;;;OAMG;WACW,kBAAkB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;IAmB5E;;OAEG;IACH,OAAO,CAAC,eAAe;YA6BT,eAAe;CAa9B"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@machinemetrics/mm-erp-sdk",
3
3
  "description": "A library for syncing data between MachineMetrics and ERP systems",
4
- "version": "0.1.7-beta.1",
4
+ "version": "0.1.7-beta.3",
5
5
  "license": "MIT",
6
6
  "author": "machinemetrics",
7
7
  "main": "dist/mm-erp-sdk.js",
@@ -45,11 +45,6 @@ export const runDataSyncService = async (connectorPath: string) => {
45
45
  // Pass through all other environment variables that might be needed
46
46
  ...process.env,
47
47
  },
48
-
49
- // Add worker options for better isolation and cleanup
50
- execArgv: [
51
- "--expose-gc", // Allow manual garbage collection
52
- ],
53
48
  },
54
49
 
55
50
  jobs: [
@@ -10,22 +10,23 @@ type PagingParams = {
10
10
  };
11
11
 
12
12
  export class PsqlService {
13
+ private connection: odbc.Connection | null = null;
13
14
  private config: PsqlConfiguration;
14
15
 
15
16
  constructor(config: PsqlConfiguration) {
16
17
  this.config = config;
17
18
  }
18
19
 
19
- // REMOVED: dispose() method - not needed anymore
20
- // REMOVED: connection property - not needed anymore
21
- // REMOVED: openConnection() method - not needed anymore
22
- // REMOVED: closeConnection() method - not needed anymore
20
+ async dispose() {
21
+ await this.closeConnection();
22
+ }
23
23
 
24
24
  /**
25
25
  * Build PSQL ODBC connection string
26
26
  * CRITICAL: ServerName must use IP.PORT format (e.g., 10.4.0.11.1583)
27
27
  */
28
28
  private buildConnectionString(): string {
29
+ // PSQL requires ServerName in format IP.PORT (not IP:PORT)
29
30
  const serverName = `${this.config.host}.${this.config.port}`;
30
31
 
31
32
  return (
@@ -42,7 +43,7 @@ export class PsqlService {
42
43
 
43
44
  /**
44
45
  * Execute a query and return the results
45
- * Creates a fresh connection for each query to avoid handle corruption
46
+ * Interface matches SqlServerService for consistency
46
47
  *
47
48
  * @param query The SQL query to execute
48
49
  * @param params Query parameters (currently unused for PSQL read operations)
@@ -54,14 +55,12 @@ export class PsqlService {
54
55
  params: Record<string, string> = {},
55
56
  paging?: PagingParams
56
57
  ): Promise<ERPResponse | undefined> {
57
- let connection: odbc.Connection | null = null;
58
+ const connection = await this.openConnection();
58
59
 
60
+ let records;
59
61
  try {
60
- // Create fresh connection for THIS query only
61
- const connStr = this.buildConnectionString();
62
- logger.debug("Creating fresh PSQL connection for query");
63
- connection = await odbc.connect(connStr);
64
-
62
+ // For Phase 1 (read-only), we execute queries directly
63
+ // Phase 2 will add proper parameter binding for INSERT/UPDATE/DELETE
65
64
  if (Object.keys(params).length > 0) {
66
65
  logger.warn(
67
66
  "PsqlService: Query parameters provided but parameter binding not yet implemented. " +
@@ -69,62 +68,85 @@ export class PsqlService {
69
68
  );
70
69
  }
71
70
 
72
- const records = await connection.query(query);
73
- const allRecords = PsqlService.recordsetToRecords(records);
74
- const rowsFetched = allRecords.length;
75
-
76
- // Apply paging if requested
77
- const pagedData =
78
- paging?.offset !== undefined || paging?.limit !== undefined
79
- ? allRecords.slice(
80
- paging.offset || 0,
81
- (paging.offset || 0) + (paging.limit || allRecords.length)
82
- )
83
- : allRecords;
84
-
85
- return {
86
- data: pagedData,
87
- paging: {
88
- count: rowsFetched,
89
- limit: paging?.limit || 0,
90
- offset: paging?.offset || 0,
91
- nextPage:
92
- paging?.limit && (paging.offset || 0) + paging.limit < rowsFetched
93
- ? String((paging.offset || 0) + paging.limit)
94
- : undefined,
95
- previousPage: paging?.offset
96
- ? String(Math.max(0, (paging.offset || 0) - (paging.limit || 10)))
97
- : undefined,
98
- },
99
- };
71
+ records = await connection.query(query);
100
72
  } catch (error) {
101
73
  const errorInfo = error as OdbcErrorResponse;
102
74
  logger.error("Error fetching data from PSQL", {
103
75
  error: errorInfo.message,
104
76
  odbcErrors: errorInfo.odbcErrors,
105
- query: query.substring(0, 200), // Log first 200 chars of query
106
77
  });
107
78
 
108
79
  throw this.handleOdbcError(errorInfo);
109
- } finally {
110
- // CRITICAL: Always close connection, even on error
111
- if (connection) {
112
- try {
113
- await connection.close();
114
- logger.debug("PSQL connection closed successfully");
115
- } catch (err) {
116
- // Don't throw on close errors, just log
117
- logger.warn("Error closing PSQL connection (non-fatal)", {
118
- error: err,
119
- });
120
- }
121
- }
80
+ }
81
+
82
+ const allRecords = PsqlService.recordsetToRecords(records);
83
+ const rowsFetched = allRecords.length;
84
+
85
+ // Apply paging if requested
86
+ const pagedData =
87
+ paging?.offset !== undefined || paging?.limit !== undefined
88
+ ? allRecords.slice(
89
+ paging.offset || 0,
90
+ (paging.offset || 0) + (paging.limit || allRecords.length)
91
+ )
92
+ : allRecords;
93
+
94
+ return {
95
+ data: pagedData,
96
+ paging: {
97
+ count: rowsFetched,
98
+ limit: paging?.limit || 0,
99
+ offset: paging?.offset || 0,
100
+ nextPage:
101
+ paging?.limit && (paging.offset || 0) + paging.limit < rowsFetched
102
+ ? String((paging.offset || 0) + paging.limit)
103
+ : undefined,
104
+ previousPage: paging?.offset
105
+ ? String(Math.max(0, (paging.offset || 0) - (paging.limit || 10)))
106
+ : undefined,
107
+ },
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Opens a connection to PSQL database
113
+ * Caches the connection so that it can be reused.
114
+ * On failure to connect, throws
115
+ */
116
+ async openConnection(): Promise<odbc.Connection> {
117
+ // If we have a connection, reuse it
118
+ // Note: ODBC connections don't have a .connected property like SQL Server
119
+ // We'll keep it simple and reuse if not null
120
+ if (this.connection) {
121
+ logger.debug("Reusing existing PSQL connection");
122
+ return this.connection;
123
+ }
124
+
125
+ try {
126
+ const connStr = this.buildConnectionString();
127
+ logger.info("Opening new PSQL connection");
128
+ logger.debug(
129
+ "Connection string (password hidden):",
130
+ connStr.replace(/PWD=[^;]+/, "PWD=***")
131
+ );
132
+
133
+ this.connection = await odbc.connect(connStr);
134
+ logger.info("Successfully connected to PSQL database");
135
+ return this.connection;
136
+ } catch (error) {
137
+ logger.error("PsqlService>>openConnection>> Connection failed", {
138
+ error,
139
+ });
140
+ throw this.handleOdbcError(error as OdbcErrorResponse);
122
141
  }
123
142
  }
124
143
 
125
144
  /**
126
145
  * Transform ODBC result set to array of Record<string, string> instances.
127
146
  * IMPORTANT: PSQL CHAR fields are often padded with spaces - we trim them
147
+ *
148
+ * @param recordset Result set from ODBC query
149
+ * @returns array of Record<string, string> instances
128
150
  */
129
151
  public static recordsetToRecords(recordset: any[]): Record<string, string>[] {
130
152
  if (!Array.isArray(recordset)) {
@@ -135,6 +157,7 @@ export class PsqlService {
135
157
  const transformedRow: Record<string, string> = {};
136
158
  Object.keys(row).forEach((key) => {
137
159
  const value = row[key];
160
+ // Convert to string and trim (PSQL CHAR fields have trailing spaces)
138
161
  transformedRow[key] =
139
162
  value !== null && value !== undefined ? String(value).trim() : "";
140
163
  });
@@ -175,4 +198,18 @@ export class PsqlService {
175
198
  return new Error(`PSQL error (${errorCode || "unknown"}): ${message}`);
176
199
  }
177
200
  }
201
+
202
+ private async closeConnection(): Promise<void> {
203
+ if (this.connection) {
204
+ logger.info("Closing PSQL connection");
205
+ try {
206
+ await this.connection.close();
207
+ } catch (error) {
208
+ logger.error("PsqlService::closeConnection: Error closing connection", {
209
+ error,
210
+ });
211
+ }
212
+ this.connection = null;
213
+ }
214
+ }
178
215
  }