@faasjs/knex 8.0.0-beta.6 → 8.0.0-beta.8
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 +6 -0
- package/dist/index.cjs +317 -216
- package/dist/index.d.ts +86 -53
- package/dist/index.mjs +286 -212
- package/package.json +10 -13
package/README.md
CHANGED
|
@@ -13,19 +13,25 @@ npm install @faasjs/knex
|
|
|
13
13
|
|
|
14
14
|
## Functions
|
|
15
15
|
|
|
16
|
+
- [createPgliteKnex](functions/createPgliteKnex.md)
|
|
16
17
|
- [initPostgresTypeParsers](functions/initPostgresTypeParsers.md)
|
|
18
|
+
- [mountFaasKnex](functions/mountFaasKnex.md)
|
|
17
19
|
- [query](functions/query.md)
|
|
18
20
|
- [raw](functions/raw.md)
|
|
19
21
|
- [transaction](functions/transaction.md)
|
|
22
|
+
- [unmountFaasKnex](functions/unmountFaasKnex.md)
|
|
20
23
|
- [useKnex](functions/useKnex.md)
|
|
21
24
|
|
|
22
25
|
## Classes
|
|
23
26
|
|
|
24
27
|
- [Knex](classes/Knex.md)
|
|
28
|
+
- [KnexSchema](classes/KnexSchema.md)
|
|
25
29
|
|
|
26
30
|
## Type Aliases
|
|
27
31
|
|
|
28
32
|
- [KnexConfig](type-aliases/KnexConfig.md)
|
|
33
|
+
- [MountedKnexAdapter](type-aliases/MountedKnexAdapter.md)
|
|
34
|
+
- [MountFaasKnexOptions](type-aliases/MountFaasKnexOptions.md)
|
|
29
35
|
|
|
30
36
|
## Variables
|
|
31
37
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,239 +1,340 @@
|
|
|
1
|
-
'
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
8
27
|
|
|
9
|
-
|
|
28
|
+
//#endregion
|
|
29
|
+
let node_crypto = require("node:crypto");
|
|
30
|
+
let node_fs = require("node:fs");
|
|
31
|
+
let node_path = require("node:path");
|
|
32
|
+
let _faasjs_node_utils = require("@faasjs/node-utils");
|
|
33
|
+
let knex = require("knex");
|
|
34
|
+
knex = __toESM(knex);
|
|
35
|
+
let _faasjs_func = require("@faasjs/func");
|
|
10
36
|
|
|
11
|
-
|
|
37
|
+
//#region src/pglite.ts
|
|
38
|
+
function parsePgliteConnection(connection) {
|
|
39
|
+
if (typeof connection === "undefined" || connection === null) return `memory://${(0, node_crypto.randomUUID)()}`;
|
|
40
|
+
if (typeof connection !== "string" || !connection.trim().length) throw Error("[Knex] Invalid \"pglite\" connection, expected non-empty string in config.connection or SECRET_<NAME>_CONNECTION.");
|
|
41
|
+
return connection;
|
|
42
|
+
}
|
|
43
|
+
function ensurePgliteConnectionPath(connection) {
|
|
44
|
+
if (connection.includes("://")) return;
|
|
45
|
+
(0, node_fs.mkdirSync)((0, node_path.dirname)((0, node_path.resolve)(connection)), { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
async function loadPglitePackages() {
|
|
48
|
+
try {
|
|
49
|
+
const pgliteModule = await (0, _faasjs_node_utils.loadPackage)("@electric-sql/pglite", []);
|
|
50
|
+
const PgliteDialect = await (0, _faasjs_node_utils.loadPackage)("knex-pglite");
|
|
51
|
+
if (typeof pgliteModule.PGlite !== "function" || !pgliteModule.types) throw Error("Invalid @electric-sql/pglite exports");
|
|
52
|
+
if (typeof PgliteDialect !== "function") throw Error("Invalid knex-pglite exports");
|
|
53
|
+
return {
|
|
54
|
+
PGlite: pgliteModule.PGlite,
|
|
55
|
+
types: pgliteModule.types,
|
|
56
|
+
PgliteDialect
|
|
57
|
+
};
|
|
58
|
+
} catch {
|
|
59
|
+
throw Error("[Knex] client \"pglite\" requires dependencies \"@electric-sql/pglite\" and \"knex-pglite\". Please install both packages in your project.");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create a knex instance backed by `knex-pglite`.
|
|
64
|
+
* If connection is missing, it defaults to an in-memory database.
|
|
65
|
+
*/
|
|
66
|
+
async function createPgliteKnex(config = {}, connection) {
|
|
67
|
+
const resolvedConnection = parsePgliteConnection(connection ?? config.connection);
|
|
68
|
+
ensurePgliteConnectionPath(resolvedConnection);
|
|
69
|
+
const { PGlite, types, PgliteDialect } = await loadPglitePackages();
|
|
70
|
+
const { client: _client, connection: _connection, pool: _pool, ...restConfig } = config;
|
|
71
|
+
const pglite = new PGlite(resolvedConnection, { parsers: {
|
|
72
|
+
[types.INT2]: (v) => Number.parseInt(v, 10),
|
|
73
|
+
[types.INT4]: (v) => Number.parseInt(v, 10),
|
|
74
|
+
[types.INT8]: (v) => Number.parseInt(v, 10),
|
|
75
|
+
[types.FLOAT4]: (v) => Number.parseFloat(v),
|
|
76
|
+
[types.FLOAT8]: (v) => Number.parseFloat(v),
|
|
77
|
+
[types.NUMERIC]: (v) => Number.parseFloat(v)
|
|
78
|
+
} });
|
|
79
|
+
return (0, knex.default)({
|
|
80
|
+
...restConfig,
|
|
81
|
+
client: PgliteDialect,
|
|
82
|
+
connection: { pglite }
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Mount a knex adapter to `globalThis.FaasJS_Knex` for `@faasjs/knex`.
|
|
87
|
+
*/
|
|
88
|
+
function mountFaasKnex(db, options = {}) {
|
|
89
|
+
const globalWithFaasKnex = globalThis;
|
|
90
|
+
const name = options.name || "knex";
|
|
91
|
+
if (!globalWithFaasKnex.FaasJS_Knex) globalWithFaasKnex.FaasJS_Knex = {};
|
|
92
|
+
globalWithFaasKnex.FaasJS_Knex[name] = {
|
|
93
|
+
adapter: db,
|
|
94
|
+
query: db,
|
|
95
|
+
config: options.config || {}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Remove mounted knex adapter from `globalThis.FaasJS_Knex`.
|
|
100
|
+
*/
|
|
101
|
+
function unmountFaasKnex(name = "knex") {
|
|
102
|
+
const globalWithFaasKnex = globalThis;
|
|
103
|
+
if (!globalWithFaasKnex.FaasJS_Knex) return;
|
|
104
|
+
delete globalWithFaasKnex.FaasJS_Knex[name];
|
|
105
|
+
}
|
|
12
106
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/plugin.ts
|
|
109
|
+
/**
|
|
110
|
+
* Origin [knex](https://knexjs.org/) instance.
|
|
111
|
+
*/
|
|
112
|
+
const originKnex = knex.default;
|
|
113
|
+
const Name = "knex";
|
|
114
|
+
if (!global.FaasJS_Knex) global.FaasJS_Knex = {};
|
|
115
|
+
function getGlobalKnexAdapters() {
|
|
116
|
+
if (!global.FaasJS_Knex) global.FaasJS_Knex = {};
|
|
117
|
+
return global.FaasJS_Knex;
|
|
18
118
|
}
|
|
19
119
|
async function initPostgresTypeParsers() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
(v) => Number.parseInt(v, 10)
|
|
28
|
-
);
|
|
29
|
-
pg.types.setTypeParser(
|
|
30
|
-
pg.types.builtins.INT8,
|
|
31
|
-
(v) => Number.parseInt(v, 10)
|
|
32
|
-
);
|
|
33
|
-
pg.types.setTypeParser(
|
|
34
|
-
pg.types.builtins.FLOAT4,
|
|
35
|
-
(v) => Number.parseFloat(v)
|
|
36
|
-
);
|
|
37
|
-
pg.types.setTypeParser(
|
|
38
|
-
pg.types.builtins.FLOAT8,
|
|
39
|
-
(v) => Number.parseFloat(v)
|
|
40
|
-
);
|
|
41
|
-
pg.types.setTypeParser(
|
|
42
|
-
pg.types.builtins.NUMERIC,
|
|
43
|
-
(v) => Number.parseFloat(v)
|
|
44
|
-
);
|
|
120
|
+
const pg = await (0, _faasjs_node_utils.loadPackage)("pg");
|
|
121
|
+
pg.types.setTypeParser(pg.types.builtins.INT2, (v) => Number.parseInt(v, 10));
|
|
122
|
+
pg.types.setTypeParser(pg.types.builtins.INT4, (v) => Number.parseInt(v, 10));
|
|
123
|
+
pg.types.setTypeParser(pg.types.builtins.INT8, (v) => Number.parseInt(v, 10));
|
|
124
|
+
pg.types.setTypeParser(pg.types.builtins.FLOAT4, (v) => Number.parseFloat(v));
|
|
125
|
+
pg.types.setTypeParser(pg.types.builtins.FLOAT8, (v) => Number.parseFloat(v));
|
|
126
|
+
pg.types.setTypeParser(pg.types.builtins.NUMERIC, (v) => Number.parseFloat(v));
|
|
45
127
|
}
|
|
46
128
|
var Knex = class {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
this.logger.debug("[%s] transaction begin commit", trxId);
|
|
191
|
-
await trx.commit();
|
|
192
|
-
this.logger.debug("[%s] transaction committed: %j", trxId, result);
|
|
193
|
-
trx.emit("commit");
|
|
194
|
-
return result;
|
|
195
|
-
} catch (error) {
|
|
196
|
-
await trx.rollback(error);
|
|
197
|
-
this.logger.error("[%s] transaction rollback: %s", trxId, error);
|
|
198
|
-
trx.emit("rollback", error);
|
|
199
|
-
throw error;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
schema() {
|
|
203
|
-
if (!this.adapter) throw Error(`[${this.name}] Client not initialized.`);
|
|
204
|
-
return this.adapter.schema;
|
|
205
|
-
}
|
|
206
|
-
async quit() {
|
|
207
|
-
if (!global.FaasJS_Knex[this.name]) return;
|
|
208
|
-
try {
|
|
209
|
-
await global.FaasJS_Knex[this.name].adapter.destroy();
|
|
210
|
-
delete global.FaasJS_Knex[this.name];
|
|
211
|
-
} catch (error) {
|
|
212
|
-
console.error(error);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
129
|
+
type = "knex";
|
|
130
|
+
name = Name;
|
|
131
|
+
config;
|
|
132
|
+
adapter;
|
|
133
|
+
query;
|
|
134
|
+
logger;
|
|
135
|
+
constructor(config) {
|
|
136
|
+
if (config) {
|
|
137
|
+
this.name = config.name || this.name;
|
|
138
|
+
this.config = config.config || Object.create(null);
|
|
139
|
+
} else this.config = Object.create(null);
|
|
140
|
+
}
|
|
141
|
+
async onMount(data, next) {
|
|
142
|
+
this.logger = data.logger;
|
|
143
|
+
const existsAdapter = getGlobalKnexAdapters()[this.name];
|
|
144
|
+
if (existsAdapter) {
|
|
145
|
+
this.config = existsAdapter.config;
|
|
146
|
+
this.adapter = existsAdapter.adapter;
|
|
147
|
+
this.query = this.adapter;
|
|
148
|
+
this.logger.debug("use exists adapter");
|
|
149
|
+
await next();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const prefix = `SECRET_${this.name.toUpperCase()}_`;
|
|
153
|
+
for (let key in process.env) if (key.startsWith(prefix)) {
|
|
154
|
+
const value = process.env[key];
|
|
155
|
+
key = key.replace(prefix, "").toLowerCase();
|
|
156
|
+
if (typeof this.config[key] === "undefined") if (key.startsWith("connection_")) {
|
|
157
|
+
if (typeof this.config.connection === "string") continue;
|
|
158
|
+
if (!this.config.connection || typeof this.config.connection !== "object") this.config.connection = Object.create(null);
|
|
159
|
+
this.config.connection[key.replace("connection_", "")] = value;
|
|
160
|
+
} else this.config[key] = value;
|
|
161
|
+
}
|
|
162
|
+
if (data.config.plugins?.[this.name || this.type]?.config) this.config = (0, _faasjs_node_utils.deepMerge)(data.config.plugins[this.name || this.type].config, this.config);
|
|
163
|
+
if (this.config.client === "pglite") {
|
|
164
|
+
const connectionEnvKeys = Object.keys(process.env).filter((key) => key.startsWith(`${prefix}CONNECTION_`));
|
|
165
|
+
if (connectionEnvKeys.length) throw Error(`[Knex] Invalid "pglite" env keys: ${connectionEnvKeys.join(", ")}. Use ${prefix}CONNECTION instead.`);
|
|
166
|
+
this.adapter = await createPgliteKnex(this.config);
|
|
167
|
+
} else {
|
|
168
|
+
switch (this.config.client) {
|
|
169
|
+
case "sqlite3":
|
|
170
|
+
this.config.client = "better-sqlite3";
|
|
171
|
+
this.config.useNullAsDefault = true;
|
|
172
|
+
break;
|
|
173
|
+
case "pg":
|
|
174
|
+
if (!this.config.pool) this.config.pool = Object.create(null);
|
|
175
|
+
this.config.pool = Object.assign({
|
|
176
|
+
propagateCreateError: false,
|
|
177
|
+
min: 0,
|
|
178
|
+
max: 10,
|
|
179
|
+
acquireTimeoutMillis: 5e3,
|
|
180
|
+
idleTimeoutMillis: 3e4
|
|
181
|
+
}, this.config.pool);
|
|
182
|
+
if (typeof this.config.connection === "string" && !this.config.connection.includes("json=true")) this.config.connection = `${this.config.connection}?json=true`;
|
|
183
|
+
break;
|
|
184
|
+
default:
|
|
185
|
+
if (typeof this.config.client === "string") {
|
|
186
|
+
if (this.config.client.startsWith("npm:")) {
|
|
187
|
+
const client = await (0, _faasjs_node_utils.loadPackage)(this.config.client.replace("npm:", ""));
|
|
188
|
+
if (!client) throw Error(`Invalid client: ${this.config.client}`);
|
|
189
|
+
if (typeof client === "function") {
|
|
190
|
+
this.config.client = client;
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
if (client.default && typeof client.default === "function") {
|
|
194
|
+
this.config.client = client.default;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
throw Error(`Invalid client: ${this.config.client}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
this.adapter = (0, knex.default)(this.config);
|
|
203
|
+
if (this.config.client === "pg") await initPostgresTypeParsers();
|
|
204
|
+
}
|
|
205
|
+
this.query = this.adapter;
|
|
206
|
+
this.query.on("query", ({ sql, __knexQueryUid, bindings }) => {
|
|
207
|
+
if (!__knexQueryUid) return;
|
|
208
|
+
this.logger.time(`Knex${this.name}${__knexQueryUid}`);
|
|
209
|
+
this.logger.debug("[%s] query begin: %s %j", __knexQueryUid, sql, bindings);
|
|
210
|
+
}).on("query-response", (response, { sql, __knexQueryUid, bindings }) => {
|
|
211
|
+
if (!__knexQueryUid) return;
|
|
212
|
+
this.logger.timeEnd(`Knex${this.name}${__knexQueryUid}`, "[%s] query done: %s %j %j", __knexQueryUid, sql, bindings, response);
|
|
213
|
+
}).on("query-error", (_, { __knexQueryUid, sql, bindings }) => {
|
|
214
|
+
if (!__knexQueryUid) return;
|
|
215
|
+
this.logger.timeEnd(`Knex${this.name}${__knexQueryUid}`, "[%s] query failed: %s %j", __knexQueryUid, sql, bindings);
|
|
216
|
+
});
|
|
217
|
+
data.logger.debug("connected");
|
|
218
|
+
getGlobalKnexAdapters()[this.name] = this;
|
|
219
|
+
await next();
|
|
220
|
+
}
|
|
221
|
+
async onInvoke(data, next) {
|
|
222
|
+
this.logger = data.logger;
|
|
223
|
+
await next();
|
|
224
|
+
}
|
|
225
|
+
async raw(sql, bindings = []) {
|
|
226
|
+
if (!this.adapter) throw Error("[Knex] Client not initialized.");
|
|
227
|
+
return this.adapter.raw(sql, bindings);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Wraps a transaction, returning a promise that resolves to the return value of the callback.
|
|
231
|
+
*
|
|
232
|
+
* - Support 'commit' and 'rollback' event.
|
|
233
|
+
*/
|
|
234
|
+
async transaction(scope, config, options) {
|
|
235
|
+
if (!this.adapter) throw Error(`[${this.name}] Client not initialized.`);
|
|
236
|
+
if (options?.trx) return scope(options.trx);
|
|
237
|
+
const trx = await this.adapter.transaction(config);
|
|
238
|
+
const trxId = (0, node_crypto.randomUUID)();
|
|
239
|
+
this.logger.debug("[%s] transaction begin", trxId);
|
|
240
|
+
try {
|
|
241
|
+
const result = await scope(trx);
|
|
242
|
+
if (trx.isCompleted()) {
|
|
243
|
+
this.logger.debug("[%s] transaction has been finished in scope", trxId);
|
|
244
|
+
return result;
|
|
245
|
+
}
|
|
246
|
+
this.logger.debug("[%s] transaction begin commit", trxId);
|
|
247
|
+
await trx.commit();
|
|
248
|
+
this.logger.debug("[%s] transaction committed: %j", trxId, result);
|
|
249
|
+
trx.emit("commit");
|
|
250
|
+
return result;
|
|
251
|
+
} catch (error) {
|
|
252
|
+
await trx.rollback(error);
|
|
253
|
+
this.logger.error("[%s] transaction rollback: %s", trxId, error);
|
|
254
|
+
trx.emit("rollback", error);
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
schema() {
|
|
259
|
+
if (!this.adapter) throw Error(`[${this.name}] Client not initialized.`);
|
|
260
|
+
return this.adapter.schema;
|
|
261
|
+
}
|
|
262
|
+
async quit() {
|
|
263
|
+
const adapters = getGlobalKnexAdapters();
|
|
264
|
+
if (!adapters[this.name]) return;
|
|
265
|
+
try {
|
|
266
|
+
await adapters[this.name].adapter.destroy();
|
|
267
|
+
delete adapters[this.name];
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error(error);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
215
272
|
};
|
|
216
273
|
function useKnex(config) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
274
|
+
const name = config?.name || Name;
|
|
275
|
+
const adapters = getGlobalKnexAdapters();
|
|
276
|
+
if (adapters[name]) return (0, _faasjs_func.usePlugin)(adapters[name]);
|
|
277
|
+
return (0, _faasjs_func.usePlugin)(new Knex(config));
|
|
220
278
|
}
|
|
221
279
|
function query(table) {
|
|
222
|
-
|
|
223
|
-
table
|
|
224
|
-
);
|
|
280
|
+
return useKnex().query(table);
|
|
225
281
|
}
|
|
226
282
|
async function transaction(scope, config, options) {
|
|
227
|
-
|
|
283
|
+
return useKnex().transaction(scope, config, options);
|
|
228
284
|
}
|
|
229
285
|
async function raw(sql, bindings = []) {
|
|
230
|
-
|
|
286
|
+
return useKnex().raw(sql, bindings);
|
|
231
287
|
}
|
|
232
288
|
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/schema.ts
|
|
291
|
+
const DefaultMigratorConfig = {
|
|
292
|
+
directory: "./src/db/migrations",
|
|
293
|
+
extension: "ts"
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Migration helper for FaasJS's knex plugin.
|
|
297
|
+
*/
|
|
298
|
+
var KnexSchema = class {
|
|
299
|
+
knex;
|
|
300
|
+
constructor(knex) {
|
|
301
|
+
this.knex = knex;
|
|
302
|
+
}
|
|
303
|
+
getAdapter() {
|
|
304
|
+
if (!this.knex.adapter) throw Error(`[${this.knex.name}] Client not initialized.`);
|
|
305
|
+
return this.knex.adapter;
|
|
306
|
+
}
|
|
307
|
+
getMigratorConfig() {
|
|
308
|
+
return Object.assign({}, DefaultMigratorConfig, this.knex.config?.migrations || Object.create(null));
|
|
309
|
+
}
|
|
310
|
+
async migrateLatest() {
|
|
311
|
+
return this.getAdapter().migrate.latest(this.getMigratorConfig());
|
|
312
|
+
}
|
|
313
|
+
async migrateRollback() {
|
|
314
|
+
return this.getAdapter().migrate.rollback(this.getMigratorConfig());
|
|
315
|
+
}
|
|
316
|
+
async migrateStatus() {
|
|
317
|
+
return this.getAdapter().migrate.status(this.getMigratorConfig());
|
|
318
|
+
}
|
|
319
|
+
async migrateCurrentVersion() {
|
|
320
|
+
return this.getAdapter().migrate.currentVersion(this.getMigratorConfig());
|
|
321
|
+
}
|
|
322
|
+
async migrateMake(name) {
|
|
323
|
+
const migrationName = name?.trim();
|
|
324
|
+
if (!migrationName) throw Error("[KnexSchema] Missing migration name. Usage: npm run migrate:make -- create_users");
|
|
325
|
+
return this.getAdapter().migrate.make(migrationName, this.getMigratorConfig());
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
//#endregion
|
|
233
330
|
exports.Knex = Knex;
|
|
331
|
+
exports.KnexSchema = KnexSchema;
|
|
332
|
+
exports.createPgliteKnex = createPgliteKnex;
|
|
234
333
|
exports.initPostgresTypeParsers = initPostgresTypeParsers;
|
|
334
|
+
exports.mountFaasKnex = mountFaasKnex;
|
|
235
335
|
exports.originKnex = originKnex;
|
|
236
336
|
exports.query = query;
|
|
237
337
|
exports.raw = raw;
|
|
238
338
|
exports.transaction = transaction;
|
|
239
|
-
exports.
|
|
339
|
+
exports.unmountFaasKnex = unmountFaasKnex;
|
|
340
|
+
exports.useKnex = useKnex;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,68 +1,101 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
export { Knex as OriginKnex } from 'knex';
|
|
1
|
+
import knex, { Knex as Knex$1, Knex as OriginKnex } from "knex";
|
|
2
|
+
import { InvokeData, MountData, Next, Plugin, UseifyPlugin } from "@faasjs/func";
|
|
3
|
+
import { Logger } from "@faasjs/logger";
|
|
5
4
|
|
|
5
|
+
//#region src/pglite.d.ts
|
|
6
|
+
type MountedKnexAdapter = {
|
|
7
|
+
adapter: Knex$1;
|
|
8
|
+
query: Knex$1;
|
|
9
|
+
config: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
type MountFaasKnexOptions = {
|
|
12
|
+
/** key of `globalThis.FaasJS_Knex`, default is `knex` */name?: string; /** optional config metadata passed through to `@faasjs/knex` */
|
|
13
|
+
config?: Record<string, unknown>;
|
|
14
|
+
};
|
|
6
15
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* [](https://github.com/faasjs/faasjs/blob/main/packages/knex/LICENSE)
|
|
10
|
-
* [](https://www.npmjs.com/package/@faasjs/knex)
|
|
11
|
-
*
|
|
12
|
-
* ## Install
|
|
13
|
-
*
|
|
14
|
-
* ```sh
|
|
15
|
-
* npm install @faasjs/knex
|
|
16
|
-
* ```
|
|
17
|
-
* @packageDocumentation
|
|
16
|
+
* Create a knex instance backed by `knex-pglite`.
|
|
17
|
+
* If connection is missing, it defaults to an in-memory database.
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
declare function createPgliteKnex(config?: Partial<Knex$1.Config>, connection?: string): Promise<Knex$1>;
|
|
20
|
+
/**
|
|
21
|
+
* Mount a knex adapter to `globalThis.FaasJS_Knex` for `@faasjs/knex`.
|
|
22
|
+
*/
|
|
23
|
+
declare function mountFaasKnex(db: Knex$1, options?: MountFaasKnexOptions): void;
|
|
24
|
+
/**
|
|
25
|
+
* Remove mounted knex adapter from `globalThis.FaasJS_Knex`.
|
|
26
|
+
*/
|
|
27
|
+
declare function unmountFaasKnex(name?: string): void;
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/plugin.d.ts
|
|
20
30
|
/**
|
|
21
31
|
* Origin [knex](https://knexjs.org/) instance.
|
|
22
32
|
*/
|
|
23
33
|
declare const originKnex: typeof knex;
|
|
24
|
-
|
|
25
34
|
type KnexConfig = {
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
name?: string;
|
|
36
|
+
config?: OriginKnex.Config;
|
|
28
37
|
};
|
|
29
38
|
declare function initPostgresTypeParsers(): Promise<void>;
|
|
30
39
|
declare class Knex implements Plugin {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
readonly type = "knex";
|
|
41
|
+
readonly name: string;
|
|
42
|
+
config: OriginKnex.Config;
|
|
43
|
+
adapter: OriginKnex;
|
|
44
|
+
query: OriginKnex;
|
|
45
|
+
logger: Logger;
|
|
46
|
+
constructor(config?: KnexConfig);
|
|
47
|
+
onMount(data: MountData, next: Next): Promise<void>;
|
|
48
|
+
onInvoke(data: InvokeData<any, any, any>, next: Next): Promise<void>;
|
|
49
|
+
raw<TResult = any>(sql: string, bindings?: OriginKnex.RawBinding[] | OriginKnex.ValueDict): Promise<OriginKnex.Raw<TResult>>;
|
|
50
|
+
/**
|
|
51
|
+
* Wraps a transaction, returning a promise that resolves to the return value of the callback.
|
|
52
|
+
*
|
|
53
|
+
* - Support 'commit' and 'rollback' event.
|
|
54
|
+
*/
|
|
55
|
+
transaction<TResult = any>(scope: (trx: OriginKnex.Transaction<any, any>) => Promise<TResult>, config?: OriginKnex.TransactionConfig, options?: {
|
|
56
|
+
trx?: OriginKnex.Transaction;
|
|
57
|
+
}): Promise<TResult>;
|
|
58
|
+
schema(): OriginKnex.SchemaBuilder;
|
|
59
|
+
quit(): Promise<void>;
|
|
51
60
|
}
|
|
52
61
|
declare function useKnex(config?: KnexConfig): UseifyPlugin<Knex>;
|
|
53
|
-
declare function query<TName extends
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
declare function query<TName extends OriginKnex.TableNames>(table: TName): OriginKnex.QueryBuilder<OriginKnex.TableType<TName>, {
|
|
63
|
+
_base: OriginKnex.ResolveTableType<OriginKnex.TableType<TName>, 'base'>;
|
|
64
|
+
_hasSelection: false;
|
|
65
|
+
_keys: never;
|
|
66
|
+
_aliases: {};
|
|
67
|
+
_single: false;
|
|
68
|
+
_intersectProps: {};
|
|
69
|
+
_unionProps: never;
|
|
61
70
|
}[]>;
|
|
62
|
-
declare function query<TName extends {} = any, TResult = any[]>(table: string):
|
|
63
|
-
declare function transaction<TResult = any>(scope: (trx:
|
|
64
|
-
|
|
71
|
+
declare function query<TName extends {} = any, TResult = any[]>(table: string): OriginKnex.QueryBuilder<TName, TResult>;
|
|
72
|
+
declare function transaction<TResult = any>(scope: (trx: OriginKnex.Transaction<any, any>) => Promise<TResult>, config?: OriginKnex.TransactionConfig, options?: {
|
|
73
|
+
trx?: OriginKnex.Transaction;
|
|
65
74
|
}): Promise<TResult>;
|
|
66
|
-
declare function raw<TResult = any>(sql: string, bindings?:
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
declare function raw<TResult = any>(sql: string, bindings?: OriginKnex.RawBinding[] | OriginKnex.ValueDict): Promise<OriginKnex.Raw<TResult>>;
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/schema.d.ts
|
|
78
|
+
/**
|
|
79
|
+
* Migration helper for FaasJS's knex plugin.
|
|
80
|
+
*/
|
|
81
|
+
declare class KnexSchema {
|
|
82
|
+
readonly knex: {
|
|
83
|
+
name: string;
|
|
84
|
+
adapter?: Knex$1;
|
|
85
|
+
config: Knex$1.Config;
|
|
86
|
+
};
|
|
87
|
+
constructor(knex: {
|
|
88
|
+
name: string;
|
|
89
|
+
adapter?: Knex$1;
|
|
90
|
+
config: Knex$1.Config;
|
|
91
|
+
});
|
|
92
|
+
private getAdapter;
|
|
93
|
+
private getMigratorConfig;
|
|
94
|
+
migrateLatest(): Promise<any>;
|
|
95
|
+
migrateRollback(): Promise<any>;
|
|
96
|
+
migrateStatus(): Promise<number>;
|
|
97
|
+
migrateCurrentVersion(): Promise<string>;
|
|
98
|
+
migrateMake(name: string): Promise<string>;
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { Knex, KnexConfig, KnexSchema, MountFaasKnexOptions, MountedKnexAdapter, type OriginKnex, createPgliteKnex, initPostgresTypeParsers, mountFaasKnex, originKnex, query, raw, transaction, unmountFaasKnex, useKnex };
|
package/dist/index.mjs
CHANGED
|
@@ -1,227 +1,301 @@
|
|
|
1
|
-
import { randomUUID } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { loadPackage } from
|
|
5
|
-
import knex from
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdirSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { deepMerge, loadPackage } from "@faasjs/node-utils";
|
|
5
|
+
import knex from "knex";
|
|
6
|
+
import { usePlugin } from "@faasjs/func";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (!
|
|
11
|
-
|
|
8
|
+
//#region src/pglite.ts
|
|
9
|
+
function parsePgliteConnection(connection) {
|
|
10
|
+
if (typeof connection === "undefined" || connection === null) return `memory://${randomUUID()}`;
|
|
11
|
+
if (typeof connection !== "string" || !connection.trim().length) throw Error("[Knex] Invalid \"pglite\" connection, expected non-empty string in config.connection or SECRET_<NAME>_CONNECTION.");
|
|
12
|
+
return connection;
|
|
13
|
+
}
|
|
14
|
+
function ensurePgliteConnectionPath(connection) {
|
|
15
|
+
if (connection.includes("://")) return;
|
|
16
|
+
mkdirSync(dirname(resolve(connection)), { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
async function loadPglitePackages() {
|
|
19
|
+
try {
|
|
20
|
+
const pgliteModule = await loadPackage("@electric-sql/pglite", []);
|
|
21
|
+
const PgliteDialect = await loadPackage("knex-pglite");
|
|
22
|
+
if (typeof pgliteModule.PGlite !== "function" || !pgliteModule.types) throw Error("Invalid @electric-sql/pglite exports");
|
|
23
|
+
if (typeof PgliteDialect !== "function") throw Error("Invalid knex-pglite exports");
|
|
24
|
+
return {
|
|
25
|
+
PGlite: pgliteModule.PGlite,
|
|
26
|
+
types: pgliteModule.types,
|
|
27
|
+
PgliteDialect
|
|
28
|
+
};
|
|
29
|
+
} catch {
|
|
30
|
+
throw Error("[Knex] client \"pglite\" requires dependencies \"@electric-sql/pglite\" and \"knex-pglite\". Please install both packages in your project.");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a knex instance backed by `knex-pglite`.
|
|
35
|
+
* If connection is missing, it defaults to an in-memory database.
|
|
36
|
+
*/
|
|
37
|
+
async function createPgliteKnex(config = {}, connection) {
|
|
38
|
+
const resolvedConnection = parsePgliteConnection(connection ?? config.connection);
|
|
39
|
+
ensurePgliteConnectionPath(resolvedConnection);
|
|
40
|
+
const { PGlite, types, PgliteDialect } = await loadPglitePackages();
|
|
41
|
+
const { client: _client, connection: _connection, pool: _pool, ...restConfig } = config;
|
|
42
|
+
const pglite = new PGlite(resolvedConnection, { parsers: {
|
|
43
|
+
[types.INT2]: (v) => Number.parseInt(v, 10),
|
|
44
|
+
[types.INT4]: (v) => Number.parseInt(v, 10),
|
|
45
|
+
[types.INT8]: (v) => Number.parseInt(v, 10),
|
|
46
|
+
[types.FLOAT4]: (v) => Number.parseFloat(v),
|
|
47
|
+
[types.FLOAT8]: (v) => Number.parseFloat(v),
|
|
48
|
+
[types.NUMERIC]: (v) => Number.parseFloat(v)
|
|
49
|
+
} });
|
|
50
|
+
return knex({
|
|
51
|
+
...restConfig,
|
|
52
|
+
client: PgliteDialect,
|
|
53
|
+
connection: { pglite }
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Mount a knex adapter to `globalThis.FaasJS_Knex` for `@faasjs/knex`.
|
|
58
|
+
*/
|
|
59
|
+
function mountFaasKnex(db, options = {}) {
|
|
60
|
+
const globalWithFaasKnex = globalThis;
|
|
61
|
+
const name = options.name || "knex";
|
|
62
|
+
if (!globalWithFaasKnex.FaasJS_Knex) globalWithFaasKnex.FaasJS_Knex = {};
|
|
63
|
+
globalWithFaasKnex.FaasJS_Knex[name] = {
|
|
64
|
+
adapter: db,
|
|
65
|
+
query: db,
|
|
66
|
+
config: options.config || {}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Remove mounted knex adapter from `globalThis.FaasJS_Knex`.
|
|
71
|
+
*/
|
|
72
|
+
function unmountFaasKnex(name = "knex") {
|
|
73
|
+
const globalWithFaasKnex = globalThis;
|
|
74
|
+
if (!globalWithFaasKnex.FaasJS_Knex) return;
|
|
75
|
+
delete globalWithFaasKnex.FaasJS_Knex[name];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/plugin.ts
|
|
80
|
+
/**
|
|
81
|
+
* Origin [knex](https://knexjs.org/) instance.
|
|
82
|
+
*/
|
|
83
|
+
const originKnex = knex;
|
|
84
|
+
const Name = "knex";
|
|
85
|
+
if (!global.FaasJS_Knex) global.FaasJS_Knex = {};
|
|
86
|
+
function getGlobalKnexAdapters() {
|
|
87
|
+
if (!global.FaasJS_Knex) global.FaasJS_Knex = {};
|
|
88
|
+
return global.FaasJS_Knex;
|
|
12
89
|
}
|
|
13
90
|
async function initPostgresTypeParsers() {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
(v) => Number.parseInt(v, 10)
|
|
22
|
-
);
|
|
23
|
-
pg.types.setTypeParser(
|
|
24
|
-
pg.types.builtins.INT8,
|
|
25
|
-
(v) => Number.parseInt(v, 10)
|
|
26
|
-
);
|
|
27
|
-
pg.types.setTypeParser(
|
|
28
|
-
pg.types.builtins.FLOAT4,
|
|
29
|
-
(v) => Number.parseFloat(v)
|
|
30
|
-
);
|
|
31
|
-
pg.types.setTypeParser(
|
|
32
|
-
pg.types.builtins.FLOAT8,
|
|
33
|
-
(v) => Number.parseFloat(v)
|
|
34
|
-
);
|
|
35
|
-
pg.types.setTypeParser(
|
|
36
|
-
pg.types.builtins.NUMERIC,
|
|
37
|
-
(v) => Number.parseFloat(v)
|
|
38
|
-
);
|
|
91
|
+
const pg = await loadPackage("pg");
|
|
92
|
+
pg.types.setTypeParser(pg.types.builtins.INT2, (v) => Number.parseInt(v, 10));
|
|
93
|
+
pg.types.setTypeParser(pg.types.builtins.INT4, (v) => Number.parseInt(v, 10));
|
|
94
|
+
pg.types.setTypeParser(pg.types.builtins.INT8, (v) => Number.parseInt(v, 10));
|
|
95
|
+
pg.types.setTypeParser(pg.types.builtins.FLOAT4, (v) => Number.parseFloat(v));
|
|
96
|
+
pg.types.setTypeParser(pg.types.builtins.FLOAT8, (v) => Number.parseFloat(v));
|
|
97
|
+
pg.types.setTypeParser(pg.types.builtins.NUMERIC, (v) => Number.parseFloat(v));
|
|
39
98
|
}
|
|
40
99
|
var Knex = class {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
this.logger.debug("[%s] transaction begin commit", trxId);
|
|
185
|
-
await trx.commit();
|
|
186
|
-
this.logger.debug("[%s] transaction committed: %j", trxId, result);
|
|
187
|
-
trx.emit("commit");
|
|
188
|
-
return result;
|
|
189
|
-
} catch (error) {
|
|
190
|
-
await trx.rollback(error);
|
|
191
|
-
this.logger.error("[%s] transaction rollback: %s", trxId, error);
|
|
192
|
-
trx.emit("rollback", error);
|
|
193
|
-
throw error;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
schema() {
|
|
197
|
-
if (!this.adapter) throw Error(`[${this.name}] Client not initialized.`);
|
|
198
|
-
return this.adapter.schema;
|
|
199
|
-
}
|
|
200
|
-
async quit() {
|
|
201
|
-
if (!global.FaasJS_Knex[this.name]) return;
|
|
202
|
-
try {
|
|
203
|
-
await global.FaasJS_Knex[this.name].adapter.destroy();
|
|
204
|
-
delete global.FaasJS_Knex[this.name];
|
|
205
|
-
} catch (error) {
|
|
206
|
-
console.error(error);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
100
|
+
type = "knex";
|
|
101
|
+
name = Name;
|
|
102
|
+
config;
|
|
103
|
+
adapter;
|
|
104
|
+
query;
|
|
105
|
+
logger;
|
|
106
|
+
constructor(config) {
|
|
107
|
+
if (config) {
|
|
108
|
+
this.name = config.name || this.name;
|
|
109
|
+
this.config = config.config || Object.create(null);
|
|
110
|
+
} else this.config = Object.create(null);
|
|
111
|
+
}
|
|
112
|
+
async onMount(data, next) {
|
|
113
|
+
this.logger = data.logger;
|
|
114
|
+
const existsAdapter = getGlobalKnexAdapters()[this.name];
|
|
115
|
+
if (existsAdapter) {
|
|
116
|
+
this.config = existsAdapter.config;
|
|
117
|
+
this.adapter = existsAdapter.adapter;
|
|
118
|
+
this.query = this.adapter;
|
|
119
|
+
this.logger.debug("use exists adapter");
|
|
120
|
+
await next();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const prefix = `SECRET_${this.name.toUpperCase()}_`;
|
|
124
|
+
for (let key in process.env) if (key.startsWith(prefix)) {
|
|
125
|
+
const value = process.env[key];
|
|
126
|
+
key = key.replace(prefix, "").toLowerCase();
|
|
127
|
+
if (typeof this.config[key] === "undefined") if (key.startsWith("connection_")) {
|
|
128
|
+
if (typeof this.config.connection === "string") continue;
|
|
129
|
+
if (!this.config.connection || typeof this.config.connection !== "object") this.config.connection = Object.create(null);
|
|
130
|
+
this.config.connection[key.replace("connection_", "")] = value;
|
|
131
|
+
} else this.config[key] = value;
|
|
132
|
+
}
|
|
133
|
+
if (data.config.plugins?.[this.name || this.type]?.config) this.config = deepMerge(data.config.plugins[this.name || this.type].config, this.config);
|
|
134
|
+
if (this.config.client === "pglite") {
|
|
135
|
+
const connectionEnvKeys = Object.keys(process.env).filter((key) => key.startsWith(`${prefix}CONNECTION_`));
|
|
136
|
+
if (connectionEnvKeys.length) throw Error(`[Knex] Invalid "pglite" env keys: ${connectionEnvKeys.join(", ")}. Use ${prefix}CONNECTION instead.`);
|
|
137
|
+
this.adapter = await createPgliteKnex(this.config);
|
|
138
|
+
} else {
|
|
139
|
+
switch (this.config.client) {
|
|
140
|
+
case "sqlite3":
|
|
141
|
+
this.config.client = "better-sqlite3";
|
|
142
|
+
this.config.useNullAsDefault = true;
|
|
143
|
+
break;
|
|
144
|
+
case "pg":
|
|
145
|
+
if (!this.config.pool) this.config.pool = Object.create(null);
|
|
146
|
+
this.config.pool = Object.assign({
|
|
147
|
+
propagateCreateError: false,
|
|
148
|
+
min: 0,
|
|
149
|
+
max: 10,
|
|
150
|
+
acquireTimeoutMillis: 5e3,
|
|
151
|
+
idleTimeoutMillis: 3e4
|
|
152
|
+
}, this.config.pool);
|
|
153
|
+
if (typeof this.config.connection === "string" && !this.config.connection.includes("json=true")) this.config.connection = `${this.config.connection}?json=true`;
|
|
154
|
+
break;
|
|
155
|
+
default:
|
|
156
|
+
if (typeof this.config.client === "string") {
|
|
157
|
+
if (this.config.client.startsWith("npm:")) {
|
|
158
|
+
const client = await loadPackage(this.config.client.replace("npm:", ""));
|
|
159
|
+
if (!client) throw Error(`Invalid client: ${this.config.client}`);
|
|
160
|
+
if (typeof client === "function") {
|
|
161
|
+
this.config.client = client;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
if (client.default && typeof client.default === "function") {
|
|
165
|
+
this.config.client = client.default;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
throw Error(`Invalid client: ${this.config.client}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
this.adapter = knex(this.config);
|
|
174
|
+
if (this.config.client === "pg") await initPostgresTypeParsers();
|
|
175
|
+
}
|
|
176
|
+
this.query = this.adapter;
|
|
177
|
+
this.query.on("query", ({ sql, __knexQueryUid, bindings }) => {
|
|
178
|
+
if (!__knexQueryUid) return;
|
|
179
|
+
this.logger.time(`Knex${this.name}${__knexQueryUid}`);
|
|
180
|
+
this.logger.debug("[%s] query begin: %s %j", __knexQueryUid, sql, bindings);
|
|
181
|
+
}).on("query-response", (response, { sql, __knexQueryUid, bindings }) => {
|
|
182
|
+
if (!__knexQueryUid) return;
|
|
183
|
+
this.logger.timeEnd(`Knex${this.name}${__knexQueryUid}`, "[%s] query done: %s %j %j", __knexQueryUid, sql, bindings, response);
|
|
184
|
+
}).on("query-error", (_, { __knexQueryUid, sql, bindings }) => {
|
|
185
|
+
if (!__knexQueryUid) return;
|
|
186
|
+
this.logger.timeEnd(`Knex${this.name}${__knexQueryUid}`, "[%s] query failed: %s %j", __knexQueryUid, sql, bindings);
|
|
187
|
+
});
|
|
188
|
+
data.logger.debug("connected");
|
|
189
|
+
getGlobalKnexAdapters()[this.name] = this;
|
|
190
|
+
await next();
|
|
191
|
+
}
|
|
192
|
+
async onInvoke(data, next) {
|
|
193
|
+
this.logger = data.logger;
|
|
194
|
+
await next();
|
|
195
|
+
}
|
|
196
|
+
async raw(sql, bindings = []) {
|
|
197
|
+
if (!this.adapter) throw Error("[Knex] Client not initialized.");
|
|
198
|
+
return this.adapter.raw(sql, bindings);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Wraps a transaction, returning a promise that resolves to the return value of the callback.
|
|
202
|
+
*
|
|
203
|
+
* - Support 'commit' and 'rollback' event.
|
|
204
|
+
*/
|
|
205
|
+
async transaction(scope, config, options) {
|
|
206
|
+
if (!this.adapter) throw Error(`[${this.name}] Client not initialized.`);
|
|
207
|
+
if (options?.trx) return scope(options.trx);
|
|
208
|
+
const trx = await this.adapter.transaction(config);
|
|
209
|
+
const trxId = randomUUID();
|
|
210
|
+
this.logger.debug("[%s] transaction begin", trxId);
|
|
211
|
+
try {
|
|
212
|
+
const result = await scope(trx);
|
|
213
|
+
if (trx.isCompleted()) {
|
|
214
|
+
this.logger.debug("[%s] transaction has been finished in scope", trxId);
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
this.logger.debug("[%s] transaction begin commit", trxId);
|
|
218
|
+
await trx.commit();
|
|
219
|
+
this.logger.debug("[%s] transaction committed: %j", trxId, result);
|
|
220
|
+
trx.emit("commit");
|
|
221
|
+
return result;
|
|
222
|
+
} catch (error) {
|
|
223
|
+
await trx.rollback(error);
|
|
224
|
+
this.logger.error("[%s] transaction rollback: %s", trxId, error);
|
|
225
|
+
trx.emit("rollback", error);
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
schema() {
|
|
230
|
+
if (!this.adapter) throw Error(`[${this.name}] Client not initialized.`);
|
|
231
|
+
return this.adapter.schema;
|
|
232
|
+
}
|
|
233
|
+
async quit() {
|
|
234
|
+
const adapters = getGlobalKnexAdapters();
|
|
235
|
+
if (!adapters[this.name]) return;
|
|
236
|
+
try {
|
|
237
|
+
await adapters[this.name].adapter.destroy();
|
|
238
|
+
delete adapters[this.name];
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error(error);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
209
243
|
};
|
|
210
244
|
function useKnex(config) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
245
|
+
const name = config?.name || Name;
|
|
246
|
+
const adapters = getGlobalKnexAdapters();
|
|
247
|
+
if (adapters[name]) return usePlugin(adapters[name]);
|
|
248
|
+
return usePlugin(new Knex(config));
|
|
214
249
|
}
|
|
215
250
|
function query(table) {
|
|
216
|
-
|
|
217
|
-
table
|
|
218
|
-
);
|
|
251
|
+
return useKnex().query(table);
|
|
219
252
|
}
|
|
220
253
|
async function transaction(scope, config, options) {
|
|
221
|
-
|
|
254
|
+
return useKnex().transaction(scope, config, options);
|
|
222
255
|
}
|
|
223
256
|
async function raw(sql, bindings = []) {
|
|
224
|
-
|
|
257
|
+
return useKnex().raw(sql, bindings);
|
|
225
258
|
}
|
|
226
259
|
|
|
227
|
-
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region src/schema.ts
|
|
262
|
+
const DefaultMigratorConfig = {
|
|
263
|
+
directory: "./src/db/migrations",
|
|
264
|
+
extension: "ts"
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Migration helper for FaasJS's knex plugin.
|
|
268
|
+
*/
|
|
269
|
+
var KnexSchema = class {
|
|
270
|
+
knex;
|
|
271
|
+
constructor(knex) {
|
|
272
|
+
this.knex = knex;
|
|
273
|
+
}
|
|
274
|
+
getAdapter() {
|
|
275
|
+
if (!this.knex.adapter) throw Error(`[${this.knex.name}] Client not initialized.`);
|
|
276
|
+
return this.knex.adapter;
|
|
277
|
+
}
|
|
278
|
+
getMigratorConfig() {
|
|
279
|
+
return Object.assign({}, DefaultMigratorConfig, this.knex.config?.migrations || Object.create(null));
|
|
280
|
+
}
|
|
281
|
+
async migrateLatest() {
|
|
282
|
+
return this.getAdapter().migrate.latest(this.getMigratorConfig());
|
|
283
|
+
}
|
|
284
|
+
async migrateRollback() {
|
|
285
|
+
return this.getAdapter().migrate.rollback(this.getMigratorConfig());
|
|
286
|
+
}
|
|
287
|
+
async migrateStatus() {
|
|
288
|
+
return this.getAdapter().migrate.status(this.getMigratorConfig());
|
|
289
|
+
}
|
|
290
|
+
async migrateCurrentVersion() {
|
|
291
|
+
return this.getAdapter().migrate.currentVersion(this.getMigratorConfig());
|
|
292
|
+
}
|
|
293
|
+
async migrateMake(name) {
|
|
294
|
+
const migrationName = name?.trim();
|
|
295
|
+
if (!migrationName) throw Error("[KnexSchema] Missing migration name. Usage: npm run migrate:make -- create_users");
|
|
296
|
+
return this.getAdapter().migrate.make(migrationName, this.getMigratorConfig());
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
//#endregion
|
|
301
|
+
export { Knex, KnexSchema, createPgliteKnex, initPostgresTypeParsers, mountFaasKnex, originKnex, query, raw, transaction, unmountFaasKnex, useKnex };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faasjs/knex",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -24,29 +24,26 @@
|
|
|
24
24
|
},
|
|
25
25
|
"funding": "https://github.com/sponsors/faasjs",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "
|
|
27
|
+
"build": "tsdown src/index.ts --config ../../tsdown.config.ts"
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"dist"
|
|
31
31
|
],
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"knex": "*",
|
|
34
|
-
"@faasjs/
|
|
35
|
-
"@faasjs/
|
|
36
|
-
"@faasjs/
|
|
34
|
+
"@faasjs/func": ">=8.0.0-beta.8",
|
|
35
|
+
"@faasjs/logger": ">=8.0.0-beta.8",
|
|
36
|
+
"@faasjs/node-utils": ">=8.0.0-beta.8"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"knex": "*",
|
|
40
|
-
"@faasjs/
|
|
41
|
-
"@faasjs/
|
|
42
|
-
"@faasjs/
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"@types/node": "*",
|
|
40
|
+
"@faasjs/func": ">=8.0.0-beta.8",
|
|
41
|
+
"@faasjs/logger": ">=8.0.0-beta.8",
|
|
42
|
+
"@faasjs/node-utils": ">=8.0.0-beta.8",
|
|
43
|
+
"better-sqlite3": "*",
|
|
44
|
+
"knex-pglite": "*",
|
|
46
45
|
"@types/pg": "*",
|
|
47
|
-
"mysql": "*",
|
|
48
46
|
"pg": "*",
|
|
49
|
-
"better-sqlite3": "*",
|
|
50
47
|
"cloudflare-d1-http-knex": "*"
|
|
51
48
|
},
|
|
52
49
|
"engines": {
|