@teamkeel/functions-runtime 0.335.0 → 0.337.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/package.json +1 -2
- package/pnpm-lock.yaml +8 -48
- package/src/ModelAPI.js +7 -7
- package/src/ModelAPI.test.js +3 -3
- package/src/QueryBuilder.js +3 -3
- package/src/database.js +90 -39
- package/src/handleRequest.js +2 -2
- package/src/handleRequest.test.js +2 -2
- package/src/index.js +2 -2
- package/src/permissions.test.js +2 -2
- package/src/tryExecuteFunction.js +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teamkeel/functions-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.337.0",
|
|
4
4
|
"description": "Internal package used by @teamkeel/sdk",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@opentelemetry/api": "^1.4.1",
|
|
23
23
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.38.0",
|
|
24
|
-
"@opentelemetry/instrumentation": "^0.40.0",
|
|
25
24
|
"@opentelemetry/resources": "^1.12.0",
|
|
26
25
|
"@opentelemetry/sdk-trace-base": "^1.12.0",
|
|
27
26
|
"@opentelemetry/sdk-trace-node": "^1.12.0",
|
package/pnpm-lock.yaml
CHANGED
|
@@ -7,9 +7,6 @@ dependencies:
|
|
|
7
7
|
'@opentelemetry/exporter-trace-otlp-proto':
|
|
8
8
|
specifier: ^0.38.0
|
|
9
9
|
version: 0.38.0(@opentelemetry/api@1.4.1)
|
|
10
|
-
'@opentelemetry/instrumentation':
|
|
11
|
-
specifier: ^0.40.0
|
|
12
|
-
version: 0.40.0(@opentelemetry/api@1.4.1)
|
|
13
10
|
'@opentelemetry/resources':
|
|
14
11
|
specifier: ^1.12.0
|
|
15
12
|
version: 1.12.0(@opentelemetry/api@1.4.1)
|
|
@@ -282,22 +279,6 @@ packages:
|
|
|
282
279
|
'@opentelemetry/sdk-trace-base': 1.12.0(@opentelemetry/api@1.4.1)
|
|
283
280
|
dev: false
|
|
284
281
|
|
|
285
|
-
/@opentelemetry/instrumentation@0.40.0(@opentelemetry/api@1.4.1):
|
|
286
|
-
resolution: {integrity: sha512-23TzBKPflUS1uEq5SXymnQKQDSda35KvHjnvxdcDQGE+wg6hwDHgScUCWiBmZW4sxAaPcANfs+Wc9B7yDuyT6Q==}
|
|
287
|
-
engines: {node: '>=14'}
|
|
288
|
-
peerDependencies:
|
|
289
|
-
'@opentelemetry/api': ^1.3.0
|
|
290
|
-
dependencies:
|
|
291
|
-
'@opentelemetry/api': 1.4.1
|
|
292
|
-
'@types/shimmer': 1.0.2
|
|
293
|
-
import-in-the-middle: 1.3.5
|
|
294
|
-
require-in-the-middle: 7.1.1
|
|
295
|
-
semver: 7.5.0
|
|
296
|
-
shimmer: 1.2.1
|
|
297
|
-
transitivePeerDependencies:
|
|
298
|
-
- supports-color
|
|
299
|
-
dev: false
|
|
300
|
-
|
|
301
282
|
/@opentelemetry/otlp-exporter-base@0.38.0(@opentelemetry/api@1.4.1):
|
|
302
283
|
resolution: {integrity: sha512-VWQo7vUDyW/7/FT8RErAtM/29i/fllCc9xMtnK7kDuheAjJU68zrZ88bQOsLamHvOCU3KVpozjfTZVxZKQRYXw==}
|
|
303
284
|
engines: {node: '>=14'}
|
|
@@ -464,10 +445,6 @@ packages:
|
|
|
464
445
|
/@types/node@18.11.18:
|
|
465
446
|
resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==}
|
|
466
447
|
|
|
467
|
-
/@types/shimmer@1.0.2:
|
|
468
|
-
resolution: {integrity: sha512-dKkr1bTxbEsFlh2ARpKzcaAmsYixqt9UyCdoEZk8rHyE4iQYcDCyvSjDSf7JUWJHlJiTtbIoQjxKh6ViywqDAg==}
|
|
469
|
-
dev: false
|
|
470
|
-
|
|
471
448
|
/acorn-walk@8.2.0:
|
|
472
449
|
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
|
|
473
450
|
engines: {node: '>=0.4.0'}
|
|
@@ -568,6 +545,7 @@ packages:
|
|
|
568
545
|
optional: true
|
|
569
546
|
dependencies:
|
|
570
547
|
ms: 2.1.2
|
|
548
|
+
dev: true
|
|
571
549
|
|
|
572
550
|
/deep-eql@4.1.3:
|
|
573
551
|
resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
|
|
@@ -623,6 +601,7 @@ packages:
|
|
|
623
601
|
|
|
624
602
|
/function-bind@1.1.1:
|
|
625
603
|
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
|
|
604
|
+
dev: true
|
|
626
605
|
|
|
627
606
|
/get-func-name@2.0.0:
|
|
628
607
|
resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==}
|
|
@@ -633,6 +612,7 @@ packages:
|
|
|
633
612
|
engines: {node: '>= 0.4.0'}
|
|
634
613
|
dependencies:
|
|
635
614
|
function-bind: 1.1.1
|
|
615
|
+
dev: true
|
|
636
616
|
|
|
637
617
|
/header-case@2.0.4:
|
|
638
618
|
resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==}
|
|
@@ -641,16 +621,11 @@ packages:
|
|
|
641
621
|
tslib: 2.4.1
|
|
642
622
|
dev: false
|
|
643
623
|
|
|
644
|
-
/import-in-the-middle@1.3.5:
|
|
645
|
-
resolution: {integrity: sha512-yzHlBqi1EBFrkieAnSt8eTgO5oLSl+YJ7qaOpUH/PMqQOMZoQ/RmDlwnTLQrwYto+gHYjRG+i/IbsB1eDx32NQ==}
|
|
646
|
-
dependencies:
|
|
647
|
-
module-details-from-path: 1.0.3
|
|
648
|
-
dev: false
|
|
649
|
-
|
|
650
624
|
/is-core-module@2.11.0:
|
|
651
625
|
resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
|
|
652
626
|
dependencies:
|
|
653
627
|
has: 1.0.3
|
|
628
|
+
dev: true
|
|
654
629
|
|
|
655
630
|
/json-rpc-2.0@1.4.2:
|
|
656
631
|
resolution: {integrity: sha512-oqiMRhWN4Q+2ySitZR5GA9vtiNOK19GTDDad0yn8/T/ND+Ap81QP6+3UMl738H4bmRbCEwhQkkBruNqx7EXfUQ==}
|
|
@@ -712,12 +687,9 @@ packages:
|
|
|
712
687
|
ufo: 1.0.1
|
|
713
688
|
dev: true
|
|
714
689
|
|
|
715
|
-
/module-details-from-path@1.0.3:
|
|
716
|
-
resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==}
|
|
717
|
-
dev: false
|
|
718
|
-
|
|
719
690
|
/ms@2.1.2:
|
|
720
691
|
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
|
692
|
+
dev: true
|
|
721
693
|
|
|
722
694
|
/nanoid@3.3.4:
|
|
723
695
|
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
|
|
@@ -759,6 +731,7 @@ packages:
|
|
|
759
731
|
|
|
760
732
|
/path-parse@1.0.7:
|
|
761
733
|
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
|
734
|
+
dev: true
|
|
762
735
|
|
|
763
736
|
/pathe@0.2.0:
|
|
764
737
|
resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==}
|
|
@@ -896,17 +869,6 @@ packages:
|
|
|
896
869
|
long: 5.2.3
|
|
897
870
|
dev: false
|
|
898
871
|
|
|
899
|
-
/require-in-the-middle@7.1.1:
|
|
900
|
-
resolution: {integrity: sha512-OScOjQjrrjhAdFpQmnkE/qbIBGCRFhQB/YaJhcC3CPOlmhe7llnW46Ac1J5+EjcNXOTnDdpF96Erw/yedsGksQ==}
|
|
901
|
-
engines: {node: '>=8.6.0'}
|
|
902
|
-
dependencies:
|
|
903
|
-
debug: 4.3.4
|
|
904
|
-
module-details-from-path: 1.0.3
|
|
905
|
-
resolve: 1.22.1
|
|
906
|
-
transitivePeerDependencies:
|
|
907
|
-
- supports-color
|
|
908
|
-
dev: false
|
|
909
|
-
|
|
910
872
|
/resolve@1.22.1:
|
|
911
873
|
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
|
|
912
874
|
hasBin: true
|
|
@@ -914,6 +876,7 @@ packages:
|
|
|
914
876
|
is-core-module: 2.11.0
|
|
915
877
|
path-parse: 1.0.7
|
|
916
878
|
supports-preserve-symlinks-flag: 1.0.0
|
|
879
|
+
dev: true
|
|
917
880
|
|
|
918
881
|
/rollup@3.10.0:
|
|
919
882
|
resolution: {integrity: sha512-JmRYz44NjC1MjVF2VKxc0M1a97vn+cDxeqWmnwyAF4FvpjK8YFdHpaqvQB+3IxCvX05vJxKZkoMDU8TShhmJVA==}
|
|
@@ -939,10 +902,6 @@ packages:
|
|
|
939
902
|
upper-case-first: 2.0.2
|
|
940
903
|
dev: false
|
|
941
904
|
|
|
942
|
-
/shimmer@1.2.1:
|
|
943
|
-
resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==}
|
|
944
|
-
dev: false
|
|
945
|
-
|
|
946
905
|
/siginfo@2.0.0:
|
|
947
906
|
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
|
948
907
|
dev: true
|
|
@@ -989,6 +948,7 @@ packages:
|
|
|
989
948
|
/supports-preserve-symlinks-flag@1.0.0:
|
|
990
949
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
|
991
950
|
engines: {node: '>= 0.4'}
|
|
951
|
+
dev: true
|
|
992
952
|
|
|
993
953
|
/tinybench@2.3.1:
|
|
994
954
|
resolution: {integrity: sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==}
|
package/src/ModelAPI.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { useDatabase } = require("./database");
|
|
2
2
|
const { QueryBuilder } = require("./QueryBuilder");
|
|
3
3
|
const { QueryContext } = require("./QueryContext");
|
|
4
4
|
const { applyWhereConditions } = require("./applyWhereConditions");
|
|
@@ -56,7 +56,7 @@ class ModelAPI {
|
|
|
56
56
|
|
|
57
57
|
async create(values) {
|
|
58
58
|
const name = tracing.spanNameForModelAPI(this._modelName, "create");
|
|
59
|
-
const db =
|
|
59
|
+
const db = useDatabase();
|
|
60
60
|
|
|
61
61
|
return tracing.withSpan(name, async (span) => {
|
|
62
62
|
try {
|
|
@@ -83,7 +83,7 @@ class ModelAPI {
|
|
|
83
83
|
|
|
84
84
|
async findOne(where = {}) {
|
|
85
85
|
const name = tracing.spanNameForModelAPI(this._modelName, "findOne");
|
|
86
|
-
const db =
|
|
86
|
+
const db = useDatabase();
|
|
87
87
|
|
|
88
88
|
return tracing.withSpan(name, async (span) => {
|
|
89
89
|
let builder = db
|
|
@@ -108,7 +108,7 @@ class ModelAPI {
|
|
|
108
108
|
|
|
109
109
|
async findMany(params) {
|
|
110
110
|
const name = tracing.spanNameForModelAPI(this._modelName, "findMany");
|
|
111
|
-
const db =
|
|
111
|
+
const db = useDatabase();
|
|
112
112
|
const where = params?.where || {};
|
|
113
113
|
|
|
114
114
|
return tracing.withSpan(name, async (span) => {
|
|
@@ -164,7 +164,7 @@ class ModelAPI {
|
|
|
164
164
|
|
|
165
165
|
async update(where, values) {
|
|
166
166
|
const name = tracing.spanNameForModelAPI(this._modelName, "update");
|
|
167
|
-
const db =
|
|
167
|
+
const db = useDatabase();
|
|
168
168
|
|
|
169
169
|
return tracing.withSpan(name, async (span) => {
|
|
170
170
|
let builder = db.updateTable(this._tableName).returningAll();
|
|
@@ -189,7 +189,7 @@ class ModelAPI {
|
|
|
189
189
|
|
|
190
190
|
async delete(where) {
|
|
191
191
|
const name = tracing.spanNameForModelAPI(this._modelName, "delete");
|
|
192
|
-
const db =
|
|
192
|
+
const db = useDatabase();
|
|
193
193
|
|
|
194
194
|
return tracing.withSpan(name, async (span) => {
|
|
195
195
|
let builder = db.deleteFrom(this._tableName).returning(["id"]);
|
|
@@ -210,7 +210,7 @@ class ModelAPI {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
where(where) {
|
|
213
|
-
const db =
|
|
213
|
+
const db = useDatabase();
|
|
214
214
|
|
|
215
215
|
let builder = db
|
|
216
216
|
.selectFrom(this._tableName)
|
package/src/ModelAPI.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { test, expect, beforeEach } from "vitest";
|
|
2
|
-
const { ModelAPI
|
|
2
|
+
const { ModelAPI } = require("./ModelAPI");
|
|
3
3
|
const { sql } = require("kysely");
|
|
4
|
-
const {
|
|
4
|
+
const { useDatabase } = require("./database");
|
|
5
5
|
const KSUID = require("ksuid");
|
|
6
6
|
|
|
7
7
|
process.env.KEEL_DB_CONN_TYPE = "pg";
|
|
@@ -12,7 +12,7 @@ let postAPI;
|
|
|
12
12
|
let authorAPI;
|
|
13
13
|
|
|
14
14
|
beforeEach(async () => {
|
|
15
|
-
const db =
|
|
15
|
+
const db = useDatabase();
|
|
16
16
|
|
|
17
17
|
await sql`
|
|
18
18
|
DROP TABLE IF EXISTS post;
|
package/src/QueryBuilder.js
CHANGED
|
@@ -5,8 +5,8 @@ const {
|
|
|
5
5
|
applyOrderBy,
|
|
6
6
|
} = require("./applyAdditionalQueryConstraints");
|
|
7
7
|
const { applyJoins } = require("./applyJoins");
|
|
8
|
-
const { camelCaseObject
|
|
9
|
-
const {
|
|
8
|
+
const { camelCaseObject } = require("./casing");
|
|
9
|
+
const { useDatabase } = require("./database");
|
|
10
10
|
const { QueryContext } = require("./QueryContext");
|
|
11
11
|
const tracing = require("./tracing");
|
|
12
12
|
|
|
@@ -45,7 +45,7 @@ class QueryBuilder {
|
|
|
45
45
|
|
|
46
46
|
async findMany(params) {
|
|
47
47
|
const name = tracing.spanNameForModelAPI(this._modelName, "findMany");
|
|
48
|
-
const db =
|
|
48
|
+
const db = useDatabase();
|
|
49
49
|
|
|
50
50
|
return tracing.withSpan(name, async (span) => {
|
|
51
51
|
const context = new QueryContext([this._tableName], this._tableConfigMap);
|
package/src/database.js
CHANGED
|
@@ -2,56 +2,43 @@ const { Kysely, PostgresDialect } = require("kysely");
|
|
|
2
2
|
const { AsyncLocalStorage } = require("async_hooks");
|
|
3
3
|
const pg = require("pg");
|
|
4
4
|
const { PROTO_ACTION_TYPES } = require("./consts");
|
|
5
|
+
const { withSpan } = require("./tracing");
|
|
6
|
+
|
|
7
|
+
// withDatabase is responsible for setting the correct database client in our AsyncLocalStorage
|
|
8
|
+
// so that the the code in a custom function uses the correct client.
|
|
9
|
+
// For GET and LIST action types, no transaction is used, but for
|
|
10
|
+
// actions that mutate data such as CREATE, DELETE & UPDATE, all of the code inside
|
|
11
|
+
// the user's custom function is wrapped in a transaction so we can rollback
|
|
12
|
+
// the transaction if something goes wrong.
|
|
13
|
+
// withDatabase shouldn't be exposed in the public api of the sdk
|
|
14
|
+
async function withDatabase(db, actionType, cb) {
|
|
15
|
+
let requiresTransaction = true;
|
|
5
16
|
|
|
6
|
-
// withTransaction wraps the containing code with a transaction
|
|
7
|
-
// and sets the transaction in the AsyncLocalStorage so consumers further
|
|
8
|
-
// down the hierarchy can access the current transaction.
|
|
9
|
-
// For read type operations such as list & get, no transaction is used
|
|
10
|
-
async function withTransaction(db, actionType, cb) {
|
|
11
17
|
switch (actionType) {
|
|
12
18
|
case PROTO_ACTION_TYPES.GET:
|
|
13
19
|
case PROTO_ACTION_TYPES.LIST:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
});
|
|
17
|
-
default:
|
|
18
|
-
return db.transaction().execute(async (transaction) => {
|
|
19
|
-
return dbInstance.run(transaction, async () => {
|
|
20
|
-
return cb({ transaction });
|
|
21
|
-
});
|
|
22
|
-
});
|
|
20
|
+
requiresTransaction = false;
|
|
21
|
+
break;
|
|
23
22
|
}
|
|
24
|
-
}
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
return v;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function getDialect() {
|
|
35
|
-
const dbConnType = process.env["KEEL_DB_CONN_TYPE"];
|
|
36
|
-
switch (dbConnType) {
|
|
37
|
-
case "pg":
|
|
38
|
-
return new PostgresDialect({
|
|
39
|
-
pool: new pg.Pool({
|
|
40
|
-
connectionString: mustEnv("KEEL_DB_CONN"),
|
|
41
|
-
}),
|
|
24
|
+
if (requiresTransaction) {
|
|
25
|
+
return db.transaction().execute(async (transaction) => {
|
|
26
|
+
return dbInstance.run(transaction, async () => {
|
|
27
|
+
return cb({ transaction });
|
|
42
28
|
});
|
|
43
|
-
|
|
44
|
-
default:
|
|
45
|
-
throw Error("unexpected KEEL_DB_CONN_TYPE: " + dbConnType);
|
|
29
|
+
});
|
|
46
30
|
}
|
|
31
|
+
|
|
32
|
+
return dbInstance.run(db, async () => {
|
|
33
|
+
return cb({ transaction: db });
|
|
34
|
+
});
|
|
47
35
|
}
|
|
48
36
|
|
|
49
37
|
let db = null;
|
|
50
38
|
const dbInstance = new AsyncLocalStorage();
|
|
51
39
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
function getDatabase() {
|
|
40
|
+
// useDatabase will retrieve the database client set by withDatabase from the local storage
|
|
41
|
+
function useDatabase() {
|
|
55
42
|
let fromStore = dbInstance.getStore();
|
|
56
43
|
if (fromStore) {
|
|
57
44
|
return fromStore;
|
|
@@ -61,6 +48,9 @@ function getDatabase() {
|
|
|
61
48
|
return db;
|
|
62
49
|
}
|
|
63
50
|
|
|
51
|
+
// todo: ideally we wouldn't want to give you a fresh Kysely instance here if nothing
|
|
52
|
+
// has been found in the context, but the @teamkeel/testing package needs some restructuring
|
|
53
|
+
// to allow for the database client to be set in the store so that this method can throw an error at this line instead of returning a fresh kysely instance.
|
|
64
54
|
db = new Kysely({
|
|
65
55
|
dialect: getDialect(),
|
|
66
56
|
log(event) {
|
|
@@ -76,5 +66,66 @@ function getDatabase() {
|
|
|
76
66
|
return db;
|
|
77
67
|
}
|
|
78
68
|
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
function mustEnv(key) {
|
|
70
|
+
const v = process.env[key];
|
|
71
|
+
if (!v) {
|
|
72
|
+
throw new Error(`expected environment variable ${key} to be set`);
|
|
73
|
+
}
|
|
74
|
+
return v;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class InstrumentedPool extends pg.Pool {
|
|
78
|
+
async connect(...args) {
|
|
79
|
+
const _super = super.connect.bind(this);
|
|
80
|
+
return withSpan("Database Connect", function () {
|
|
81
|
+
return _super(...args);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const txStatements = {
|
|
87
|
+
begin: "Transaction Begin",
|
|
88
|
+
commit: "Transaction Commit",
|
|
89
|
+
rollback: "Transaction Rollback",
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
class InstrumentedClient extends pg.Client {
|
|
93
|
+
async query(...args) {
|
|
94
|
+
const _super = super.query.bind(this);
|
|
95
|
+
const sql = args[0];
|
|
96
|
+
|
|
97
|
+
let sqlAttribute = false;
|
|
98
|
+
|
|
99
|
+
let spanName = txStatements[sql.toLowerCase()];
|
|
100
|
+
if (!spanName) {
|
|
101
|
+
spanName = "Database Query";
|
|
102
|
+
sqlAttribute = true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return withSpan(spanName, function (span) {
|
|
106
|
+
if (sqlAttribute) {
|
|
107
|
+
span.setAttribute("sql", args[0]);
|
|
108
|
+
}
|
|
109
|
+
return _super(...args);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function getDialect() {
|
|
115
|
+
const dbConnType = process.env["KEEL_DB_CONN_TYPE"];
|
|
116
|
+
switch (dbConnType) {
|
|
117
|
+
case "pg":
|
|
118
|
+
return new PostgresDialect({
|
|
119
|
+
pool: new InstrumentedPool({
|
|
120
|
+
Client: InstrumentedClient,
|
|
121
|
+
connectionString: mustEnv("KEEL_DB_CONN"),
|
|
122
|
+
}),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
default:
|
|
126
|
+
throw Error("unexpected KEEL_DB_CONN_TYPE: " + dbConnType);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports.useDatabase = useDatabase;
|
|
131
|
+
module.exports.withDatabase = withDatabase;
|
package/src/handleRequest.js
CHANGED
|
@@ -3,7 +3,7 @@ const {
|
|
|
3
3
|
createJSONRPCSuccessResponse,
|
|
4
4
|
JSONRPCErrorCode,
|
|
5
5
|
} = require("json-rpc-2.0");
|
|
6
|
-
const {
|
|
6
|
+
const { useDatabase } = require("./database");
|
|
7
7
|
const { tryExecuteFunction } = require("./tryExecuteFunction");
|
|
8
8
|
const { errorToJSONRPCResponse, RuntimeErrors } = require("./errors");
|
|
9
9
|
const opentelemetry = require("@opentelemetry/api");
|
|
@@ -57,7 +57,7 @@ async function handleRequest(request, config) {
|
|
|
57
57
|
? true
|
|
58
58
|
: null;
|
|
59
59
|
|
|
60
|
-
const db =
|
|
60
|
+
const db = useDatabase();
|
|
61
61
|
const customFunction = functions[request.method];
|
|
62
62
|
|
|
63
63
|
const result = await tryExecuteFunction(
|
|
@@ -3,7 +3,7 @@ import { sql } from "kysely";
|
|
|
3
3
|
import { handleRequest, RuntimeErrors } from "./handleRequest";
|
|
4
4
|
import { test, expect, beforeEach, describe } from "vitest";
|
|
5
5
|
import { ModelAPI } from "./ModelAPI";
|
|
6
|
-
import {
|
|
6
|
+
import { useDatabase } from "./database";
|
|
7
7
|
const { Permissions } = require("./permissions");
|
|
8
8
|
import { PROTO_ACTION_TYPES } from "./consts";
|
|
9
9
|
import KSUID from "ksuid";
|
|
@@ -188,7 +188,7 @@ describe("ModelAPI error handling", () => {
|
|
|
188
188
|
process.env.KEEL_DB_CONN_TYPE = "pg";
|
|
189
189
|
process.env.KEEL_DB_CONN = `postgresql://postgres:postgres@localhost:5432/functions-runtime`;
|
|
190
190
|
|
|
191
|
-
db =
|
|
191
|
+
db = useDatabase();
|
|
192
192
|
|
|
193
193
|
await sql`
|
|
194
194
|
DROP TABLE IF EXISTS post;
|
package/src/index.js
CHANGED
|
@@ -2,7 +2,7 @@ const { ModelAPI } = require("./ModelAPI");
|
|
|
2
2
|
const { RequestHeaders } = require("./RequestHeaders");
|
|
3
3
|
const { handleRequest } = require("./handleRequest");
|
|
4
4
|
const KSUID = require("ksuid");
|
|
5
|
-
const {
|
|
5
|
+
const { useDatabase } = require("./database");
|
|
6
6
|
const {
|
|
7
7
|
Permissions,
|
|
8
8
|
PERMISSION_STATE,
|
|
@@ -14,7 +14,7 @@ module.exports = {
|
|
|
14
14
|
ModelAPI,
|
|
15
15
|
RequestHeaders,
|
|
16
16
|
handleRequest,
|
|
17
|
-
|
|
17
|
+
useDatabase,
|
|
18
18
|
Permissions,
|
|
19
19
|
PERMISSION_STATE,
|
|
20
20
|
checkBuiltInPermissions,
|
package/src/permissions.test.js
CHANGED
|
@@ -6,7 +6,7 @@ const {
|
|
|
6
6
|
checkBuiltInPermissions,
|
|
7
7
|
} = require("./permissions");
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { useDatabase } from "./database";
|
|
10
10
|
|
|
11
11
|
import { beforeEach, describe, expect, test } from "vitest";
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ process.env.KEEL_DB_CONN = `postgresql://postgres:postgres@localhost:5432/functi
|
|
|
15
15
|
|
|
16
16
|
let permissions;
|
|
17
17
|
let ctx = {};
|
|
18
|
-
let db =
|
|
18
|
+
let db = useDatabase();
|
|
19
19
|
|
|
20
20
|
describe("explicit", () => {
|
|
21
21
|
beforeEach(() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { withDatabase } = require("./database");
|
|
2
2
|
const {
|
|
3
3
|
withPermissions,
|
|
4
4
|
PERMISSION_STATE,
|
|
@@ -16,7 +16,7 @@ function tryExecuteFunction(
|
|
|
16
16
|
const actionType = actionTypes[request.method];
|
|
17
17
|
|
|
18
18
|
return withPermissions(permitted, async ({ getPermissionState }) => {
|
|
19
|
-
return
|
|
19
|
+
return withDatabase(db, actionType, async ({ transaction }) => {
|
|
20
20
|
const fnResult = await cb();
|
|
21
21
|
|
|
22
22
|
// api.permissions maintains an internal state of whether the current operation has been *explicitly* permitted/denied by the user in the course of their custom function, or if execution has already been permitted by a role based permission (evaluated in the main runtime).
|