@bdkinc/knex-ibmi 0.3.22 → 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/README.md CHANGED
@@ -1,159 +1,173 @@
1
- [![npm version](http://img.shields.io/npm/v/@bdkinc/knex-ibmi.svg)](https://npmjs.org/package/@bdkinc/knex-ibmi)
1
+ # @bdkinc/knex-ibmi
2
2
 
3
- **Please submit an issue for any bug encounter or any questions you have.**
3
+ [![npm version](http://img.shields.io/npm/v/@bdkinc/knex-ibmi.svg)](https://npmjs.org/package/@bdkinc/knex-ibmi)
4
4
 
5
- ## Description
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
- This is an external dialect for [knex](https://knexjs.org).
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
- For more information on IBMi OSS here are the [docs](https://ibmi-oss-docs.readthedocs.io/en/latest/README.html)
9
+ > Found an issue or have a question? Please open an issue.
12
10
 
13
- ## Supported functionality
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 --save odbc knex @bdkinc/knex-ibmi
25
+ ```bash
26
+ npm install @bdkinc/knex-ibmi knex odbc
24
27
  ```
25
28
 
26
- Requires Node v16 or higher.
29
+ ## Quick Start
27
30
 
28
- ## Dependencies
31
+ ```js
32
+ import knex from "knex";
33
+ import { DB2Dialect } from "@bdkinc/knex-ibmi";
29
34
 
30
- `npm install odbc` see [odbc](https://github.com/IBM/node-odbc)
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
- `npm install knex` see [knex](https://github.com/tgriesser/knex)
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 library can be used as commonjs, esm or TypeScript.
63
+ This package can be used with CommonJS, ESM, or TypeScript.
37
64
 
38
- ### CommonJs
65
+ ### CommonJS
39
66
 
40
- ```javascript
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: "localhost", // hostname or ip address of server
48
- database: "*LOCAL", // usually named in your odbc.ini connection
49
- user: "<user>", // IBMi username
50
- password: "<password>", // IBMi password
51
- driver: "IBM i Access ODBC Driver", // defined in odbcinst.ini
52
- connectionStringParams: {
53
- // DSN connection string parameters https://www.ibm.com/docs/en/i/7.5?topic=details-connection-string-keywords
54
- ALLOWPROCCALLS: 1,
55
- CMT: 0,
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
- const query = db.select("*").from("table").where({ foo: "bar" });
66
-
67
- query
68
- .then((result) => console.log(result))
69
- .catch((err) => console.error(err))
70
- .finally(() => process.exit());
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
- ```javascript
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: "localhost", // hostname or ip address of server
86
- database: "*LOCAL", // usually named in your odbc.ini connection
87
- user: "<user>", // IBMi username
88
- password: "<password>", // IBMi password
89
- driver: "IBM i Access ODBC Driver", // defined in odbcinst.ini
90
- connectionStringParams: {
91
- // DSN connection string parameters https://www.ibm.com/docs/en/i/7.5?topic=details-connection-string-keywords
92
- ALLOWPROCCALLS: 1,
93
- CMT: 0,
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 data = await db.select("*").from("table").where({ foo: "bar" });
107
- console.log(data);
108
- } catch (err) {
109
- throw new Error(err);
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
- process.exit();
129
+ await db.destroy();
112
130
  }
113
131
  ```
114
132
 
115
133
  ### TypeScript
116
134
 
117
- ```typescript
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: "localhost", // hostname or ip address of server
125
- database: "*LOCAL", // usually named in your odbc.ini connection
126
- user: "<user>", // IBMi username
127
- password: "<password>", // IBMi password
128
- driver: "IBM i Access ODBC Driver", // defined in odbcinst.ini
129
- connectionStringParams: {
130
- // DSN connection string parameters https://www.ibm.com/docs/en/i/7.5?topic=details-connection-string-keywords
131
- ALLOWPROCCALLS: 1,
132
- CMT: 0,
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 data = await db.select("*").from("table").where({ foo: "bar" });
146
- console.log(data);
147
- } catch (err) {
148
- throw new Error(err);
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
- process.exit();
164
+ await db.destroy();
151
165
  }
152
166
  ```
153
167
 
154
- ### Streaming example
168
+ ### Streaming
155
169
 
156
- ```typescript
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: "localhost", // hostname or ip address of server
166
- database: "*LOCAL", // usually named in your odbc.ini connection
167
- user: "<user>", // IBMi username
168
- password: "<password>", // IBMi password
169
- driver: "IBM i Access ODBC Driver", // defined in odbcinst.ini
170
- connectionStringParams: {
171
- // DSN connection string parameters https://www.ibm.com/docs/en/i/7.5?topic=details-connection-string-keywords
172
- ALLOWPROCCALLS: 1,
173
- CMT: 0,
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 data = await db
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
- chunk: any,
196
- encoding: BufferEncoding,
197
- callback: TransformCallback,
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
- // pipe through the transformer
207
- data.pipe(transform);
208
-
209
- await finished(data); // db queries are promises, we need to wait until resolved
207
+ stream.pipe(transform);
208
+ await finished(stream);
210
209
 
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 (err) {
216
- throw err;
214
+ } catch (error) {
215
+ console.error("Streaming error:", error);
217
216
  } finally {
218
- process.exit();
217
+ await db.destroy();
219
218
  }
220
219
  ```
221
220
 
222
- ## Configuring your driver
221
+ ## ODBC Driver Setup
223
222
 
224
- If you don't know the name of your installed driver, then look in `odbcinst.ini`. You can find the full path of the file by running `odbcinst -j`.
225
- There you should see an entry like the one below:
223
+ If you don't know the name of your installed driver, check `odbcinst.ini`. Find its path with:
226
224
 
225
+ ```bash
226
+ odbcinst -j
227
227
  ```
228
- [IBM i Access ODBC Driver] <== driver name in square brackets
228
+
229
+ Example entries:
230
+
231
+ ```
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,20 +248,126 @@ DontDLClose=1
244
248
  UsageCount=1
245
249
  ```
246
250
 
247
- If that still doesn't work, then unixodbc is probably looking for the config files in the wrong directory.
248
- A common case is that the configs are in `/etc` but your system expects them to be somewhere else.
249
- In such a case, override the path unixodbc looks in via the `ODBCSYSINI` and `ODBCINI` environment variables.
250
- E.g., `ODBCINI=/etc ODBCSYSINI=/etc`.
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
+ ```
251
257
 
252
258
  ## Bundling with Vite
253
- If you are bundling your application with Vite, then you will need to add this to your config.
254
259
 
255
- ```javascript
256
- // vite.config.js
260
+ If you bundle with Vite, exclude certain native deps during optimize step:
257
261
 
262
+ ```js
263
+ // vite.config.js
258
264
  export default {
259
265
  optimizeDeps: {
260
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"
261
318
  }
262
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
263
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/