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