@teamkeel/functions-runtime 0.373.1 → 0.374.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 +2 -2
- package/src/ModelAPI.js +109 -19
- package/src/tracing.js +9 -0
- package/src/tracing.test.js +4 -1
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teamkeel/functions-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.374.0",
|
|
4
4
|
"description": "Internal package used by @teamkeel/sdk",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
7
|
+
"test": "vitest run --reporter verbose --threads false",
|
|
8
8
|
"format": "npx prettier --write src/**/*.js"
|
|
9
9
|
},
|
|
10
10
|
"keywords": [],
|
package/src/ModelAPI.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { sql } = require("kysely");
|
|
1
2
|
const { useDatabase } = require("./database");
|
|
2
3
|
const { QueryBuilder } = require("./QueryBuilder");
|
|
3
4
|
const { QueryContext } = require("./QueryContext");
|
|
@@ -50,26 +51,10 @@ class ModelAPI {
|
|
|
50
51
|
|
|
51
52
|
async create(values) {
|
|
52
53
|
const name = tracing.spanNameForModelAPI(this._modelName, "create");
|
|
53
|
-
const db = useDatabase();
|
|
54
54
|
|
|
55
|
-
return tracing.withSpan(name,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.insertInto(this._tableName)
|
|
59
|
-
.values(
|
|
60
|
-
snakeCaseObject({
|
|
61
|
-
...values,
|
|
62
|
-
})
|
|
63
|
-
)
|
|
64
|
-
.returningAll();
|
|
65
|
-
|
|
66
|
-
span.setAttribute("sql", query.compile().sql);
|
|
67
|
-
const row = await query.executeTakeFirstOrThrow();
|
|
68
|
-
|
|
69
|
-
return camelCaseObject(row);
|
|
70
|
-
} catch (e) {
|
|
71
|
-
throw new DatabaseError(e);
|
|
72
|
-
}
|
|
55
|
+
return tracing.withSpan(name, () => {
|
|
56
|
+
const db = useDatabase();
|
|
57
|
+
return create(db, this._tableName, this._tableConfigMap, values);
|
|
73
58
|
});
|
|
74
59
|
}
|
|
75
60
|
|
|
@@ -218,6 +203,111 @@ class ModelAPI {
|
|
|
218
203
|
}
|
|
219
204
|
}
|
|
220
205
|
|
|
206
|
+
async function create(conn, tableName, tableConfigs, values) {
|
|
207
|
+
try {
|
|
208
|
+
let query = conn.insertInto(tableName);
|
|
209
|
+
|
|
210
|
+
const keys = values ? Object.keys(values) : [];
|
|
211
|
+
const tableConfig = tableConfigs[tableName] || {};
|
|
212
|
+
const hasManyRecords = [];
|
|
213
|
+
|
|
214
|
+
if (keys.length === 0) {
|
|
215
|
+
// See https://github.com/kysely-org/kysely/issues/685#issuecomment-1711240534
|
|
216
|
+
query = query.expression(sql`default values`);
|
|
217
|
+
} else {
|
|
218
|
+
const row = {};
|
|
219
|
+
for (const key of keys) {
|
|
220
|
+
const value = values[key];
|
|
221
|
+
const columnConfig = tableConfig[key];
|
|
222
|
+
|
|
223
|
+
if (!columnConfig) {
|
|
224
|
+
row[key] = value;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
switch (columnConfig.relationshipType) {
|
|
229
|
+
case "belongsTo":
|
|
230
|
+
if (!isPlainObject(value)) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
`non-object provided for field ${key} of ${tableName}`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (isReferencingExistingRecord(value)) {
|
|
237
|
+
row[columnConfig.foreignKey] = value.id;
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const created = await create(
|
|
242
|
+
conn,
|
|
243
|
+
columnConfig.referencesTable,
|
|
244
|
+
tableConfigs,
|
|
245
|
+
value
|
|
246
|
+
);
|
|
247
|
+
row[columnConfig.foreignKey] = created.id;
|
|
248
|
+
break;
|
|
249
|
+
|
|
250
|
+
case "hasMany":
|
|
251
|
+
if (!Array.isArray(value)) {
|
|
252
|
+
throw new Error(
|
|
253
|
+
`non-array provided for has-many field ${key} of ${tableName}`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
for (const v of value) {
|
|
257
|
+
hasManyRecords.push({
|
|
258
|
+
key,
|
|
259
|
+
value: v,
|
|
260
|
+
columnConfig,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
default:
|
|
265
|
+
throw new Error(
|
|
266
|
+
`unsupported relationship type - ${tableName}.${key} (${columnConfig.relationshipType})`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
query = query.values(row);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const created = await query.returningAll().executeTakeFirstOrThrow();
|
|
275
|
+
|
|
276
|
+
await Promise.all(
|
|
277
|
+
hasManyRecords.map(async ({ key, value, columnConfig }) => {
|
|
278
|
+
if (!isPlainObject(value)) {
|
|
279
|
+
throw new Error(
|
|
280
|
+
`non-object provided for field ${key} of ${tableName}`
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (isReferencingExistingRecord(value)) {
|
|
285
|
+
throw new Error(
|
|
286
|
+
`nested update as part of create not supported for ${key} of ${tableConfig}`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
await create(conn, columnConfig.referencesTable, tableConfigs, {
|
|
291
|
+
...value,
|
|
292
|
+
[columnConfig.foreignKey]: created.id,
|
|
293
|
+
});
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
return created;
|
|
298
|
+
} catch (e) {
|
|
299
|
+
throw new DatabaseError(e);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function isPlainObject(obj) {
|
|
304
|
+
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function isReferencingExistingRecord(value) {
|
|
308
|
+
return Object.keys(value).length === 1 && value.id;
|
|
309
|
+
}
|
|
310
|
+
|
|
221
311
|
module.exports = {
|
|
222
312
|
ModelAPI,
|
|
223
313
|
DatabaseError,
|
package/src/tracing.js
CHANGED
|
@@ -119,6 +119,14 @@ function init() {
|
|
|
119
119
|
patchConsoleLog();
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
async function forceFlush() {
|
|
123
|
+
// The "delegate" is the actual provider set by the functions-runtime package
|
|
124
|
+
const provider = opentelemetry.trace.getTracerProvider().getDelegate();
|
|
125
|
+
if (provider && provider.forceFlush) {
|
|
126
|
+
await provider.forceFlush();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
122
130
|
function getTracer() {
|
|
123
131
|
return opentelemetry.trace.getTracer("functions");
|
|
124
132
|
}
|
|
@@ -131,5 +139,6 @@ module.exports = {
|
|
|
131
139
|
getTracer,
|
|
132
140
|
withSpan,
|
|
133
141
|
init,
|
|
142
|
+
forceFlush,
|
|
134
143
|
spanNameForModelAPI,
|
|
135
144
|
};
|
package/src/tracing.test.js
CHANGED
|
@@ -33,7 +33,10 @@ test("withSpan span time", async () => {
|
|
|
33
33
|
|
|
34
34
|
expect(spanEvents.map((e) => e.event)).toEqual(["onStart", "onEnd"]);
|
|
35
35
|
const spanDuration = spanEvents.pop().span._duration.pop();
|
|
36
|
-
|
|
36
|
+
|
|
37
|
+
// The '- 1' here is because sometimes the test fails due to the span duration
|
|
38
|
+
// being something like 99.87ms. As long as it's at least 99ms we're happy
|
|
39
|
+
const waitTimeNanos = (waitTimeMillis - 1) * 1000 * 1000;
|
|
37
40
|
expect(spanDuration).toBeGreaterThan(waitTimeNanos);
|
|
38
41
|
});
|
|
39
42
|
|