@mimersql/node-mimer 1.0.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.
- package/LICENSE +21 -0
- package/README.md +670 -0
- package/index.d.ts +153 -0
- package/index.js +48 -0
- package/lib/client.js +225 -0
- package/lib/find-mimer-library.js +154 -0
- package/lib/koffi-binding.js +970 -0
- package/lib/native.js +52 -0
- package/lib/pool.js +242 -0
- package/lib/prepared.js +73 -0
- package/lib/resultset.js +120 -0
- package/package.json +38 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* node-mimer - Node.js bindings for Mimer SQL
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ConnectOptions {
|
|
6
|
+
/** Database name */
|
|
7
|
+
dsn: string;
|
|
8
|
+
/** Username */
|
|
9
|
+
user: string;
|
|
10
|
+
/** Password */
|
|
11
|
+
password: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface PoolOptions extends ConnectOptions {
|
|
15
|
+
/** Maximum number of connections (default 10) */
|
|
16
|
+
max?: number;
|
|
17
|
+
/** Milliseconds before an idle connection is closed (default 30000) */
|
|
18
|
+
idleTimeout?: number;
|
|
19
|
+
/** Milliseconds to wait for a connection when pool is full (default 5000) */
|
|
20
|
+
acquireTimeout?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface FieldInfo {
|
|
24
|
+
/** Column name */
|
|
25
|
+
name: string;
|
|
26
|
+
/** Numeric Mimer type code */
|
|
27
|
+
dataTypeCode: number;
|
|
28
|
+
/** Human-readable SQL type name (e.g. "INTEGER", "NVARCHAR") */
|
|
29
|
+
dataTypeName: string;
|
|
30
|
+
/** Whether the column allows NULL values */
|
|
31
|
+
nullable: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface QueryResult {
|
|
35
|
+
/** Array of row objects (SELECT only) */
|
|
36
|
+
rows?: Record<string, any>[];
|
|
37
|
+
/** Number of rows returned or affected */
|
|
38
|
+
rowCount: number;
|
|
39
|
+
/** Column metadata (SELECT only) */
|
|
40
|
+
fields?: FieldInfo[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class MimerClient {
|
|
44
|
+
/** Whether the client is currently connected */
|
|
45
|
+
connected: boolean;
|
|
46
|
+
|
|
47
|
+
/** Connect to a Mimer SQL database */
|
|
48
|
+
connect(options: ConnectOptions): Promise<void>;
|
|
49
|
+
|
|
50
|
+
/** Execute a SQL statement with optional parameter binding */
|
|
51
|
+
query(sql: string, params?: any[]): Promise<QueryResult>;
|
|
52
|
+
|
|
53
|
+
/** Prepare a SQL statement for repeated execution */
|
|
54
|
+
prepare(sql: string): Promise<PreparedStatement>;
|
|
55
|
+
|
|
56
|
+
/** Execute a SELECT and return a cursor for row-at-a-time streaming */
|
|
57
|
+
queryCursor(sql: string, params?: any[]): Promise<ResultSet>;
|
|
58
|
+
|
|
59
|
+
/** Begin a new transaction */
|
|
60
|
+
beginTransaction(): Promise<void>;
|
|
61
|
+
|
|
62
|
+
/** Commit the current transaction */
|
|
63
|
+
commit(): Promise<void>;
|
|
64
|
+
|
|
65
|
+
/** Rollback the current transaction */
|
|
66
|
+
rollback(): Promise<void>;
|
|
67
|
+
|
|
68
|
+
/** Close the database connection */
|
|
69
|
+
close(): Promise<void>;
|
|
70
|
+
|
|
71
|
+
/** Check if connected to database */
|
|
72
|
+
isConnected(): boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class PreparedStatement {
|
|
76
|
+
/** Execute the prepared statement with parameter values */
|
|
77
|
+
execute(params?: any[]): Promise<QueryResult>;
|
|
78
|
+
|
|
79
|
+
/** Close the prepared statement and release resources */
|
|
80
|
+
close(): Promise<void>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export class ResultSet {
|
|
84
|
+
/** Column metadata array */
|
|
85
|
+
readonly fields: FieldInfo[];
|
|
86
|
+
|
|
87
|
+
/** Fetch the next row, or null when exhausted */
|
|
88
|
+
next(): Promise<Record<string, any> | null>;
|
|
89
|
+
|
|
90
|
+
/** Close the cursor and release resources */
|
|
91
|
+
close(): Promise<void>;
|
|
92
|
+
|
|
93
|
+
/** Async iterator for for-await-of */
|
|
94
|
+
[Symbol.asyncIterator](): AsyncIterableIterator<Record<string, any>>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export class Pool {
|
|
98
|
+
/** Total number of connections (idle + active) */
|
|
99
|
+
readonly totalCount: number;
|
|
100
|
+
|
|
101
|
+
/** Number of idle connections */
|
|
102
|
+
readonly idleCount: number;
|
|
103
|
+
|
|
104
|
+
/** Number of checked-out connections */
|
|
105
|
+
readonly activeCount: number;
|
|
106
|
+
|
|
107
|
+
/** Number of callers waiting for a connection */
|
|
108
|
+
readonly waitingCount: number;
|
|
109
|
+
|
|
110
|
+
/** Acquire a connection, execute the query, and release */
|
|
111
|
+
query(sql: string, params?: any[]): Promise<QueryResult>;
|
|
112
|
+
|
|
113
|
+
/** Acquire a connection and open a cursor (auto-released on close) */
|
|
114
|
+
queryCursor(sql: string, params?: any[]): Promise<ResultSet>;
|
|
115
|
+
|
|
116
|
+
/** Check out a connection for multiple operations */
|
|
117
|
+
connect(): Promise<PoolClient>;
|
|
118
|
+
|
|
119
|
+
/** Close all connections and shut down the pool */
|
|
120
|
+
end(): Promise<void>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export class PoolClient {
|
|
124
|
+
/** Execute a SQL statement */
|
|
125
|
+
query(sql: string, params?: any[]): Promise<QueryResult>;
|
|
126
|
+
|
|
127
|
+
/** Open a cursor for row-at-a-time streaming */
|
|
128
|
+
queryCursor(sql: string, params?: any[]): Promise<ResultSet>;
|
|
129
|
+
|
|
130
|
+
/** Prepare a SQL statement */
|
|
131
|
+
prepare(sql: string): Promise<PreparedStatement>;
|
|
132
|
+
|
|
133
|
+
/** Begin a new transaction */
|
|
134
|
+
beginTransaction(): Promise<void>;
|
|
135
|
+
|
|
136
|
+
/** Commit the current transaction */
|
|
137
|
+
commit(): Promise<void>;
|
|
138
|
+
|
|
139
|
+
/** Rollback the current transaction */
|
|
140
|
+
rollback(): Promise<void>;
|
|
141
|
+
|
|
142
|
+
/** Return the connection to the pool */
|
|
143
|
+
release(): void;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Create and connect a new MimerClient */
|
|
147
|
+
export function connect(options: ConnectOptions): Promise<MimerClient>;
|
|
148
|
+
|
|
149
|
+
/** Create a new connection pool */
|
|
150
|
+
export function createPool(options: PoolOptions): Pool;
|
|
151
|
+
|
|
152
|
+
/** Native addon version string */
|
|
153
|
+
export const version: string;
|
package/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Copyright (c) 2026 Mimer Information Technology
|
|
2
|
+
//
|
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
// furnished to do so, subject to the following conditions:
|
|
9
|
+
//
|
|
10
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
// copies or substantial portions of the Software.
|
|
12
|
+
//
|
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
// SOFTWARE.
|
|
20
|
+
//
|
|
21
|
+
// See license for more details.
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* node-mimer - Node.js bindings for Mimer SQL
|
|
25
|
+
*
|
|
26
|
+
* This module provides a JavaScript interface to the native Mimer API bindings.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const mimer = require('./lib/native');
|
|
30
|
+
const { MimerClient, connect } = require('./lib/client');
|
|
31
|
+
const { PreparedStatement } = require('./lib/prepared');
|
|
32
|
+
const { ResultSet } = require('./lib/resultset');
|
|
33
|
+
const { Pool, PoolClient } = require('./lib/pool');
|
|
34
|
+
|
|
35
|
+
function createPool(options) {
|
|
36
|
+
return new Pool(options);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
MimerClient,
|
|
41
|
+
PreparedStatement,
|
|
42
|
+
ResultSet,
|
|
43
|
+
Pool,
|
|
44
|
+
PoolClient,
|
|
45
|
+
connect,
|
|
46
|
+
createPool,
|
|
47
|
+
version: mimer.version,
|
|
48
|
+
};
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// Copyright (c) 2026 Mimer Information Technology
|
|
2
|
+
//
|
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
// furnished to do so, subject to the following conditions:
|
|
9
|
+
//
|
|
10
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
// copies or substantial portions of the Software.
|
|
12
|
+
//
|
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
// SOFTWARE.
|
|
20
|
+
//
|
|
21
|
+
// See license for more details.
|
|
22
|
+
|
|
23
|
+
const mimer = require('./native');
|
|
24
|
+
const { PreparedStatement } = require('./prepared');
|
|
25
|
+
const { ResultSet } = require('./resultset');
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* MimerClient provides a Promise-based interface to Mimer SQL
|
|
29
|
+
*/
|
|
30
|
+
class MimerClient {
|
|
31
|
+
constructor() {
|
|
32
|
+
this.connection = new mimer.Connection();
|
|
33
|
+
this.connected = false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Connect to a Mimer SQL database
|
|
38
|
+
* @param {Object} options - Connection options
|
|
39
|
+
* @param {string} options.dsn - Database name
|
|
40
|
+
* @param {string} options.user - Username
|
|
41
|
+
* @param {string} options.password - Password
|
|
42
|
+
* @returns {Promise<void>}
|
|
43
|
+
*/
|
|
44
|
+
async connect(options) {
|
|
45
|
+
const { dsn, user, password } = options;
|
|
46
|
+
|
|
47
|
+
if (!dsn || !user || !password) {
|
|
48
|
+
throw new Error('dsn, user, and password are required');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
try {
|
|
53
|
+
const result = this.connection.connect(dsn, user, password);
|
|
54
|
+
if (result) {
|
|
55
|
+
this.connected = true;
|
|
56
|
+
resolve();
|
|
57
|
+
} else {
|
|
58
|
+
reject(new Error('Connection failed'));
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
reject(error);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Execute a SQL query
|
|
68
|
+
* @param {string} sql - SQL statement to execute
|
|
69
|
+
* @param {Array} params - Optional parameters (for future prepared statement support)
|
|
70
|
+
* @returns {Promise<Object>} Result object with rows and metadata
|
|
71
|
+
*/
|
|
72
|
+
async query(sql, params = []) {
|
|
73
|
+
if (!this.connected) {
|
|
74
|
+
throw new Error('Not connected to database');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
try {
|
|
79
|
+
const result = this.connection.execute(sql, params);
|
|
80
|
+
resolve(result);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
reject(error);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Begin a transaction
|
|
89
|
+
* @returns {Promise<void>}
|
|
90
|
+
*/
|
|
91
|
+
async beginTransaction() {
|
|
92
|
+
if (!this.connected) {
|
|
93
|
+
throw new Error('Not connected to database');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
try {
|
|
98
|
+
this.connection.beginTransaction();
|
|
99
|
+
resolve();
|
|
100
|
+
} catch (error) {
|
|
101
|
+
reject(error);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Commit the current transaction
|
|
108
|
+
* @returns {Promise<void>}
|
|
109
|
+
*/
|
|
110
|
+
async commit() {
|
|
111
|
+
if (!this.connected) {
|
|
112
|
+
throw new Error('Not connected to database');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
try {
|
|
117
|
+
this.connection.commit();
|
|
118
|
+
resolve();
|
|
119
|
+
} catch (error) {
|
|
120
|
+
reject(error);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Rollback the current transaction
|
|
127
|
+
* @returns {Promise<void>}
|
|
128
|
+
*/
|
|
129
|
+
async rollback() {
|
|
130
|
+
if (!this.connected) {
|
|
131
|
+
throw new Error('Not connected to database');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
try {
|
|
136
|
+
this.connection.rollback();
|
|
137
|
+
resolve();
|
|
138
|
+
} catch (error) {
|
|
139
|
+
reject(error);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Close the database connection
|
|
146
|
+
* @returns {Promise<void>}
|
|
147
|
+
*/
|
|
148
|
+
async close() {
|
|
149
|
+
if (!this.connected) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
try {
|
|
155
|
+
this.connection.close();
|
|
156
|
+
this.connected = false;
|
|
157
|
+
resolve();
|
|
158
|
+
} catch (error) {
|
|
159
|
+
reject(error);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Prepare a SQL statement for repeated execution
|
|
166
|
+
* @param {string} sql - SQL statement with ? placeholders
|
|
167
|
+
* @returns {Promise<PreparedStatement>}
|
|
168
|
+
*/
|
|
169
|
+
async prepare(sql) {
|
|
170
|
+
if (!this.connected) {
|
|
171
|
+
throw new Error('Not connected to database');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return new Promise((resolve, reject) => {
|
|
175
|
+
try {
|
|
176
|
+
const stmt = this.connection.prepare(sql);
|
|
177
|
+
resolve(new PreparedStatement(stmt));
|
|
178
|
+
} catch (error) {
|
|
179
|
+
reject(error);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Execute a SELECT query and return a cursor for row-at-a-time iteration.
|
|
186
|
+
* @param {string} sql - SELECT statement (with optional ? placeholders)
|
|
187
|
+
* @param {Array} params - Optional parameter values
|
|
188
|
+
* @returns {Promise<ResultSet>}
|
|
189
|
+
*/
|
|
190
|
+
async queryCursor(sql, params = []) {
|
|
191
|
+
if (!this.connected) {
|
|
192
|
+
throw new Error('Not connected to database');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return new Promise((resolve, reject) => {
|
|
196
|
+
try {
|
|
197
|
+
const nativeRs = this.connection.executeQuery(sql, params);
|
|
198
|
+
resolve(new ResultSet(nativeRs));
|
|
199
|
+
} catch (error) {
|
|
200
|
+
reject(error);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Check if connected to database
|
|
207
|
+
* @returns {boolean}
|
|
208
|
+
*/
|
|
209
|
+
isConnected() {
|
|
210
|
+
return this.connection.isConnected();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Helper function to create a connection with options
|
|
216
|
+
* @param {Object} options - Connection options
|
|
217
|
+
* @returns {Promise<MimerClient>} Connected client instance
|
|
218
|
+
*/
|
|
219
|
+
async function connect(options) {
|
|
220
|
+
const client = new MimerClient();
|
|
221
|
+
await client.connect(options);
|
|
222
|
+
return client;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
module.exports = { MimerClient, connect };
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// Copyright (c) 2026 Mimer Information Technology
|
|
2
|
+
//
|
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
// furnished to do so, subject to the following conditions:
|
|
9
|
+
//
|
|
10
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
// copies or substantial portions of the Software.
|
|
12
|
+
//
|
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
// SOFTWARE.
|
|
20
|
+
//
|
|
21
|
+
// See license for more details.
|
|
22
|
+
|
|
23
|
+
'use strict';
|
|
24
|
+
|
|
25
|
+
const fs = require('fs');
|
|
26
|
+
const path = require('path');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Find the Mimer SQL shared library path for the current platform.
|
|
30
|
+
* Returns the path (or library name for ld search) to load with koffi.load().
|
|
31
|
+
*/
|
|
32
|
+
function findMimerLibrary() {
|
|
33
|
+
switch (process.platform) {
|
|
34
|
+
case 'linux':
|
|
35
|
+
return 'libmimerapi.so';
|
|
36
|
+
|
|
37
|
+
case 'darwin':
|
|
38
|
+
return '/usr/local/lib/libmimerapi.dylib';
|
|
39
|
+
|
|
40
|
+
case 'win32':
|
|
41
|
+
return findMimerWindows();
|
|
42
|
+
|
|
43
|
+
default:
|
|
44
|
+
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Find mimapi64.dll on Windows.
|
|
50
|
+
* Search order: MIMER_HOME → Registry → Program Files scan → defaults.
|
|
51
|
+
*/
|
|
52
|
+
function findMimerWindows() {
|
|
53
|
+
// Helper to check if a directory contains the Mimer DLL
|
|
54
|
+
function hasDll(dir) {
|
|
55
|
+
if (!dir) return false;
|
|
56
|
+
const dllPath = path.join(dir, 'lib', 'mimapi64.dll');
|
|
57
|
+
return fs.existsSync(dllPath) ? dllPath : null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Try 1: MIMER_HOME environment variable
|
|
61
|
+
if (process.env.MIMER_HOME) {
|
|
62
|
+
const dll = hasDll(process.env.MIMER_HOME);
|
|
63
|
+
if (dll) return dll;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Try 2: Windows Registry
|
|
67
|
+
try {
|
|
68
|
+
const { execSync } = require('child_process');
|
|
69
|
+
const regEnum = 'reg query "HKLM\\SOFTWARE\\Mimer\\Mimer SQL" 2>nul';
|
|
70
|
+
const output = execSync(regEnum, { encoding: 'utf8' });
|
|
71
|
+
|
|
72
|
+
const registryVersions = [];
|
|
73
|
+
for (const line of output.split('\n')) {
|
|
74
|
+
const versionMatch = line.match(/Mimer SQL\\(\d+\.\d+)\s*$/);
|
|
75
|
+
if (versionMatch) {
|
|
76
|
+
const version = versionMatch[1];
|
|
77
|
+
try {
|
|
78
|
+
const pathQuery = `reg query "HKLM\\SOFTWARE\\Mimer\\Mimer SQL\\${version}" /v PathName 2>nul`;
|
|
79
|
+
const pathOutput = execSync(pathQuery, { encoding: 'utf8' });
|
|
80
|
+
const pathMatch = pathOutput.match(/PathName\s+REG_SZ\s+(.+)/);
|
|
81
|
+
if (pathMatch && pathMatch[1]) {
|
|
82
|
+
const mimerPath = pathMatch[1].trim();
|
|
83
|
+
const dll = hasDll(mimerPath);
|
|
84
|
+
if (dll) {
|
|
85
|
+
registryVersions.push({ version, path: dll });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch (_) { /* skip */ }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (registryVersions.length > 0) {
|
|
93
|
+
registryVersions.sort((a, b) => {
|
|
94
|
+
const va = a.version.split('.').map(Number);
|
|
95
|
+
const vb = b.version.split('.').map(Number);
|
|
96
|
+
if (va[0] !== vb[0]) return vb[0] - va[0];
|
|
97
|
+
return vb[1] - va[1];
|
|
98
|
+
});
|
|
99
|
+
return registryVersions[0].path;
|
|
100
|
+
}
|
|
101
|
+
} catch (_) { /* registry not available */ }
|
|
102
|
+
|
|
103
|
+
// Try 3: Program Files scan
|
|
104
|
+
const programFiles = [
|
|
105
|
+
process.env.ProgramFiles,
|
|
106
|
+
process.env['ProgramFiles(x86)'],
|
|
107
|
+
].filter(Boolean);
|
|
108
|
+
|
|
109
|
+
const foundPaths = [];
|
|
110
|
+
for (const pf of programFiles) {
|
|
111
|
+
if (!fs.existsSync(pf)) continue;
|
|
112
|
+
try {
|
|
113
|
+
const entries = fs.readdirSync(pf, { withFileTypes: true });
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
if (entry.isDirectory() && entry.name.startsWith('Mimer SQL Experience')) {
|
|
116
|
+
const fullPath = path.join(pf, entry.name);
|
|
117
|
+
const dll = hasDll(fullPath);
|
|
118
|
+
if (dll) {
|
|
119
|
+
foundPaths.push({
|
|
120
|
+
path: dll,
|
|
121
|
+
version: entry.name.match(/(\d+\.\d+)/)?.[1] || '0.0',
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (_) { /* permission error */ }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (foundPaths.length > 0) {
|
|
130
|
+
foundPaths.sort((a, b) => {
|
|
131
|
+
const va = a.version.split('.').map(Number);
|
|
132
|
+
const vb = b.version.split('.').map(Number);
|
|
133
|
+
if (va[0] !== vb[0]) return vb[0] - va[0];
|
|
134
|
+
return vb[1] - va[1];
|
|
135
|
+
});
|
|
136
|
+
return foundPaths[0].path;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Try 4: Default locations
|
|
140
|
+
const defaultPaths = [
|
|
141
|
+
'C:\\Program Files\\Mimer SQL Experience 12.0',
|
|
142
|
+
'C:\\Program Files\\Mimer SQL Experience 11.0',
|
|
143
|
+
];
|
|
144
|
+
for (const dp of defaultPaths) {
|
|
145
|
+
const dll = hasDll(dp);
|
|
146
|
+
if (dll) return dll;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
throw new Error(
|
|
150
|
+
'Mimer SQL library not found. Please install Mimer SQL or set MIMER_HOME.'
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = findMimerLibrary;
|