@balena/pinejs 15.0.0-true-boolean-7896b116c446d891d7a0d5e4085c02a13bc9c725 → 15.0.1-build-migrations-clarify-marking-sbvr-optional-d6d0ded8eccc6eadb2492f4697918cf0afd00215-1
Sign up to get free protection for your applications and to get access to all the features.
- package/.dockerignore +4 -0
- package/.github/workflows/flowzone.yml +21 -0
- package/.husky/pre-commit +4 -0
- package/.pinejs-cache.json +1 -0
- package/.resinci.yml +1 -0
- package/.versionbot/CHANGELOG.yml +9678 -2002
- package/CHANGELOG.md +2976 -2
- package/Dockerfile +14 -0
- package/Gruntfile.ts +3 -6
- package/README.md +10 -1
- package/VERSION +1 -0
- package/build/browser.ts +1 -1
- package/build/config.ts +0 -1
- package/docker-compose.npm-test.yml +11 -0
- package/docs/AdvancedUsage.md +77 -63
- package/docs/GettingStarted.md +90 -41
- package/docs/Migrations.md +102 -1
- package/docs/ProjectConfig.md +12 -21
- package/docs/Testing.md +7 -0
- package/out/bin/abstract-sql-compiler.js +17 -17
- package/out/bin/abstract-sql-compiler.js.map +1 -1
- package/out/bin/odata-compiler.js +23 -20
- package/out/bin/odata-compiler.js.map +1 -1
- package/out/bin/sbvr-compiler.js +22 -22
- package/out/bin/sbvr-compiler.js.map +1 -1
- package/out/bin/utils.d.ts +2 -2
- package/out/bin/utils.js +3 -3
- package/out/bin/utils.js.map +1 -1
- package/out/config-loader/config-loader.d.ts +9 -8
- package/out/config-loader/config-loader.js +135 -78
- package/out/config-loader/config-loader.js.map +1 -1
- package/out/config-loader/env.d.ts +41 -16
- package/out/config-loader/env.js +46 -2
- package/out/config-loader/env.js.map +1 -1
- package/out/data-server/sbvr-server.d.ts +2 -19
- package/out/data-server/sbvr-server.js +44 -38
- package/out/data-server/sbvr-server.js.map +1 -1
- package/out/database-layer/db.d.ts +32 -14
- package/out/database-layer/db.js +120 -41
- package/out/database-layer/db.js.map +1 -1
- package/out/express-emulator/express.js +10 -11
- package/out/express-emulator/express.js.map +1 -1
- package/out/http-transactions/transactions.d.ts +2 -18
- package/out/http-transactions/transactions.js +29 -21
- package/out/http-transactions/transactions.js.map +1 -1
- package/out/migrator/async.d.ts +7 -0
- package/out/migrator/async.js +168 -0
- package/out/migrator/async.js.map +1 -0
- package/out/migrator/migrations.sbvr +43 -0
- package/out/migrator/sync.d.ts +9 -0
- package/out/migrator/sync.js +106 -0
- package/out/migrator/sync.js.map +1 -0
- package/out/migrator/utils.d.ts +78 -0
- package/out/migrator/utils.js +283 -0
- package/out/migrator/utils.js.map +1 -0
- package/out/odata-metadata/odata-metadata-generator.js +10 -13
- package/out/odata-metadata/odata-metadata-generator.js.map +1 -1
- package/out/passport-pinejs/passport-pinejs.d.ts +1 -1
- package/out/passport-pinejs/passport-pinejs.js +8 -7
- package/out/passport-pinejs/passport-pinejs.js.map +1 -1
- package/out/pinejs-session-store/pinejs-session-store.d.ts +1 -1
- package/out/pinejs-session-store/pinejs-session-store.js +20 -6
- package/out/pinejs-session-store/pinejs-session-store.js.map +1 -1
- package/out/sbvr-api/abstract-sql.d.ts +3 -2
- package/out/sbvr-api/abstract-sql.js +9 -9
- package/out/sbvr-api/abstract-sql.js.map +1 -1
- package/out/sbvr-api/cached-compile.js +1 -1
- package/out/sbvr-api/cached-compile.js.map +1 -1
- package/out/sbvr-api/common-types.d.ts +6 -5
- package/out/sbvr-api/control-flow.d.ts +8 -1
- package/out/sbvr-api/control-flow.js +36 -9
- package/out/sbvr-api/control-flow.js.map +1 -1
- package/out/sbvr-api/errors.d.ts +47 -40
- package/out/sbvr-api/errors.js +78 -77
- package/out/sbvr-api/errors.js.map +1 -1
- package/out/sbvr-api/express-extension.d.ts +4 -0
- package/out/sbvr-api/hooks.d.ts +16 -15
- package/out/sbvr-api/hooks.js +74 -48
- package/out/sbvr-api/hooks.js.map +1 -1
- package/out/sbvr-api/odata-response.d.ts +2 -2
- package/out/sbvr-api/odata-response.js +28 -30
- package/out/sbvr-api/odata-response.js.map +1 -1
- package/out/sbvr-api/permissions.d.ts +17 -16
- package/out/sbvr-api/permissions.js +369 -304
- package/out/sbvr-api/permissions.js.map +1 -1
- package/out/sbvr-api/sbvr-utils.d.ts +33 -15
- package/out/sbvr-api/sbvr-utils.js +397 -235
- package/out/sbvr-api/sbvr-utils.js.map +1 -1
- package/out/sbvr-api/translations.d.ts +6 -0
- package/out/sbvr-api/translations.js +150 -0
- package/out/sbvr-api/translations.js.map +1 -0
- package/out/sbvr-api/uri-parser.d.ts +23 -17
- package/out/sbvr-api/uri-parser.js +33 -27
- package/out/sbvr-api/uri-parser.js.map +1 -1
- package/out/sbvr-api/user.sbvr +2 -0
- package/out/server-glue/module.d.ts +6 -6
- package/out/server-glue/module.js +4 -2
- package/out/server-glue/module.js.map +1 -1
- package/out/server-glue/server.js +5 -5
- package/out/server-glue/server.js.map +1 -1
- package/package.json +89 -73
- package/pinejs.png +0 -0
- package/repo.yml +9 -9
- package/src/bin/abstract-sql-compiler.ts +5 -7
- package/src/bin/odata-compiler.ts +11 -13
- package/src/bin/sbvr-compiler.ts +11 -17
- package/src/bin/utils.ts +3 -5
- package/src/config-loader/config-loader.ts +167 -53
- package/src/config-loader/env.ts +106 -6
- package/src/data-server/sbvr-server.js +44 -38
- package/src/database-layer/db.ts +205 -64
- package/src/express-emulator/express.js +10 -11
- package/src/http-transactions/transactions.js +29 -21
- package/src/migrator/async.ts +323 -0
- package/src/migrator/migrations.sbvr +43 -0
- package/src/migrator/sync.ts +152 -0
- package/src/migrator/utils.ts +458 -0
- package/src/odata-metadata/odata-metadata-generator.ts +12 -15
- package/src/passport-pinejs/passport-pinejs.ts +9 -7
- package/src/pinejs-session-store/pinejs-session-store.ts +15 -1
- package/src/sbvr-api/abstract-sql.ts +17 -14
- package/src/sbvr-api/common-types.ts +2 -1
- package/src/sbvr-api/control-flow.ts +45 -11
- package/src/sbvr-api/errors.ts +82 -77
- package/src/sbvr-api/express-extension.ts +6 -1
- package/src/sbvr-api/hooks.ts +123 -50
- package/src/sbvr-api/odata-response.ts +23 -28
- package/src/sbvr-api/permissions.ts +548 -415
- package/src/sbvr-api/sbvr-utils.ts +581 -259
- package/src/sbvr-api/translations.ts +248 -0
- package/src/sbvr-api/uri-parser.ts +63 -49
- package/src/sbvr-api/user.sbvr +2 -0
- package/src/server-glue/module.ts +16 -10
- package/src/server-glue/server.ts +5 -5
- package/tsconfig.dev.json +1 -0
- package/tsconfig.json +1 -2
- package/typings/lf-to-abstract-sql.d.ts +6 -9
- package/typings/memoizee.d.ts +1 -1
- package/.github/CODEOWNERS +0 -1
- package/circle.yml +0 -37
- package/docs/todo.txt +0 -22
- package/out/migrator/migrator.d.ts +0 -20
- package/out/migrator/migrator.js +0 -188
- package/out/migrator/migrator.js.map +0 -1
- package/src/migrator/migrator.ts +0 -286
package/src/sbvr-api/hooks.ts
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
import type { OptionalField, Resolvable } from './common-types';
|
2
2
|
import type { Tx } from '../database-layer/db';
|
3
|
-
import type { ODataRequest } from './uri-parser';
|
3
|
+
import type { ODataRequest, ParsedODataRequest } from './uri-parser';
|
4
4
|
import type { AnyObject } from 'pinejs-client-core';
|
5
5
|
import type { TypedError } from 'typed-error';
|
6
6
|
import type { SupportedMethod } from '@balena/odata-to-abstract-sql';
|
7
7
|
|
8
|
-
import * as Bluebird from 'bluebird';
|
9
8
|
import * as _ from 'lodash';
|
10
9
|
import { settleMapSeries } from './control-flow';
|
11
10
|
import * as memoize from 'memoizee';
|
@@ -16,6 +15,7 @@ import {
|
|
16
15
|
resolveSynonym,
|
17
16
|
getAbstractSqlModel,
|
18
17
|
api,
|
18
|
+
Response,
|
19
19
|
} from './sbvr-utils';
|
20
20
|
|
21
21
|
export interface HookReq {
|
@@ -34,7 +34,7 @@ export interface HookArgs {
|
|
34
34
|
req: HookReq;
|
35
35
|
request: ODataRequest;
|
36
36
|
api: PinejsClient;
|
37
|
-
tx?: Tx;
|
37
|
+
tx?: Tx | undefined;
|
38
38
|
}
|
39
39
|
export type HookResponse = PromiseLike<any> | null | void;
|
40
40
|
|
@@ -42,14 +42,18 @@ export interface Hooks {
|
|
42
42
|
PREPARSE?: (options: Omit<HookArgs, 'request' | 'api'>) => HookResponse;
|
43
43
|
POSTPARSE?: (options: HookArgs) => HookResponse;
|
44
44
|
PRERUN?: (options: HookArgs & { tx: Tx }) => HookResponse;
|
45
|
+
/** These are run in reverse translation order from newest to oldest */
|
45
46
|
POSTRUN?: (options: HookArgs & { tx: Tx; result: any }) => HookResponse;
|
47
|
+
/** These are run in reverse translation order from newest to oldest */
|
46
48
|
PRERESPOND?: (
|
47
49
|
options: HookArgs & {
|
48
50
|
tx: Tx;
|
49
51
|
result: any;
|
50
|
-
|
52
|
+
/** This can be mutated to modify the response sent to the client */
|
53
|
+
response: Response;
|
51
54
|
},
|
52
55
|
) => HookResponse;
|
56
|
+
/** These are run in reverse translation order from newest to oldest */
|
53
57
|
'POSTRUN-ERROR'?: (
|
54
58
|
options: HookArgs & { error: TypedError | any },
|
55
59
|
) => HookResponse;
|
@@ -97,7 +101,13 @@ class SideEffectHook<T extends HookFn> extends Hook<T> {
|
|
97
101
|
|
98
102
|
public registerRollback(fn: RollbackAction): void {
|
99
103
|
if (this.rolledBack) {
|
100
|
-
|
104
|
+
(async () => {
|
105
|
+
try {
|
106
|
+
await fn();
|
107
|
+
} catch {
|
108
|
+
// Ignore any errors in the rollback callback
|
109
|
+
}
|
110
|
+
})();
|
101
111
|
} else {
|
102
112
|
this.rollbackFns.push(fn);
|
103
113
|
}
|
@@ -117,15 +127,21 @@ class SideEffectHook<T extends HookFn> extends Hook<T> {
|
|
117
127
|
|
118
128
|
// The execution order of rollback actions is unspecified
|
119
129
|
export const rollbackRequestHooks = <T extends InstantiatedHooks>(
|
120
|
-
hooks: T | undefined,
|
130
|
+
hooksList: Array<[modelName: string, hooks: T]> | undefined,
|
121
131
|
): void => {
|
122
|
-
if (
|
132
|
+
if (hooksList == null) {
|
123
133
|
return;
|
124
134
|
}
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
135
|
+
const sideEffectHooks = hooksList
|
136
|
+
.flatMap(([, v]): Array<Hook<HookFn>> => Object.values(v).flat())
|
137
|
+
.filter(
|
138
|
+
(hook): hook is SideEffectHook<HookFn> => hook instanceof SideEffectHook,
|
139
|
+
);
|
140
|
+
if (sideEffectHooks.length === 0) {
|
141
|
+
return;
|
142
|
+
}
|
143
|
+
settleMapSeries(sideEffectHooks, async (hook) => {
|
144
|
+
await hook.rollback();
|
129
145
|
});
|
130
146
|
};
|
131
147
|
|
@@ -162,38 +178,65 @@ const getResourceHooks = (vocabHooks: VocabHooks, resourceName?: string) => {
|
|
162
178
|
const getVocabHooks = (
|
163
179
|
methodHooks: MethodHooks,
|
164
180
|
vocabulary: string,
|
165
|
-
resourceName
|
181
|
+
resourceName: string | undefined,
|
182
|
+
includeAllVocab: boolean,
|
166
183
|
) => {
|
167
184
|
if (methodHooks == null) {
|
168
185
|
return {};
|
169
186
|
}
|
187
|
+
const vocabHooks = getResourceHooks(methodHooks[vocabulary], resourceName);
|
188
|
+
if (!includeAllVocab) {
|
189
|
+
// Do not include `vocabulary='all'` hooks, useful for translated vocabularies
|
190
|
+
return vocabHooks;
|
191
|
+
}
|
170
192
|
return mergeHooks(
|
171
|
-
|
193
|
+
vocabHooks,
|
172
194
|
getResourceHooks(methodHooks['all'], resourceName),
|
173
195
|
);
|
174
196
|
};
|
175
197
|
const getMethodHooks = memoize(
|
176
|
-
(
|
198
|
+
(
|
199
|
+
method: SupportedMethod,
|
200
|
+
vocabulary: string,
|
201
|
+
resourceName: string | undefined,
|
202
|
+
includeAllVocab: boolean,
|
203
|
+
) =>
|
177
204
|
mergeHooks(
|
178
|
-
getVocabHooks(
|
179
|
-
|
205
|
+
getVocabHooks(
|
206
|
+
apiHooks[method],
|
207
|
+
vocabulary,
|
208
|
+
resourceName,
|
209
|
+
includeAllVocab,
|
210
|
+
),
|
211
|
+
getVocabHooks(apiHooks['all'], vocabulary, resourceName, includeAllVocab),
|
180
212
|
),
|
181
213
|
{ primitive: true },
|
182
214
|
);
|
183
215
|
export const getHooks = (
|
184
216
|
request: Pick<
|
185
|
-
OptionalField<
|
217
|
+
OptionalField<ParsedODataRequest, 'resourceName'>,
|
186
218
|
'resourceName' | 'method' | 'vocabulary'
|
187
219
|
>,
|
220
|
+
includeAllVocab: boolean,
|
188
221
|
): InstantiatedHooks => {
|
189
222
|
let { resourceName } = request;
|
190
223
|
if (resourceName != null) {
|
191
224
|
resourceName = resolveSynonym(
|
192
|
-
request as Pick<
|
193
|
-
|
225
|
+
request as Pick<
|
226
|
+
ParsedODataRequest,
|
227
|
+
'resourceName' | 'method' | 'vocabulary'
|
228
|
+
>,
|
229
|
+
)
|
230
|
+
// Remove version suffixes
|
231
|
+
.replace(/\$.*$/, '');
|
194
232
|
}
|
195
233
|
return instantiateHooks(
|
196
|
-
getMethodHooks(
|
234
|
+
getMethodHooks(
|
235
|
+
request.method,
|
236
|
+
request.vocabulary,
|
237
|
+
resourceName,
|
238
|
+
includeAllVocab,
|
239
|
+
),
|
197
240
|
);
|
198
241
|
};
|
199
242
|
getHooks.clear = () => getMethodHooks.clear();
|
@@ -325,54 +368,84 @@ export const addPureHook = (
|
|
325
368
|
});
|
326
369
|
};
|
327
370
|
|
328
|
-
const defineApi = (args: HookArgs) => {
|
329
|
-
const {
|
330
|
-
const { vocabulary } = request;
|
371
|
+
const defineApi = (modelName: string, args: HookArgs) => {
|
372
|
+
const { req, tx } = args;
|
331
373
|
Object.defineProperty(args, 'api', {
|
332
374
|
get: _.once(() =>
|
333
|
-
api[
|
375
|
+
api[modelName].clone({
|
334
376
|
passthrough: { req, tx },
|
335
377
|
}),
|
336
378
|
),
|
337
379
|
});
|
338
380
|
};
|
339
381
|
|
382
|
+
type RunHookArgs<T extends keyof Hooks> = Omit<
|
383
|
+
Parameters<NonNullable<Hooks[T]>>[0],
|
384
|
+
'api'
|
385
|
+
>;
|
386
|
+
const getReadOnlyArgs = <T extends keyof Hooks>(
|
387
|
+
modelName: string,
|
388
|
+
args: RunHookArgs<T>,
|
389
|
+
): RunHookArgs<T> => {
|
390
|
+
if (args.tx == null || args.tx.isReadOnly()) {
|
391
|
+
// If we don't have a tx then read-only/writable is irrelevant
|
392
|
+
return args;
|
393
|
+
}
|
394
|
+
let readOnlyArgs: typeof args;
|
395
|
+
readOnlyArgs = { ...args, tx: args.tx.asReadOnly() };
|
396
|
+
if ((args as HookArgs).request != null) {
|
397
|
+
defineApi(modelName, readOnlyArgs as HookArgs);
|
398
|
+
}
|
399
|
+
return readOnlyArgs;
|
400
|
+
};
|
401
|
+
|
340
402
|
export const runHooks = async <T extends keyof Hooks>(
|
341
403
|
hookName: T,
|
342
|
-
|
343
|
-
|
404
|
+
/**
|
405
|
+
* A list of modelName/hooks to run in order, which will be reversed for hooks after the "RUN" stage,
|
406
|
+
* ie POSTRUN/PRERESPOND/POSTRUN-ERROR
|
407
|
+
*/
|
408
|
+
hooksList: Array<[modelName: string, hooks: InstantiatedHooks]> | undefined,
|
409
|
+
args: RunHookArgs<T>,
|
344
410
|
) => {
|
345
411
|
if (hooksList == null) {
|
346
412
|
return;
|
347
413
|
}
|
348
|
-
const hooks = hooksList
|
349
|
-
|
414
|
+
const hooks = hooksList
|
415
|
+
.map(([modelName, $hooks]): [string, InstantiatedHooks[T] | undefined] => [
|
416
|
+
modelName,
|
417
|
+
$hooks[hookName],
|
418
|
+
])
|
419
|
+
.filter(
|
420
|
+
(v): v is [string, InstantiatedHooks[T]] =>
|
421
|
+
v[1] != null && v[1].length > 0,
|
422
|
+
);
|
423
|
+
if (hooks.length === 0) {
|
350
424
|
return;
|
351
425
|
}
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
// If we don't have a tx then read-only/writable is irrelevant
|
358
|
-
readOnlyArgs = args;
|
426
|
+
if (['POSTRUN', 'PRERESPOND', 'POSTRUN-ERROR'].includes(hookName)) {
|
427
|
+
// Any hooks after we "run" the query are executed in reverse order from newest to oldest
|
428
|
+
// as they'll be translating the query results from "latest" backwards to the model that
|
429
|
+
// was actually requested
|
430
|
+
hooks.reverse();
|
359
431
|
}
|
360
432
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
defineApi(
|
433
|
+
for (const [modelName, modelHooks] of hooks) {
|
434
|
+
const modelArgs = { ...args };
|
435
|
+
let modelReadOnlyArgs: typeof modelArgs;
|
436
|
+
if ((args as HookArgs).request != null) {
|
437
|
+
defineApi(modelName, modelArgs as HookArgs);
|
366
438
|
}
|
367
|
-
}
|
368
439
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
440
|
+
await Promise.all(
|
441
|
+
(modelHooks as Array<Hook<HookFn>>).map(async (hook) => {
|
442
|
+
if (hook.readOnlyTx) {
|
443
|
+
modelReadOnlyArgs ??= getReadOnlyArgs(modelName, modelArgs);
|
444
|
+
await hook.run(modelReadOnlyArgs);
|
445
|
+
} else {
|
446
|
+
await hook.run(modelArgs);
|
447
|
+
}
|
448
|
+
}),
|
449
|
+
);
|
450
|
+
}
|
378
451
|
};
|
@@ -1,7 +1,7 @@
|
|
1
1
|
declare module '@balena/abstract-sql-compiler' {
|
2
2
|
interface AbstractSqlTable {
|
3
3
|
fetchProcessingFields?: {
|
4
|
-
[field: string]: NonNullable<
|
4
|
+
[field: string]: NonNullable<SbvrType['fetchProcessing']>;
|
5
5
|
};
|
6
6
|
localFields?: {
|
7
7
|
[odataName: string]: true;
|
@@ -16,7 +16,7 @@ import type {
|
|
16
16
|
import type { Result, Row } from '../database-layer/db';
|
17
17
|
|
18
18
|
import { sqlNameToODataName } from '@balena/odata-to-abstract-sql';
|
19
|
-
import
|
19
|
+
import sbvrTypes, { SbvrType } from '@balena/sbvr-types';
|
20
20
|
import * as _ from 'lodash';
|
21
21
|
import { resolveNavigationResource, resolveSynonym } from './sbvr-utils';
|
22
22
|
|
@@ -36,20 +36,20 @@ const checkForExpansion = async (
|
|
36
36
|
if (typeof field === 'string') {
|
37
37
|
try {
|
38
38
|
field = JSON.parse(field);
|
39
|
-
} catch
|
39
|
+
} catch {
|
40
40
|
// If we can't JSON.parse the field then we use it directly.
|
41
41
|
}
|
42
42
|
}
|
43
43
|
|
44
|
+
const mappingResourceName = resolveNavigationResource(
|
45
|
+
{
|
46
|
+
abstractSqlModel,
|
47
|
+
vocabulary: vocab,
|
48
|
+
resourceName: parentResourceName,
|
49
|
+
},
|
50
|
+
fieldName,
|
51
|
+
);
|
44
52
|
if (Array.isArray(field)) {
|
45
|
-
const mappingResourceName = resolveNavigationResource(
|
46
|
-
{
|
47
|
-
abstractSqlModel,
|
48
|
-
vocabulary: vocab,
|
49
|
-
resourceName: parentResourceName,
|
50
|
-
},
|
51
|
-
fieldName,
|
52
|
-
);
|
53
53
|
const expandedField = await process(
|
54
54
|
vocab,
|
55
55
|
abstractSqlModel,
|
@@ -59,14 +59,6 @@ const checkForExpansion = async (
|
|
59
59
|
);
|
60
60
|
row[fieldName] = expandedField;
|
61
61
|
} else {
|
62
|
-
const mappingResourceName = resolveNavigationResource(
|
63
|
-
{
|
64
|
-
abstractSqlModel,
|
65
|
-
vocabulary: vocab,
|
66
|
-
resourceName: parentResourceName,
|
67
|
-
},
|
68
|
-
fieldName,
|
69
|
-
);
|
70
62
|
row[fieldName] = {
|
71
63
|
__id: field,
|
72
64
|
};
|
@@ -96,8 +88,7 @@ const getLocalFields = (table: AbstractSqlTable) => {
|
|
96
88
|
if (table.localFields == null) {
|
97
89
|
table.localFields = {};
|
98
90
|
for (const { fieldName, dataType } of table.fields) {
|
99
|
-
|
100
|
-
if (dataType !== 'ForeignKey') {
|
91
|
+
if (!['ForeignKey', 'ConceptType'].includes(dataType)) {
|
101
92
|
const odataName = sqlNameToODataName(fieldName);
|
102
93
|
table.localFields[odataName] = true;
|
103
94
|
}
|
@@ -109,12 +100,16 @@ const getFetchProcessingFields = (table: AbstractSqlTable) => {
|
|
109
100
|
return (table.fetchProcessingFields ??= _(table.fields)
|
110
101
|
.filter(
|
111
102
|
({ dataType }) =>
|
112
|
-
sbvrTypes[dataType]
|
113
|
-
|
103
|
+
(sbvrTypes[dataType as keyof typeof sbvrTypes] as SbvrType)
|
104
|
+
?.fetchProcessing != null,
|
114
105
|
)
|
115
106
|
.map(({ fieldName, dataType }) => {
|
116
107
|
const odataName = sqlNameToODataName(fieldName);
|
117
|
-
return [
|
108
|
+
return [
|
109
|
+
odataName,
|
110
|
+
(sbvrTypes[dataType as keyof typeof sbvrTypes] as SbvrType)
|
111
|
+
.fetchProcessing,
|
112
|
+
];
|
118
113
|
})
|
119
114
|
.fromPairs()
|
120
115
|
.value());
|
@@ -160,16 +155,16 @@ export const process = async (
|
|
160
155
|
);
|
161
156
|
|
162
157
|
const odataIdField = sqlNameToODataName(table.idField);
|
163
|
-
|
164
|
-
|
158
|
+
for (const row of rows) {
|
159
|
+
for (const fieldName of processedFields) {
|
165
160
|
row[fieldName] = fetchProcessingFields[fieldName](row[fieldName]);
|
166
|
-
}
|
161
|
+
}
|
167
162
|
if (includeMetadata) {
|
168
163
|
row.__metadata = {
|
169
164
|
uri: resourceURI(vocab, resourceName, row[odataIdField]),
|
170
165
|
};
|
171
166
|
}
|
172
|
-
}
|
167
|
+
}
|
173
168
|
|
174
169
|
if (expandableFields.length > 0) {
|
175
170
|
await Promise.all(
|