@bdkinc/knex-ibmi 0.3.21 → 0.4.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 +0 -0
- package/README.md +250 -127
- package/dist/cli.cjs +531 -0
- package/dist/index.d.mts +137 -0
- package/dist/index.d.ts +77 -53
- package/dist/index.js +654 -199
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +971 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +29 -20
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -1,159 +1,173 @@
|
|
|
1
|
-
|
|
1
|
+
# @bdkinc/knex-ibmi
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://npmjs.org/package/@bdkinc/knex-ibmi)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Knex.js dialect for DB2 on IBM i (via ODBC). Built for usage with the official IBM i Access ODBC driver and tested on IBM i.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
This library uses the ODBC (as recommended here https://ibmi-oss-docs.readthedocs.io/en/latest/odbc/README.html)
|
|
9
|
-
driver and is only tested on IBMi.
|
|
7
|
+
For IBM i OSS docs, see https://ibmi-oss-docs.readthedocs.io/. ODBC guidance: https://ibmi-oss-docs.readthedocs.io/en/latest/odbc/README.html.
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
> Found an issue or have a question? Please open an issue.
|
|
12
10
|
|
|
13
|
-
##
|
|
11
|
+
## Features
|
|
14
12
|
|
|
15
13
|
- Query building
|
|
16
14
|
- Query execution
|
|
17
15
|
- Transactions
|
|
18
16
|
- Streaming
|
|
19
17
|
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- Node.js >= 16
|
|
21
|
+
- ODBC driver (IBM i Access ODBC Driver)
|
|
22
|
+
|
|
20
23
|
## Installation
|
|
21
24
|
|
|
22
|
-
```
|
|
23
|
-
npm install
|
|
25
|
+
```bash
|
|
26
|
+
npm install @bdkinc/knex-ibmi knex odbc
|
|
24
27
|
```
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
## Quick Start
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
```js
|
|
32
|
+
import knex from "knex";
|
|
33
|
+
import { DB2Dialect } from "@bdkinc/knex-ibmi";
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
/** @type {import("@bdkinc/knex-ibmi").DB2Config} */
|
|
36
|
+
const config = {
|
|
37
|
+
client: DB2Dialect,
|
|
38
|
+
connection: {
|
|
39
|
+
host: "your-ibm-i-host",
|
|
40
|
+
database: "*LOCAL",
|
|
41
|
+
user: "your-username",
|
|
42
|
+
password: "your-password",
|
|
43
|
+
driver: "IBM i Access ODBC Driver",
|
|
44
|
+
connectionStringParams: { DBQ: "MYLIB" },
|
|
45
|
+
},
|
|
46
|
+
pool: { min: 2, max: 10 },
|
|
47
|
+
};
|
|
31
48
|
|
|
32
|
-
|
|
49
|
+
const db = knex(config);
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const results = await db.select("*").from("MYTABLE").where({ STATUS: "A" });
|
|
53
|
+
console.log(results);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error("Database error:", error);
|
|
56
|
+
} finally {
|
|
57
|
+
await db.destroy();
|
|
58
|
+
}
|
|
59
|
+
```
|
|
33
60
|
|
|
34
61
|
## Usage
|
|
35
62
|
|
|
36
|
-
This
|
|
63
|
+
This package can be used with CommonJS, ESM, or TypeScript.
|
|
37
64
|
|
|
38
|
-
###
|
|
65
|
+
### CommonJS
|
|
39
66
|
|
|
40
|
-
```
|
|
67
|
+
```js
|
|
41
68
|
const knex = require("knex");
|
|
42
69
|
const { DB2Dialect } = require("@bdkinc/knex-ibmi");
|
|
43
70
|
|
|
44
71
|
const db = knex({
|
|
45
72
|
client: DB2Dialect,
|
|
46
73
|
connection: {
|
|
47
|
-
host: "
|
|
48
|
-
database: "*LOCAL",
|
|
49
|
-
user: "
|
|
50
|
-
password: "
|
|
51
|
-
driver: "IBM i Access ODBC Driver",
|
|
52
|
-
connectionStringParams: {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
DBQ: "MYLIB", // library or schema that holds the tables
|
|
74
|
+
host: "your-ibm-i-host",
|
|
75
|
+
database: "*LOCAL",
|
|
76
|
+
user: "your-username",
|
|
77
|
+
password: "your-password",
|
|
78
|
+
driver: "IBM i Access ODBC Driver",
|
|
79
|
+
connectionStringParams: {
|
|
80
|
+
ALLOWPROCCALLS: 1,
|
|
81
|
+
CMT: 0,
|
|
82
|
+
DBQ: "MYLIB"
|
|
57
83
|
},
|
|
58
84
|
},
|
|
59
|
-
pool: {
|
|
60
|
-
min: 2,
|
|
61
|
-
max: 10,
|
|
62
|
-
},
|
|
85
|
+
pool: { min: 2, max: 10 },
|
|
63
86
|
});
|
|
64
87
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
.
|
|
70
|
-
.
|
|
88
|
+
// Example query
|
|
89
|
+
db.select("*")
|
|
90
|
+
.from("MYTABLE")
|
|
91
|
+
.where({ STATUS: "A" })
|
|
92
|
+
.then(results => console.log(results))
|
|
93
|
+
.catch(error => console.error("Database error:", error))
|
|
94
|
+
.finally(() => db.destroy());
|
|
71
95
|
```
|
|
72
96
|
|
|
73
97
|
### ESM
|
|
74
98
|
|
|
75
|
-
```
|
|
99
|
+
```js
|
|
76
100
|
import knex from "knex";
|
|
77
101
|
import { DB2Dialect } from "@bdkinc/knex-ibmi";
|
|
78
102
|
|
|
79
|
-
/**
|
|
80
|
-
* @type {import("@bdkinc/knex-ibmi").DB2Config}
|
|
81
|
-
*/
|
|
103
|
+
/** @type {import("@bdkinc/knex-ibmi").DB2Config} */
|
|
82
104
|
const config = {
|
|
83
105
|
client: DB2Dialect,
|
|
84
106
|
connection: {
|
|
85
|
-
host: "
|
|
86
|
-
database: "*LOCAL",
|
|
87
|
-
user: "
|
|
88
|
-
password: "
|
|
89
|
-
driver: "IBM i Access ODBC Driver",
|
|
90
|
-
connectionStringParams: {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
DBQ: "MYLIB", // library or schema that holds the tables
|
|
107
|
+
host: "your-ibm-i-host",
|
|
108
|
+
database: "*LOCAL",
|
|
109
|
+
user: "your-username",
|
|
110
|
+
password: "your-password",
|
|
111
|
+
driver: "IBM i Access ODBC Driver",
|
|
112
|
+
connectionStringParams: {
|
|
113
|
+
ALLOWPROCCALLS: 1,
|
|
114
|
+
CMT: 0,
|
|
115
|
+
DBQ: "MYLIB"
|
|
95
116
|
},
|
|
96
117
|
},
|
|
97
|
-
pool: {
|
|
98
|
-
min: 2,
|
|
99
|
-
max: 10,
|
|
100
|
-
},
|
|
118
|
+
pool: { min: 2, max: 10 },
|
|
101
119
|
};
|
|
102
120
|
|
|
103
121
|
const db = knex(config);
|
|
104
122
|
|
|
105
123
|
try {
|
|
106
|
-
const
|
|
107
|
-
console.log(
|
|
108
|
-
} catch (
|
|
109
|
-
|
|
124
|
+
const results = await db.select("*").from("MYTABLE").where({ STATUS: "A" });
|
|
125
|
+
console.log(results);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error("Database error:", error);
|
|
110
128
|
} finally {
|
|
111
|
-
|
|
129
|
+
await db.destroy();
|
|
112
130
|
}
|
|
113
131
|
```
|
|
114
132
|
|
|
115
133
|
### TypeScript
|
|
116
134
|
|
|
117
|
-
```
|
|
135
|
+
```ts
|
|
118
136
|
import { knex } from "knex";
|
|
119
137
|
import { DB2Dialect, DB2Config } from "@bdkinc/knex-ibmi";
|
|
120
138
|
|
|
121
139
|
const config: DB2Config = {
|
|
122
140
|
client: DB2Dialect,
|
|
123
141
|
connection: {
|
|
124
|
-
host: "
|
|
125
|
-
database: "*LOCAL",
|
|
126
|
-
user: "
|
|
127
|
-
password: "
|
|
128
|
-
driver: "IBM i Access ODBC Driver",
|
|
129
|
-
connectionStringParams: {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
DBQ: "MYLIB", // library or schema that holds the tables
|
|
142
|
+
host: "your-ibm-i-host",
|
|
143
|
+
database: "*LOCAL",
|
|
144
|
+
user: "your-username",
|
|
145
|
+
password: "your-password",
|
|
146
|
+
driver: "IBM i Access ODBC Driver",
|
|
147
|
+
connectionStringParams: {
|
|
148
|
+
ALLOWPROCCALLS: 1,
|
|
149
|
+
CMT: 0,
|
|
150
|
+
DBQ: "MYLIB"
|
|
134
151
|
},
|
|
135
152
|
},
|
|
136
|
-
pool: {
|
|
137
|
-
min: 2,
|
|
138
|
-
max: 10,
|
|
139
|
-
},
|
|
153
|
+
pool: { min: 2, max: 10 },
|
|
140
154
|
};
|
|
141
155
|
|
|
142
156
|
const db = knex(config);
|
|
143
157
|
|
|
144
158
|
try {
|
|
145
|
-
const
|
|
146
|
-
console.log(
|
|
147
|
-
} catch (
|
|
148
|
-
|
|
159
|
+
const results = await db.select("*").from("MYTABLE").where({ STATUS: "A" });
|
|
160
|
+
console.log(results);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error("Database error:", error);
|
|
149
163
|
} finally {
|
|
150
|
-
|
|
164
|
+
await db.destroy();
|
|
151
165
|
}
|
|
152
166
|
```
|
|
153
167
|
|
|
154
|
-
### Streaming
|
|
168
|
+
### Streaming
|
|
155
169
|
|
|
156
|
-
```
|
|
170
|
+
```ts
|
|
157
171
|
import { knex } from "knex";
|
|
158
172
|
import { DB2Dialect, DB2Config } from "@bdkinc/knex-ibmi";
|
|
159
173
|
import { Transform } from "node:stream";
|
|
@@ -162,70 +176,60 @@ import { finished } from "node:stream/promises";
|
|
|
162
176
|
const config: DB2Config = {
|
|
163
177
|
client: DB2Dialect,
|
|
164
178
|
connection: {
|
|
165
|
-
host: "
|
|
166
|
-
database: "*LOCAL",
|
|
167
|
-
user: "
|
|
168
|
-
password: "
|
|
169
|
-
driver: "IBM i Access ODBC Driver",
|
|
170
|
-
connectionStringParams: {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
DBQ: "MYLIB", // library or schema that holds the tables
|
|
179
|
+
host: "your-ibm-i-host",
|
|
180
|
+
database: "*LOCAL",
|
|
181
|
+
user: "your-username",
|
|
182
|
+
password: "your-password",
|
|
183
|
+
driver: "IBM i Access ODBC Driver",
|
|
184
|
+
connectionStringParams: {
|
|
185
|
+
ALLOWPROCCALLS: 1,
|
|
186
|
+
CMT: 0,
|
|
187
|
+
DBQ: "MYLIB"
|
|
175
188
|
},
|
|
176
189
|
},
|
|
177
|
-
pool: {
|
|
178
|
-
min: 2,
|
|
179
|
-
max: 10,
|
|
180
|
-
},
|
|
190
|
+
pool: { min: 2, max: 10 },
|
|
181
191
|
};
|
|
182
192
|
|
|
183
193
|
const db = knex(config);
|
|
184
194
|
|
|
185
195
|
try {
|
|
186
|
-
const
|
|
187
|
-
.select("*")
|
|
188
|
-
.from("table")
|
|
189
|
-
.stream({ fetchSize: 1 }); // optional, fetchSize defaults to 1
|
|
196
|
+
const stream = await db.select("*").from("LARGETABLE").stream({ fetchSize: 100 });
|
|
190
197
|
|
|
191
|
-
// use an objectMode transformer
|
|
192
198
|
const transform = new Transform({
|
|
193
199
|
objectMode: true,
|
|
194
|
-
transform(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
) {
|
|
199
|
-
// chunk will be an array of objects
|
|
200
|
-
// the length of the array is the chunk size
|
|
201
|
-
console.log(chunk);
|
|
202
|
-
callback(null, chunk);
|
|
200
|
+
transform(chunk, _enc, cb) {
|
|
201
|
+
// Process each row
|
|
202
|
+
console.log("Processing row:", chunk);
|
|
203
|
+
cb(null, chunk);
|
|
203
204
|
},
|
|
204
205
|
});
|
|
205
206
|
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
stream.pipe(transform);
|
|
208
|
+
await finished(stream);
|
|
208
209
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
// or we can iterate through each record
|
|
212
|
-
for await (const record of data) {
|
|
210
|
+
// Alternative: async iteration
|
|
211
|
+
for await (const record of stream) {
|
|
213
212
|
console.log(record);
|
|
214
213
|
}
|
|
215
|
-
} catch (
|
|
216
|
-
|
|
214
|
+
} catch (error) {
|
|
215
|
+
console.error("Streaming error:", error);
|
|
217
216
|
} finally {
|
|
218
|
-
|
|
217
|
+
await db.destroy();
|
|
219
218
|
}
|
|
220
219
|
```
|
|
221
220
|
|
|
222
|
-
##
|
|
221
|
+
## ODBC Driver Setup
|
|
222
|
+
|
|
223
|
+
If you don't know the name of your installed driver, check `odbcinst.ini`. Find its path with:
|
|
223
224
|
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
```bash
|
|
226
|
+
odbcinst -j
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Example entries:
|
|
226
230
|
|
|
227
231
|
```
|
|
228
|
-
[IBM i Access ODBC Driver]
|
|
232
|
+
[IBM i Access ODBC Driver] # driver name in square brackets
|
|
229
233
|
Description=IBM i Access for Linux ODBC Driver
|
|
230
234
|
Driver=/opt/ibm/iaccess/lib/libcwbodbc.so
|
|
231
235
|
Setup=/opt/ibm/iaccess/lib/libcwbodbcs.so
|
|
@@ -244,7 +248,126 @@ DontDLClose=1
|
|
|
244
248
|
UsageCount=1
|
|
245
249
|
```
|
|
246
250
|
|
|
247
|
-
If
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
If unixODBC is using the wrong config directory (e.g., your configs are in `/etc` but it expects elsewhere), set:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
export ODBCINI=/etc
|
|
255
|
+
export ODBCSYSINI=/etc
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Bundling with Vite
|
|
259
|
+
|
|
260
|
+
If you bundle with Vite, exclude certain native deps during optimize step:
|
|
261
|
+
|
|
262
|
+
```js
|
|
263
|
+
// vite.config.js
|
|
264
|
+
export default {
|
|
265
|
+
optimizeDeps: {
|
|
266
|
+
exclude: ["@mapbox"],
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Migrations
|
|
272
|
+
|
|
273
|
+
⚠️ **Important**: Standard Knex migrations don't work reliably with IBM i DB2 due to auto-commit DDL operations and locking issues.
|
|
274
|
+
|
|
275
|
+
### Recommended: Use Built-in IBM i Migration System
|
|
276
|
+
|
|
277
|
+
The knex-ibmi library includes a custom migration system that bypasses Knex's problematic locking mechanism:
|
|
278
|
+
|
|
279
|
+
```js
|
|
280
|
+
import { createIBMiMigrationRunner } from "@bdkinc/knex-ibmi";
|
|
281
|
+
|
|
282
|
+
const migrationRunner = createIBMiMigrationRunner(db, {
|
|
283
|
+
directory: "./migrations",
|
|
284
|
+
tableName: "KNEX_MIGRATIONS",
|
|
285
|
+
schemaName: "MYSCHEMA"
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Run migrations
|
|
289
|
+
await migrationRunner.latest();
|
|
290
|
+
|
|
291
|
+
// Rollback
|
|
292
|
+
await migrationRunner.rollback();
|
|
293
|
+
|
|
294
|
+
// Check status
|
|
295
|
+
const pending = await migrationRunner.listPending();
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**CLI Usage:** The package includes a built-in CLI that can be used via npm scripts or npx:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
# Install globally (optional)
|
|
302
|
+
npm install -g @bdkinc/knex-ibmi
|
|
303
|
+
|
|
304
|
+
# Or use via npx (recommended)
|
|
305
|
+
npx ibmi-migrations migrate:latest # Run pending migrations
|
|
306
|
+
npx ibmi-migrations migrate:rollback # Rollback last batch
|
|
307
|
+
npx ibmi-migrations migrate:status # Show migration status
|
|
308
|
+
npx ibmi-migrations migrate:make create_users_table # Create new JS migration
|
|
309
|
+
npx ibmi-migrations migrate:make add_email_column -x ts # Create new TS migration
|
|
310
|
+
|
|
311
|
+
# Or add to your package.json scripts:
|
|
312
|
+
{
|
|
313
|
+
"scripts": {
|
|
314
|
+
"migrate:latest": "ibmi-migrations migrate:latest",
|
|
315
|
+
"migrate:rollback": "ibmi-migrations migrate:rollback",
|
|
316
|
+
"migrate:status": "ibmi-migrations migrate:status",
|
|
317
|
+
"migrate:make": "ibmi-migrations migrate:make"
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
# Then run with npm:
|
|
322
|
+
npm run migrate:latest
|
|
323
|
+
npm run migrate:status
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Full CLI API (similar to Knex):**
|
|
327
|
+
```bash
|
|
328
|
+
ibmi-migrations migrate:latest # Run all pending migrations
|
|
329
|
+
ibmi-migrations migrate:rollback # Rollback last migration batch
|
|
330
|
+
ibmi-migrations migrate:status # Show detailed migration status
|
|
331
|
+
ibmi-migrations migrate:currentVersion # Show current migration version
|
|
332
|
+
ibmi-migrations migrate:list # List all migrations
|
|
333
|
+
ibmi-migrations migrate:make <name> # Create new migration file
|
|
334
|
+
|
|
335
|
+
# Legacy aliases (backward compatibility):
|
|
336
|
+
ibmi-migrations latest # Same as migrate:latest
|
|
337
|
+
ibmi-migrations rollback # Same as migrate:rollback
|
|
338
|
+
ibmi-migrations status # Same as migrate:status
|
|
339
|
+
|
|
340
|
+
# Options:
|
|
341
|
+
ibmi-migrations migrate:status --env production
|
|
342
|
+
ibmi-migrations migrate:latest --knexfile ./config/knexfile.js
|
|
343
|
+
ibmi-migrations migrate:make create_users_table
|
|
344
|
+
ibmi-migrations migrate:make add_email_column -x ts # TypeScript migration
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
📖 **See [MIGRATIONS.md](./MIGRATIONS.md) for complete documentation**
|
|
348
|
+
|
|
349
|
+
### Alternative: Standard Knex with Transactions Disabled
|
|
350
|
+
|
|
351
|
+
If you must use standard Knex migrations, disable transactions to avoid issues:
|
|
352
|
+
|
|
353
|
+
```js
|
|
354
|
+
/** @type {import("@bdkinc/knex-ibmi").DB2Config} */
|
|
355
|
+
const config = {
|
|
356
|
+
client: DB2Dialect,
|
|
357
|
+
connection: { /* your connection config */ },
|
|
358
|
+
migrations: {
|
|
359
|
+
disableTransactions: true, // Required for IBM i
|
|
360
|
+
directory: './migrations',
|
|
361
|
+
tableName: 'knex_migrations',
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Warning**: Standard Knex migrations may still hang on lock operations. The built-in IBM i migration system is strongly recommended.
|
|
367
|
+
|
|
368
|
+
## Links
|
|
369
|
+
|
|
370
|
+
- Knex: https://knexjs.org/
|
|
371
|
+
- Knex repo: https://github.com/knex/knex
|
|
372
|
+
- ODBC driver: https://github.com/IBM/node-odbc
|
|
373
|
+
- IBM i OSS docs: https://ibmi-oss-docs.readthedocs.io/
|