@balena/pinejs 14.60.0-build-translated-models-85baf731130de328e2067a26c40b37309cdb1ac5-1 → 15.0.0-build-15-x-4681209f5dd8d896491fb5ed64aea47df511c14d-1
Sign up to get free protection for your applications and to get access to all the features.
- package/.pinejs-cache.json +1 -1
- package/.versionbot/CHANGELOG.yml +106 -6
- package/CHANGELOG.md +16 -4
- package/VERSION +1 -1
- package/build/browser.ts +0 -1
- package/out/bin/abstract-sql-compiler.js +0 -0
- package/out/bin/abstract-sql-compiler.js.map +1 -1
- package/out/bin/odata-compiler.js +1 -4
- package/out/bin/odata-compiler.js.map +1 -1
- package/out/bin/sbvr-compiler.js +0 -0
- package/out/bin/sbvr-compiler.js.map +1 -1
- package/out/config-loader/config-loader.d.ts +2 -5
- package/out/config-loader/config-loader.js +19 -38
- package/out/config-loader/config-loader.js.map +1 -1
- package/out/config-loader/env.js +4 -4
- package/out/config-loader/env.js.map +1 -1
- package/out/data-server/sbvr-server.d.ts +1 -13
- package/out/data-server/sbvr-server.js +17 -1
- package/out/data-server/sbvr-server.js.map +1 -1
- package/out/database-layer/db.js +12 -15
- package/out/database-layer/db.js.map +1 -1
- package/out/express-emulator/express.js +4 -4
- package/out/express-emulator/express.js.map +1 -1
- package/out/http-transactions/transactions.d.ts +1 -12
- package/out/http-transactions/transactions.js +18 -0
- package/out/http-transactions/transactions.js.map +1 -1
- package/out/migrator/async.js +12 -16
- package/out/migrator/async.js.map +1 -1
- package/out/migrator/sync.js +6 -12
- package/out/migrator/sync.js.map +1 -1
- package/out/migrator/utils.d.ts +5 -4
- package/out/migrator/utils.js +38 -20
- package/out/migrator/utils.js.map +1 -1
- package/out/pinejs-session-store/pinejs-session-store.js +18 -3
- package/out/pinejs-session-store/pinejs-session-store.js.map +1 -1
- package/out/sbvr-api/abstract-sql.js +2 -4
- 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/hooks.d.ts +3 -3
- package/out/sbvr-api/hooks.js +32 -48
- package/out/sbvr-api/hooks.js.map +1 -1
- package/out/sbvr-api/odata-response.js +4 -5
- package/out/sbvr-api/odata-response.js.map +1 -1
- package/out/sbvr-api/permissions.js +25 -65
- package/out/sbvr-api/permissions.js.map +1 -1
- package/out/sbvr-api/sbvr-utils.d.ts +5 -11
- package/out/sbvr-api/sbvr-utils.js +94 -145
- package/out/sbvr-api/sbvr-utils.js.map +1 -1
- package/out/sbvr-api/uri-parser.d.ts +1 -4
- package/out/sbvr-api/uri-parser.js +4 -11
- package/out/sbvr-api/uri-parser.js.map +1 -1
- package/package.json +8 -8
- package/src/bin/abstract-sql-compiler.ts +2 -1
- package/src/bin/odata-compiler.ts +2 -4
- package/src/bin/sbvr-compiler.ts +2 -1
- package/src/config-loader/config-loader.ts +24 -62
- package/src/config-loader/env.ts +3 -7
- package/src/data-server/sbvr-server.js +17 -1
- package/src/database-layer/db.ts +1 -1
- package/src/express-emulator/express.js +4 -4
- package/src/http-transactions/transactions.js +18 -0
- package/src/migrator/utils.ts +40 -20
- package/src/pinejs-session-store/pinejs-session-store.ts +15 -0
- package/src/sbvr-api/abstract-sql.ts +1 -2
- package/src/sbvr-api/hooks.ts +33 -80
- package/src/sbvr-api/odata-response.ts +1 -2
- package/src/sbvr-api/permissions.ts +20 -68
- package/src/sbvr-api/sbvr-utils.ts +107 -195
- package/src/sbvr-api/uri-parser.ts +5 -8
- package/tsconfig.json +1 -1
- package/out/sbvr-api/translations.d.ts +0 -6
- package/out/sbvr-api/translations.js +0 -136
- package/out/sbvr-api/translations.js.map +0 -1
- package/src/sbvr-api/translations.ts +0 -219
@@ -63,7 +63,6 @@ import {
|
|
63
63
|
rollbackRequestHooks,
|
64
64
|
getHooks,
|
65
65
|
runHooks,
|
66
|
-
InstantiatedHooks,
|
67
66
|
} from './hooks';
|
68
67
|
export {
|
69
68
|
HookReq,
|
@@ -93,7 +92,6 @@ import {
|
|
93
92
|
export { resolveOdataBind } from './abstract-sql';
|
94
93
|
import * as odataResponse from './odata-response';
|
95
94
|
import { env } from '../server-glue/module';
|
96
|
-
import { translateAbstractSqlModel } from './translations';
|
97
95
|
|
98
96
|
const LF2AbstractSQLTranslator = LF2AbstractSQL.createTranslator(sbvrTypes);
|
99
97
|
const LF2AbstractSQLTranslatorVersion = `${LF2AbstractSQLVersion}+${sbvrTypesVersion}`;
|
@@ -104,18 +102,14 @@ export type ExecutableModel =
|
|
104
102
|
|
105
103
|
interface CompiledModel {
|
106
104
|
vocab: string;
|
107
|
-
translateTo?: string;
|
108
|
-
resourceRenames?: ReturnType<typeof translateAbstractSqlModel>;
|
109
105
|
se?: string | undefined;
|
110
106
|
lf?: LFModel | undefined;
|
111
107
|
abstractSql: AbstractSQLCompiler.AbstractSqlModel;
|
112
|
-
sql
|
108
|
+
sql: AbstractSQLCompiler.SqlModel;
|
113
109
|
odataMetadata: ReturnType<typeof generateODataMetadata>;
|
114
110
|
}
|
115
111
|
const models: {
|
116
|
-
[vocabulary: string]: CompiledModel
|
117
|
-
versions: string[];
|
118
|
-
};
|
112
|
+
[vocabulary: string]: CompiledModel;
|
119
113
|
} = {};
|
120
114
|
|
121
115
|
export interface Actor {
|
@@ -129,7 +123,7 @@ export interface User extends Actor {
|
|
129
123
|
|
130
124
|
export interface ApiKey extends Actor {
|
131
125
|
key: string;
|
132
|
-
actor
|
126
|
+
actor: number;
|
133
127
|
}
|
134
128
|
|
135
129
|
export interface Response {
|
@@ -240,7 +234,7 @@ const prettifyConstraintError = (
|
|
240
234
|
break;
|
241
235
|
case 'postgres':
|
242
236
|
const resourceName = resolveSynonym(request);
|
243
|
-
const abstractSqlModel =
|
237
|
+
const abstractSqlModel = getAbstractSqlModel(request);
|
244
238
|
matches = new RegExp(
|
245
239
|
'"' + abstractSqlModel.tables[resourceName].name + '_(.*?)_key"',
|
246
240
|
).exec(err.message);
|
@@ -273,7 +267,7 @@ const prettifyConstraintError = (
|
|
273
267
|
break;
|
274
268
|
case 'postgres':
|
275
269
|
const resourceName = resolveSynonym(request);
|
276
|
-
const abstractSqlModel =
|
270
|
+
const abstractSqlModel = getAbstractSqlModel(request);
|
277
271
|
const tableName = abstractSqlModel.tables[resourceName].name;
|
278
272
|
matches = new RegExp(
|
279
273
|
'"' +
|
@@ -305,7 +299,7 @@ const prettifyConstraintError = (
|
|
305
299
|
|
306
300
|
if (err instanceof db.CheckConstraintError) {
|
307
301
|
const resourceName = resolveSynonym(request);
|
308
|
-
const abstractSqlModel =
|
302
|
+
const abstractSqlModel = getAbstractSqlModel(request);
|
309
303
|
const table = abstractSqlModel.tables[resourceName];
|
310
304
|
if (table.checks) {
|
311
305
|
switch (db.engine) {
|
@@ -380,12 +374,8 @@ export const validateModel = async (
|
|
380
374
|
'abstractSqlQuery' | 'modifiedFields' | 'method' | 'vocabulary'
|
381
375
|
>,
|
382
376
|
): Promise<void> => {
|
383
|
-
const { sql } = models[modelName];
|
384
|
-
if (!sql) {
|
385
|
-
throw new Error(`Tried to validate a virtual model: '${modelName}'`);
|
386
|
-
}
|
387
377
|
await Promise.all(
|
388
|
-
sql.rules.map(async (rule) => {
|
378
|
+
models[modelName].sql.rules.map(async (rule) => {
|
389
379
|
if (!isRuleAffected(rule, request)) {
|
390
380
|
// If none of the fields intersect we don't need to run the rule! :D
|
391
381
|
return;
|
@@ -436,19 +426,11 @@ export const generateSqlModel = (
|
|
436
426
|
() => AbstractSQLCompiler[targetDatabaseEngine].compileSchema(abstractSql),
|
437
427
|
);
|
438
428
|
|
439
|
-
export
|
440
|
-
model: ExecutableModel & { translateTo?: undefined },
|
441
|
-
targetDatabaseEngine: AbstractSQLCompiler.Engines,
|
442
|
-
): RequiredField<CompiledModel, 'sql'>;
|
443
|
-
export function generateModels(
|
429
|
+
export const generateModels = (
|
444
430
|
model: ExecutableModel,
|
445
431
|
targetDatabaseEngine: AbstractSQLCompiler.Engines,
|
446
|
-
): CompiledModel
|
447
|
-
|
448
|
-
model: ExecutableModel,
|
449
|
-
targetDatabaseEngine: AbstractSQLCompiler.Engines,
|
450
|
-
): CompiledModel {
|
451
|
-
const { apiRoot: vocab, modelText: se, translateTo, translations } = model;
|
432
|
+
): CompiledModel => {
|
433
|
+
const { apiRoot: vocab, modelText: se } = model;
|
452
434
|
let { abstractSql: maybeAbstractSql } = model;
|
453
435
|
|
454
436
|
let lf: ReturnType<typeof generateLfModel> | undefined;
|
@@ -476,41 +458,16 @@ export function generateModels(
|
|
476
458
|
() => generateODataMetadata(vocab, abstractSql),
|
477
459
|
);
|
478
460
|
|
479
|
-
let sql: AbstractSQLCompiler.
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
models[translateTo].abstractSql,
|
486
|
-
model.apiRoot,
|
487
|
-
translateTo,
|
488
|
-
translations,
|
489
|
-
);
|
490
|
-
} else {
|
491
|
-
for (const [key, table] of Object.entries(abstractSql.tables)) {
|
492
|
-
// Alias the current version so it can be explicitly referenced
|
493
|
-
abstractSql.tables[`${key}$${model.apiRoot}`] = { ...table };
|
494
|
-
}
|
495
|
-
try {
|
496
|
-
sql = generateSqlModel(abstractSql, targetDatabaseEngine);
|
497
|
-
} catch (e) {
|
498
|
-
console.error(`Error compiling model '${vocab}':`, e);
|
499
|
-
throw new Error(`Error compiling model '${vocab}': ` + e);
|
500
|
-
}
|
461
|
+
let sql: ReturnType<AbstractSQLCompiler.EngineInstance['compileSchema']>;
|
462
|
+
try {
|
463
|
+
sql = generateSqlModel(abstractSql, targetDatabaseEngine);
|
464
|
+
} catch (e) {
|
465
|
+
console.error(`Error compiling model '${vocab}':`, e);
|
466
|
+
throw new Error(`Error compiling model '${vocab}': ` + e);
|
501
467
|
}
|
502
468
|
|
503
|
-
return {
|
504
|
-
|
505
|
-
translateTo,
|
506
|
-
resourceRenames,
|
507
|
-
se,
|
508
|
-
lf,
|
509
|
-
abstractSql,
|
510
|
-
sql,
|
511
|
-
odataMetadata,
|
512
|
-
};
|
513
|
-
}
|
469
|
+
return { vocab, se, lf, abstractSql, sql, odataMetadata };
|
470
|
+
};
|
514
471
|
|
515
472
|
export const executeModel = (
|
516
473
|
tx: Db.Tx,
|
@@ -529,42 +486,30 @@ export const executeModels = async (
|
|
529
486
|
await syncMigrator.run(tx, model);
|
530
487
|
const compiledModel = generateModels(model, db.engine);
|
531
488
|
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
});
|
544
|
-
}
|
545
|
-
await promise;
|
489
|
+
// Create tables related to terms and fact types
|
490
|
+
// Run statements sequentially, as the order of the CREATE TABLE statements matters (eg. for foreign keys).
|
491
|
+
for (const createStatement of compiledModel.sql.createSchema) {
|
492
|
+
const promise = tx.executeSql(createStatement);
|
493
|
+
if (db.engine === 'websql') {
|
494
|
+
promise.catch((err) => {
|
495
|
+
console.warn(
|
496
|
+
"Ignoring errors in the create table statements for websql as it doesn't support CREATE IF NOT EXISTS",
|
497
|
+
err,
|
498
|
+
);
|
499
|
+
});
|
546
500
|
}
|
501
|
+
await promise;
|
547
502
|
}
|
548
503
|
await syncMigrator.postRun(tx, model);
|
549
504
|
|
550
505
|
odataResponse.prepareModel(compiledModel.abstractSql);
|
551
506
|
deepFreeze(compiledModel.abstractSql);
|
552
|
-
|
553
|
-
const versions = [apiRoot];
|
554
|
-
if (compiledModel.translateTo != null) {
|
555
|
-
versions.push(...models[compiledModel.translateTo].versions);
|
556
|
-
}
|
557
|
-
models[apiRoot] = {
|
558
|
-
...compiledModel,
|
559
|
-
versions,
|
560
|
-
};
|
507
|
+
models[apiRoot] = compiledModel;
|
561
508
|
|
562
509
|
// Validate the [empty] model according to the rules.
|
563
510
|
// This may eventually lead to entering obligatory data.
|
564
511
|
// For the moment it blocks such models from execution.
|
565
|
-
|
566
|
-
await validateModel(tx, apiRoot);
|
567
|
-
}
|
512
|
+
await validateModel(tx, apiRoot);
|
568
513
|
|
569
514
|
// TODO: Can we do this without the cast?
|
570
515
|
api[apiRoot] = new PinejsClient('/' + apiRoot + '/') as LoggingClient;
|
@@ -624,7 +569,10 @@ export const executeModels = async (
|
|
624
569
|
let uri = '/dev/model';
|
625
570
|
const body: AnyObject = {
|
626
571
|
is_of__vocabulary: model.vocab,
|
627
|
-
model_value:
|
572
|
+
model_value:
|
573
|
+
typeof model[modelType] === 'string'
|
574
|
+
? { value: model[modelType] }
|
575
|
+
: model[modelType],
|
628
576
|
model_type: modelType,
|
629
577
|
};
|
630
578
|
const id = result?.[0]?.id;
|
@@ -666,30 +614,27 @@ const cleanupModel = (vocab: string) => {
|
|
666
614
|
};
|
667
615
|
|
668
616
|
export const deleteModel = async (vocabulary: string) => {
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
$filter: {
|
685
|
-
is_of__vocabulary: vocabulary,
|
686
|
-
},
|
617
|
+
await db.transaction(async (tx) => {
|
618
|
+
const dropStatements: Array<Promise<any>> = models[
|
619
|
+
vocabulary
|
620
|
+
].sql.dropSchema.map((dropStatement) => tx.executeSql(dropStatement));
|
621
|
+
await Promise.all(
|
622
|
+
dropStatements.concat([
|
623
|
+
api.dev.delete({
|
624
|
+
resource: 'model',
|
625
|
+
passthrough: {
|
626
|
+
tx,
|
627
|
+
req: permissions.root,
|
628
|
+
},
|
629
|
+
options: {
|
630
|
+
$filter: {
|
631
|
+
is_of__vocabulary: vocabulary,
|
687
632
|
},
|
688
|
-
}
|
689
|
-
|
690
|
-
)
|
691
|
-
|
692
|
-
}
|
633
|
+
},
|
634
|
+
}),
|
635
|
+
]),
|
636
|
+
);
|
637
|
+
});
|
693
638
|
await cleanupModel(vocabulary);
|
694
639
|
};
|
695
640
|
|
@@ -982,28 +927,12 @@ export const getAbstractSqlModel = (
|
|
982
927
|
return (request.abstractSqlModel ??= models[request.vocabulary].abstractSql);
|
983
928
|
};
|
984
929
|
|
985
|
-
const getFinalAbstractSqlModel = (
|
986
|
-
request: Pick<
|
987
|
-
uriParser.ODataRequest,
|
988
|
-
'translateVersions' | 'finalAbstractSqlModel'
|
989
|
-
>,
|
990
|
-
): AbstractSQLCompiler.AbstractSqlModel => {
|
991
|
-
const finalModel = _.last(request.translateVersions)!;
|
992
|
-
return (request.finalAbstractSqlModel ??= models[finalModel].abstractSql);
|
993
|
-
};
|
994
|
-
|
995
930
|
const getIdField = (
|
996
931
|
request: Pick<
|
997
932
|
uriParser.ODataRequest,
|
998
|
-
| '
|
999
|
-
| 'finalAbstractSqlModel'
|
1000
|
-
| 'abstractSqlModel'
|
1001
|
-
| 'resourceName'
|
1002
|
-
| 'vocabulary'
|
933
|
+
'vocabulary' | 'abstractSqlModel' | 'resourceName'
|
1003
934
|
>,
|
1004
|
-
) =>
|
1005
|
-
// TODO: Should resolveSynonym also be using the finalAbstractSqlModel?
|
1006
|
-
getFinalAbstractSqlModel(request).tables[resolveSynonym(request)].idField;
|
935
|
+
) => getAbstractSqlModel(request).tables[resolveSynonym(request)].idField;
|
1007
936
|
|
1008
937
|
export const getAffectedIds = async (
|
1009
938
|
args: HookArgs & {
|
@@ -1046,18 +975,17 @@ const $getAffectedIds = async ({
|
|
1046
975
|
// We reparse to make sure we get a clean odataQuery, without permissions already added
|
1047
976
|
// And we use the request's url rather than the req for things like batch where the req url is ../$batch
|
1048
977
|
const parsedRequest: uriParser.ParsedODataRequest &
|
1049
|
-
Partial<Pick<uriParser.ODataRequest, 'engine'
|
978
|
+
Partial<Pick<uriParser.ODataRequest, 'engine'>> =
|
1050
979
|
await uriParser.parseOData({
|
1051
980
|
method: request.method,
|
1052
981
|
url: `/${request.vocabulary}${request.url}`,
|
1053
982
|
});
|
1054
983
|
|
1055
984
|
parsedRequest.engine = request.engine;
|
1056
|
-
parsedRequest.translateVersions = request.translateVersions;
|
1057
985
|
// Mark that the engine is required now that we've set it
|
1058
986
|
let affectedRequest: uriParser.ODataRequest = parsedRequest as RequiredField<
|
1059
987
|
typeof parsedRequest,
|
1060
|
-
'engine'
|
988
|
+
'engine'
|
1061
989
|
>;
|
1062
990
|
const abstractSqlModel = getAbstractSqlModel(affectedRequest);
|
1063
991
|
const resourceName = resolveSynonym(affectedRequest);
|
@@ -1100,18 +1028,10 @@ const runODataRequest = (req: Express.Request, vocabulary: string) => {
|
|
1100
1028
|
|
1101
1029
|
// Get the hooks for the current method/vocabulary as we know it,
|
1102
1030
|
// in order to run PREPARSE hooks, before parsing gets us more info
|
1103
|
-
const
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
{
|
1108
|
-
method: req.method as SupportedMethod,
|
1109
|
-
vocabulary: version,
|
1110
|
-
},
|
1111
|
-
// Only include the `all` vocab for the first model version
|
1112
|
-
version === versions[0],
|
1113
|
-
),
|
1114
|
-
]);
|
1031
|
+
const reqHooks = getHooks({
|
1032
|
+
method: req.method as SupportedMethod,
|
1033
|
+
vocabulary,
|
1034
|
+
});
|
1115
1035
|
|
1116
1036
|
const transactions: Db.Tx[] = [];
|
1117
1037
|
const tryCancelRequest = () => {
|
@@ -1154,49 +1074,23 @@ const runODataRequest = (req: Express.Request, vocabulary: string) => {
|
|
1154
1074
|
|
1155
1075
|
const prepareRequest = async (
|
1156
1076
|
parsedRequest: uriParser.ParsedODataRequest &
|
1157
|
-
Partial<Pick<uriParser.ODataRequest, 'engine'
|
1077
|
+
Partial<Pick<uriParser.ODataRequest, 'engine'>>,
|
1158
1078
|
): Promise<uriParser.ODataRequest> => {
|
1159
1079
|
parsedRequest.engine = db.engine;
|
1160
|
-
|
1161
|
-
// Mark that the engine/translateVersions is required now that we've set it
|
1080
|
+
// Mark that the engine is required now that we've set it
|
1162
1081
|
const $request: uriParser.ODataRequest = parsedRequest as RequiredField<
|
1163
1082
|
typeof parsedRequest,
|
1164
|
-
'engine'
|
1083
|
+
'engine'
|
1165
1084
|
>;
|
1085
|
+
// Get the full hooks list now that we can.
|
1086
|
+
$request.hooks = getHooks($request);
|
1166
1087
|
// Add/check the relevant permissions
|
1167
1088
|
try {
|
1168
|
-
$request.hooks
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
version,
|
1174
|
-
getHooks(
|
1175
|
-
{
|
1176
|
-
resourceName: $request.resourceName,
|
1177
|
-
vocabulary: version,
|
1178
|
-
method: $request.method,
|
1179
|
-
},
|
1180
|
-
// Only include the `all` vocab for the first model version
|
1181
|
-
version === versions[0],
|
1182
|
-
),
|
1183
|
-
];
|
1184
|
-
$request.hooks.push(hooks);
|
1185
|
-
await runHooks('POSTPARSE', [hooks], {
|
1186
|
-
req,
|
1187
|
-
request: $request,
|
1188
|
-
tx: req.tx,
|
1189
|
-
});
|
1190
|
-
const { resourceRenames } = models[version];
|
1191
|
-
if (resourceRenames) {
|
1192
|
-
const resourceName = resolveSynonym($request);
|
1193
|
-
if (resourceRenames[resourceName]) {
|
1194
|
-
$request.resourceName = sqlNameToODataName(
|
1195
|
-
resourceRenames[resourceName],
|
1196
|
-
);
|
1197
|
-
}
|
1198
|
-
}
|
1199
|
-
}
|
1089
|
+
await runHooks('POSTPARSE', $request.hooks, {
|
1090
|
+
req,
|
1091
|
+
request: $request,
|
1092
|
+
tx: req.tx,
|
1093
|
+
});
|
1200
1094
|
const translatedRequest = await uriParser.translateUri($request);
|
1201
1095
|
return await compileRequest(translatedRequest);
|
1202
1096
|
} catch (err: any) {
|
@@ -1531,12 +1425,9 @@ const checkReadOnlyRequests = (request: uriParser.ODataRequest) => {
|
|
1531
1425
|
return true;
|
1532
1426
|
}
|
1533
1427
|
// If there are hooks then check that they're all read-only
|
1534
|
-
return hooks.every(
|
1535
|
-
|
1536
|
-
|
1537
|
-
hookTypeHooks == null || hookTypeHooks.every((hook) => hook.readOnlyTx)
|
1538
|
-
);
|
1539
|
-
}),
|
1428
|
+
return Object.values(hooks).every(
|
1429
|
+
(hookTypeHooks) =>
|
1430
|
+
hookTypeHooks == null || hookTypeHooks.every((hook) => hook.readOnlyTx),
|
1540
1431
|
);
|
1541
1432
|
};
|
1542
1433
|
|
@@ -1631,7 +1522,7 @@ const respondGet = async (
|
|
1631
1522
|
const d = await odataResponse.process(
|
1632
1523
|
vocab,
|
1633
1524
|
getAbstractSqlModel(request),
|
1634
|
-
request.
|
1525
|
+
request.resourceName,
|
1635
1526
|
result.rows,
|
1636
1527
|
{ includeMetadata: metadata === 'full' },
|
1637
1528
|
);
|
@@ -1680,7 +1571,7 @@ const runPost = async (
|
|
1680
1571
|
if (rowsAffected === 0) {
|
1681
1572
|
throw new PermissionError();
|
1682
1573
|
}
|
1683
|
-
await validateModel(tx,
|
1574
|
+
await validateModel(tx, request.vocabulary, request);
|
1684
1575
|
|
1685
1576
|
return insertId;
|
1686
1577
|
};
|
@@ -1692,11 +1583,7 @@ const respondPost = async (
|
|
1692
1583
|
tx: Db.Tx,
|
1693
1584
|
): Promise<Response> => {
|
1694
1585
|
const vocab = request.vocabulary;
|
1695
|
-
const location = odataResponse.resourceURI(
|
1696
|
-
vocab,
|
1697
|
-
request.originalResourceName,
|
1698
|
-
id,
|
1699
|
-
);
|
1586
|
+
const location = odataResponse.resourceURI(vocab, request.resourceName, id);
|
1700
1587
|
if (env.DEBUG) {
|
1701
1588
|
api[vocab].logger.log('Insert ID: ', request.resourceName, id);
|
1702
1589
|
}
|
@@ -1754,7 +1641,7 @@ const runPut = async (
|
|
1754
1641
|
({ rowsAffected } = await runQuery(tx, request, undefined, idField));
|
1755
1642
|
}
|
1756
1643
|
if (rowsAffected > 0) {
|
1757
|
-
await validateModel(tx,
|
1644
|
+
await validateModel(tx, request.vocabulary, request);
|
1758
1645
|
}
|
1759
1646
|
return undefined;
|
1760
1647
|
};
|
@@ -1792,7 +1679,7 @@ const runDelete = async (
|
|
1792
1679
|
getIdField(request),
|
1793
1680
|
);
|
1794
1681
|
if (rowsAffected > 0) {
|
1795
|
-
await validateModel(tx,
|
1682
|
+
await validateModel(tx, request.vocabulary, request);
|
1796
1683
|
}
|
1797
1684
|
|
1798
1685
|
return undefined;
|
@@ -1812,6 +1699,31 @@ export const executeStandardModels = async (tx: Db.Tx): Promise<void> => {
|
|
1812
1699
|
ALTER TABLE "model"
|
1813
1700
|
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
1814
1701
|
`,
|
1702
|
+
'15.0.0-data-types': async ($tx, sbvrUtils) => {
|
1703
|
+
switch (sbvrUtils.db.engine) {
|
1704
|
+
case 'mysql':
|
1705
|
+
await $tx.executeSql(`\
|
1706
|
+
ALTER TABLE "model"
|
1707
|
+
MODIFY "model value" JSON NOT NULL;
|
1708
|
+
|
1709
|
+
UPDATE "model"
|
1710
|
+
SET "model value" = CAST('{"value":' || CAST("model value" AS CHAR) || '}' AS JSON)
|
1711
|
+
WHERE "model type" IN ('se', 'odataMetadata')
|
1712
|
+
AND CAST("model value" AS CHAR) LIKE '"%';`);
|
1713
|
+
break;
|
1714
|
+
case 'postgres':
|
1715
|
+
await $tx.executeSql(`\
|
1716
|
+
ALTER TABLE "model"
|
1717
|
+
ALTER COLUMN "model value" SET DATA TYPE JSONB USING "model value"::JSONB;
|
1718
|
+
|
1719
|
+
UPDATE "model"
|
1720
|
+
SET "model value" = CAST('{"value":' || CAST("model value" AS TEXT) || '}' AS JSON)
|
1721
|
+
WHERE "model type" IN ('se', 'odataMetadata')
|
1722
|
+
AND CAST("model value" AS TEXT) LIKE '"%';`);
|
1723
|
+
break;
|
1724
|
+
// No need to migrate for websql
|
1725
|
+
}
|
1726
|
+
},
|
1815
1727
|
},
|
1816
1728
|
});
|
1817
1729
|
await executeModels(tx, permissions.config.models);
|
@@ -42,7 +42,6 @@ export interface ParsedODataRequest {
|
|
42
42
|
url: string;
|
43
43
|
vocabulary: string;
|
44
44
|
resourceName: string;
|
45
|
-
originalResourceName: string;
|
46
45
|
values: AnyObject;
|
47
46
|
odataQuery: ODataQuery;
|
48
47
|
odataBinds: OdataBinds;
|
@@ -51,9 +50,7 @@ export interface ParsedODataRequest {
|
|
51
50
|
_defer?: boolean;
|
52
51
|
}
|
53
52
|
export interface ODataRequest extends ParsedODataRequest {
|
54
|
-
translateVersions: string[];
|
55
53
|
abstractSqlModel?: AbstractSQLCompiler.AbstractSqlModel;
|
56
|
-
finalAbstractSqlModel?: AbstractSQLCompiler.AbstractSqlModel;
|
57
54
|
abstractSqlQuery?: AbstractSQLCompiler.AbstractSqlQuery;
|
58
55
|
sqlQuery?: AbstractSQLCompiler.SqlResult | AbstractSQLCompiler.SqlResult[];
|
59
56
|
tx?: Tx;
|
@@ -62,7 +59,7 @@ export interface ODataRequest extends ParsedODataRequest {
|
|
62
59
|
>;
|
63
60
|
affectedIds?: number[];
|
64
61
|
pendingAffectedIds?: Promise<number[]>;
|
65
|
-
hooks?:
|
62
|
+
hooks?: InstantiatedHooks;
|
66
63
|
engine: AbstractSQLCompiler.Engines;
|
67
64
|
}
|
68
65
|
|
@@ -147,7 +144,8 @@ export const memoizedParseOdata = (() => {
|
|
147
144
|
|
148
145
|
export const memoizedGetOData2AbstractSQL = memoizeWeak(
|
149
146
|
(abstractSqlModel: AbstractSQLCompiler.AbstractSqlModel) => {
|
150
|
-
|
147
|
+
// TODO: REMOVE THIS, it's temporary due to mismatched abstract-sql-compiler versions
|
148
|
+
return new OData2AbstractSQL(abstractSqlModel as any, undefined, {
|
151
149
|
// Use minimized aliases when not in debug mode for smaller queries
|
152
150
|
minimizeAliases: !env.DEBUG,
|
153
151
|
});
|
@@ -294,7 +292,6 @@ export async function parseOData(
|
|
294
292
|
url,
|
295
293
|
vocabulary: apiRoot,
|
296
294
|
resourceName: odata.tree.resource,
|
297
|
-
originalResourceName: odata.tree.resource,
|
298
295
|
values: b.data ?? {},
|
299
296
|
odataQuery: odata.tree,
|
300
297
|
odataBinds: odata.binds,
|
@@ -357,7 +354,6 @@ const parseODataChangeset = (
|
|
357
354
|
url,
|
358
355
|
vocabulary: apiRoot,
|
359
356
|
resourceName: odata.tree.resource,
|
360
|
-
originalResourceName: odata.tree.resource,
|
361
357
|
odataBinds: odata.binds,
|
362
358
|
odataQuery: odata.tree,
|
363
359
|
values: b.data ?? {},
|
@@ -423,7 +419,8 @@ export const translateUri = <
|
|
423
419
|
return true;
|
424
420
|
},
|
425
421
|
});
|
426
|
-
|
422
|
+
// TODO: REMOVE THIS, it's temporary due to mismatched abstract-sql-compiler versions
|
423
|
+
request.abstractSqlQuery = abstractSqlQuery as any;
|
427
424
|
return request;
|
428
425
|
}
|
429
426
|
return request;
|
package/tsconfig.json
CHANGED
@@ -1,6 +0,0 @@
|
|
1
|
-
import { AbstractSqlModel, ReferencedFieldNode, Definition, SelectQueryNode, NumberTypeNodes, BooleanTypeNodes, UnknownTypeNodes, NullNode } from '@balena/abstract-sql-compiler';
|
2
|
-
import { Dictionary } from './common-types';
|
3
|
-
export type AliasValidNodeType = ReferencedFieldNode | SelectQueryNode | NumberTypeNodes | BooleanTypeNodes | UnknownTypeNodes | NullNode;
|
4
|
-
export declare const translateAbstractSqlModel: (fromAbstractSqlModel: AbstractSqlModel, toAbstractSqlModel: AbstractSqlModel, fromVersion: string, toVersion: string, translationDefinitions?: Dictionary<(Definition & {
|
5
|
-
$toResource?: string;
|
6
|
-
}) | Dictionary<string | AliasValidNodeType>>) => Dictionary<string>;
|