@sap/xsodata 8.2.1 → 8.3.1
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/CHANGELOG.md +10 -0
- package/index.js +2 -2
- package/lib/configuration.js +1 -1
- package/lib/db/connect.js +1 -1
- package/lib/db/dbSegment.js +68 -123
- package/lib/db/dbVersionChecks.js +2 -8
- package/lib/handlerConfiguration.js +2 -2
- package/lib/http/conditionalHttpHandler.js +27 -34
- package/lib/http/simpleHttpRequest.js +14 -18
- package/lib/http/simpleHttpResponse.js +9 -6
- package/lib/http/uriParser.js +9 -9
- package/lib/http/validator/httpRequestValidator.js +9 -9
- package/lib/model/annotationFactory.js +11 -11
- package/lib/model/association.js +3 -3
- package/lib/model/entityType.js +33 -67
- package/lib/model/metadataReader.js +31 -52
- package/lib/model/model.js +0 -1
- package/lib/model/validator/xsoDataConcurrencyTokenValidator.js +6 -6
- package/lib/model/xsodataReader.js +36 -28
- package/lib/processor/authorizationProcessor.js +22 -33
- package/lib/processor/batchProcessor.js +22 -33
- package/lib/processor/errorProcessor.js +4 -4
- package/lib/processor/exitProcessor.js +19 -19
- package/lib/processor/processor.js +9 -9
- package/lib/processor/resourceProcessor.js +31 -61
- package/lib/processor/resourceProcessorDelete.js +16 -16
- package/lib/processor/resourceProcessorDeleteLinks.js +25 -25
- package/lib/processor/resourceProcessorGet.js +5 -5
- package/lib/processor/resourceProcessorPost.js +43 -45
- package/lib/processor/resourceProcessorPut.js +35 -39
- package/lib/processor/resourceProcessorPutPostLinks.js +38 -39
- package/lib/security/securityContext.js +5 -5
- package/lib/serializer/atomSerializer.js +54 -55
- package/lib/serializer/atomXmlToJsonSerializer.js +32 -44
- package/lib/serializer/content.js +5 -5
- package/lib/serializer/json.js +31 -33
- package/lib/serializer/jsonSerializer.js +4 -4
- package/lib/serializer/metadataSerializer.js +32 -35
- package/lib/serializer/serializer.js +29 -43
- package/lib/serializer/serviceSerializer.js +19 -24
- package/lib/serializer/value.js +1 -2
- package/lib/serializer/xmlToJsonSerializer.js +18 -18
- package/lib/sql/createDeleteLinksStatements.js +10 -10
- package/lib/sql/createDeleteStatements.js +12 -12
- package/lib/sql/createGetStatements.js +49 -107
- package/lib/sql/createLinksSQLStatements_1_n.js +27 -27
- package/lib/sql/createPutPostLinksStatements.js +9 -9
- package/lib/sql/createPutStatements.js +0 -1
- package/lib/sql/dataCollectorDelete.js +9 -9
- package/lib/sql/dataCollectorDeleteLinks.js +3 -3
- package/lib/sql/dataCollectorGet.js +9 -17
- package/lib/sql/dataCollectorLinks.js +23 -27
- package/lib/sql/dataCollectorPost.js +20 -20
- package/lib/sql/dataCollectorPut.js +36 -36
- package/lib/sql/dataCollectorPutPostLinks.js +3 -3
- package/lib/sql/sqlStatement.js +81 -128
- package/lib/sql/sqlTools.js +3 -7
- package/lib/sql/statementProcessor.js +7 -14
- package/lib/uri/applyChecks.js +3 -3
- package/lib/uri/checks/checkAllowedMethod.js +3 -3
- package/lib/uri/checks/checkAllowedMethodForBatch.js +2 -2
- package/lib/uri/checks/checkAllowedMethodsForResourcePath.js +3 -3
- package/lib/uri/checks/checkFilterOnAggregatedColumn.js +5 -5
- package/lib/uri/checks/checkFilterOrderByOnGenKeyColumn.js +6 -6
- package/lib/uri/checks/checkGenKeyRestrictions.js +2 -2
- package/lib/uri/checks/checkModificationForbidden.js +3 -3
- package/lib/uri/checks/checkPostPutDeleteChecks.js +5 -5
- package/lib/uri/checks/checkSystemQueryOptions.js +10 -10
- package/lib/uri/checks.js +15 -15
- package/lib/uri/expandSelectTreeBuilder.js +12 -16
- package/lib/uri/oDataUriParser.js +20 -20
- package/lib/uri/queryParameterParser.js +25 -33
- package/lib/uri/resourcePathParser.js +47 -62
- package/lib/uri/uriType.js +4 -4
- package/lib/utils/associations.js +4 -4
- package/lib/utils/batch/batchExecutor.js +49 -51
- package/lib/utils/batch/batchObjects.js +10 -10
- package/lib/utils/batch/batchParser.js +27 -28
- package/lib/utils/batch/batchWriter.js +1 -1
- package/lib/utils/checkContentType.js +34 -39
- package/lib/utils/debugView.js +35 -36
- package/lib/utils/errors/applicationError.js +2 -2
- package/lib/utils/errors/debugInfo.js +2 -2
- package/lib/utils/errors/http/badRequest.js +2 -2
- package/lib/utils/errors/http/forbidden.js +2 -2
- package/lib/utils/errors/http/methodNotAllowed.js +2 -2
- package/lib/utils/errors/http/notAcceptable.js +2 -2
- package/lib/utils/errors/http/notFound.js +2 -2
- package/lib/utils/errors/http/notImplemented.js +2 -2
- package/lib/utils/errors/http/notModified.js +2 -2
- package/lib/utils/errors/http/notSupported.js +2 -2
- package/lib/utils/errors/http/preconditionFailed.js +2 -2
- package/lib/utils/errors/http/preconditionRequired.js +2 -2
- package/lib/utils/errors/http/unauthorized.js +2 -2
- package/lib/utils/errors/http/unsupportedMediaType.js +2 -2
- package/lib/utils/errors/httpError.js +2 -2
- package/lib/utils/errors/internalError.js +2 -2
- package/lib/utils/errors/modelFileError.js +2 -2
- package/lib/utils/errors/sqlError.js +2 -2
- package/lib/utils/errors/testError.js +2 -2
- package/lib/utils/errors/typeError.js +5 -5
- package/lib/utils/errors/xsODataError.js +1 -1
- package/lib/utils/logger.js +21 -32
- package/lib/utils/measurement.js +14 -13
- package/lib/utils/requestContext.js +2 -2
- package/lib/utils/stateMaschine.js +6 -6
- package/lib/utils/tableCleanup.js +3 -3
- package/lib/utils/typeConverter.js +21 -21
- package/lib/utils/typeConverters/converterTools.js +25 -331
- package/lib/utils/typeConverters/dbToJson.js +3 -3
- package/lib/utils/typeConverters/dbToUri.js +7 -7
- package/lib/utils/typeConverters/dbToXml.js +9 -9
- package/lib/utils/typeConverters/jsonToDb.js +20 -27
- package/lib/utils/typeConverters/uriToDb.js +45 -92
- package/lib/utils/typeConverters/xmlValueToJson.js +9 -13
- package/lib/utils/typedObjects.js +11 -79
- package/lib/utils/utils.js +20 -23
- package/lib/xsodata.js +37 -47
- package/package.json +9 -11
- package/.npmignore +0 -40
|
@@ -16,7 +16,7 @@ const EntityType = require('../model/entityType.js');
|
|
|
16
16
|
* @param {Array} segments Uri Segments
|
|
17
17
|
* @constructor
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
const ResourcePathReader = function (context, segments) {
|
|
20
20
|
this.context = context;
|
|
21
21
|
this.gModel = context.gModel;
|
|
22
22
|
|
|
@@ -37,19 +37,19 @@ var ResourcePathReader = function (context, segments) {
|
|
|
37
37
|
* @returns {null|dbSegments.DbSegment}
|
|
38
38
|
*/
|
|
39
39
|
ResourcePathReader.prototype.consumeFirstSegment = function consumeFirstSegment() {
|
|
40
|
-
|
|
40
|
+
let segment = this.reduceSegments.shift(); //of type uriSegmentTypes.js#ResourceSegment
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
//load entity from xsodata
|
|
44
|
-
|
|
44
|
+
let entityType = this.gModel.getEntityType(segment.identifier);
|
|
45
45
|
if (entityType === undefined) {
|
|
46
46
|
throw new Http404_NotFound("Resource not found for the segment '" + segment.identifier + "' at position " + segment.position + ".");
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// check if this segments is used to supply input parameters for the following calcview segment
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
let inputParameters = null;
|
|
51
|
+
let keys = null;
|
|
52
|
+
let isCollection = null;
|
|
53
53
|
if (entityType.kind === model.entityKind.inputParameters || entityType.kind === model.entityKind.calculationView) {
|
|
54
54
|
if (entityType._entityType.parameters && entityType._entityType.parameters.viaKey === true) {
|
|
55
55
|
// e.g. FromCalcView(IN_INTEGER=888,IN_NVARCHAR='AAA',KEY_1=1)/nav(IN_INTEGER=999,IN_NVARCHAR='BBB',KEY_2=38)
|
|
@@ -81,12 +81,11 @@ ResourcePathReader.prototype.consumeFirstSegment = function consumeFirstSegment(
|
|
|
81
81
|
segment = this.reduceSegments.shift(); //of type uriSegmentTypes.js#ResourceSegment
|
|
82
82
|
if (segment) {
|
|
83
83
|
// validate calc view segment and adopt entityType for next segments
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const navigation = entityType.getNavigation(segment.identifier);
|
|
85
|
+
const association = this.gModel.getAssociationByName(navigation.association);
|
|
86
86
|
// ### association is FromCalcViewParameters_to_FromCalcView
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
//var endFrom = this.getFromEnd(navigation, association, entityType);
|
|
88
|
+
const endTo = this.getTargetEnd(navigation, association, entityType);
|
|
90
89
|
entityType = this.gModel.getEntityType(endTo.type);
|
|
91
90
|
if (!entityType) {
|
|
92
91
|
throw new Http404_NotFound("Resource not found for the segment '" + segment.identifier + "' at position " + segment.position + ".");
|
|
@@ -134,7 +133,7 @@ ResourcePathReader.prototype.consumeFirstSegment = function consumeFirstSegment(
|
|
|
134
133
|
|
|
135
134
|
ResourcePathReader.prototype.consumeFollowerSegment = function consumeFollowerSegment(prevDbSegment) {
|
|
136
135
|
|
|
137
|
-
|
|
136
|
+
let segment = this.reduceSegments.shift();
|
|
138
137
|
// ### segment is nav
|
|
139
138
|
// ### prevDbSegment.kind is "entity"
|
|
140
139
|
if (prevDbSegment.kind === dbSegments.DBS_Property && segment.identifier !== '$value') {
|
|
@@ -185,7 +184,7 @@ ResourcePathReader.prototype.consumeFollowerSegment = function consumeFollowerSe
|
|
|
185
184
|
|
|
186
185
|
//check for primitive property
|
|
187
186
|
// ### segement.identifier is nav
|
|
188
|
-
|
|
187
|
+
const property = prevDbSegment.entityType.__metadata.getProperty(segment.identifier);
|
|
189
188
|
if (property) {
|
|
190
189
|
// segment is a valid property in path
|
|
191
190
|
prevDbSegment.kind = dbSegments.DBS_Property;
|
|
@@ -194,26 +193,21 @@ ResourcePathReader.prototype.consumeFollowerSegment = function consumeFollowerSe
|
|
|
194
193
|
}
|
|
195
194
|
|
|
196
195
|
|
|
197
|
-
|
|
196
|
+
const navigation = prevDbSegment.entityType.getNavigation(segment.identifier);
|
|
198
197
|
// ### association is first_to_second
|
|
199
198
|
if (!navigation) {
|
|
200
199
|
//E.g. /Teams('1')/$links/invalid
|
|
201
200
|
throw new Http400_BadRequest("Resource not found for the segment '" + segment.identifier + "'");
|
|
202
201
|
}
|
|
203
|
-
|
|
202
|
+
const association = this.getAssociation(navigation);
|
|
204
203
|
// ### association is first_to_second
|
|
205
204
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// // check for generated association between calcview paramters and calcview result
|
|
209
|
-
// association = this.gModel.getAssociationByName(navigation.association);
|
|
210
|
-
//}
|
|
211
|
-
var endFrom = this.getFromEnd(navigation, association, prevDbSegment.entityType);
|
|
212
|
-
var endTo = this.getTargetEnd(navigation, association, prevDbSegment.entityType);
|
|
205
|
+
const endFrom = this.getFromEnd(navigation, association, prevDbSegment.entityType);
|
|
206
|
+
let endTo = this.getTargetEnd(navigation, association, prevDbSegment.entityType);
|
|
213
207
|
|
|
214
|
-
|
|
208
|
+
let targetEntity = this.gModel.getEntityType(endTo.type);
|
|
215
209
|
// ### targetEntity is ToCalcView
|
|
216
|
-
|
|
210
|
+
const dbSegment = new dbSegments.DbSegment(dbSegments.DBS_ResourceNavigation, targetEntity, this.tableCount++);
|
|
217
211
|
prevDbSegment.nextDBSegment = dbSegment;
|
|
218
212
|
dbSegment.previousDBSegment = prevDbSegment;
|
|
219
213
|
dbSegment.association = association;
|
|
@@ -244,9 +238,7 @@ ResourcePathReader.prototype.consumeFollowerSegment = function consumeFollowerSe
|
|
|
244
238
|
inputs.forEach(function (kv) {
|
|
245
239
|
dbSegment.addInputParameter(this.context, kv.name, kv.value);
|
|
246
240
|
}, this);
|
|
247
|
-
//if (keys.length > 0) {
|
|
248
241
|
dbSegment.setKeyValues(keys);
|
|
249
|
-
//}
|
|
250
242
|
|
|
251
243
|
dbSegment.isCollection = keys.length === 0;
|
|
252
244
|
} else {
|
|
@@ -263,13 +255,12 @@ ResourcePathReader.prototype.consumeFollowerSegment = function consumeFollowerSe
|
|
|
263
255
|
}
|
|
264
256
|
|
|
265
257
|
// validate calc view segment and adopt entityType for next segments
|
|
266
|
-
|
|
267
|
-
|
|
258
|
+
const navigation2 = targetEntity.getNavigation(segment.identifier);
|
|
259
|
+
const association2 = this.gModel.getAssociationByName(navigation2.association);
|
|
268
260
|
// ### association is FromCalcViewParameters_to_FromCalcView
|
|
269
261
|
|
|
270
262
|
endTo = this.getTargetEnd(navigation, association2, targetEntity);
|
|
271
|
-
|
|
272
|
-
var entityType2 = this.gModel.getEntityType(endTo.type);
|
|
263
|
+
const entityType2 = this.gModel.getEntityType(endTo.type);
|
|
273
264
|
// ### entityType is FromCalcview
|
|
274
265
|
if (!entityType2) {
|
|
275
266
|
throw new Http404_NotFound("Resource not found for the segment '" + segment.identifier + "' at position " + segment.position + ".");
|
|
@@ -314,7 +305,7 @@ ResourcePathReader.prototype.consumeFollowerSegment = function consumeFollowerSe
|
|
|
314
305
|
* @returns {null|dbSegments.DbSegment}
|
|
315
306
|
*/
|
|
316
307
|
ResourcePathReader.prototype.consumeLinksSegment = function (prevDbSegment) {
|
|
317
|
-
|
|
308
|
+
const segment = this.reduceSegments.shift();
|
|
318
309
|
|
|
319
310
|
if (!segment || !segment.identifier) {
|
|
320
311
|
// E.g. /Teams('1')/$links
|
|
@@ -348,19 +339,19 @@ ResourcePathReader.prototype.consumeLinksSegment = function (prevDbSegment) {
|
|
|
348
339
|
}
|
|
349
340
|
|
|
350
341
|
// Check for navigation property
|
|
351
|
-
|
|
342
|
+
const navigation = prevDbSegment.entityType.getNavigation(segment.identifier);
|
|
352
343
|
if (!navigation) {
|
|
353
344
|
//E.g. /Teams('1')/$links/invalid
|
|
354
345
|
throw new Http404_NotFound("The request URI is not valid. The segment '" + segment.identifier + "' must refer to a navigation property since the previous segment identifier is '$links'.");
|
|
355
346
|
}
|
|
356
347
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
348
|
+
const association = this.getAssociation(navigation);
|
|
349
|
+
const endTo = this.getTargetEnd(navigation, association, prevDbSegment.entityType);
|
|
350
|
+
const endFrom = this.getFromEnd(navigation, association, prevDbSegment.entityType);
|
|
360
351
|
|
|
361
|
-
|
|
352
|
+
const targetEntity = this.gModel.getEntityType(endTo.type);
|
|
362
353
|
|
|
363
|
-
|
|
354
|
+
const dbSegment = new dbSegments.DbSegment(dbSegments.DBS_ResourceNavigation, targetEntity, this.tableCount++);
|
|
364
355
|
prevDbSegment.nextDBSegment = dbSegment;
|
|
365
356
|
dbSegment.previousDBSegment = prevDbSegment;
|
|
366
357
|
dbSegment.association = association;
|
|
@@ -396,13 +387,11 @@ ResourcePathReader.prototype.consumeLinksSegment = function (prevDbSegment) {
|
|
|
396
387
|
prevDbSegment.setOver(association.over);
|
|
397
388
|
}
|
|
398
389
|
|
|
399
|
-
//this.dbSegments.push(dbSegment);
|
|
400
390
|
return dbSegment;
|
|
401
391
|
};
|
|
402
392
|
|
|
403
393
|
ResourcePathReader.prototype.processResourcePath = function () {
|
|
404
|
-
|
|
405
|
-
var lastDBSegment = null;
|
|
394
|
+
let lastDBSegment = null;
|
|
406
395
|
while (this.reduceSegments.length > 0) {
|
|
407
396
|
if (lastDBSegment === null) {
|
|
408
397
|
lastDBSegment = this.consumeFirstSegment();
|
|
@@ -428,7 +417,7 @@ ResourcePathReader.prototype.addExpand = function (dbSeg, expandNavName, expandI
|
|
|
428
417
|
if (dbSeg.isLinks) {
|
|
429
418
|
return;
|
|
430
419
|
}
|
|
431
|
-
|
|
420
|
+
const dbSegNew = this._createNavigationSegment(dbSeg, expandNavName);
|
|
432
421
|
dbSeg.addExpandDbSegment(expandNavName, dbSegNew);
|
|
433
422
|
|
|
434
423
|
// recurse
|
|
@@ -444,18 +433,18 @@ ResourcePathReader.prototype.addExpand = function (dbSeg, expandNavName, expandI
|
|
|
444
433
|
* @private
|
|
445
434
|
*/
|
|
446
435
|
ResourcePathReader.prototype._createNavigationSegment = function (dbSeg, expandNavName) {
|
|
447
|
-
|
|
436
|
+
const navigation = dbSeg.entityType.getNavigation(expandNavName);
|
|
448
437
|
if (!navigation) {
|
|
449
438
|
throw new Http400_BadRequest(`Unknown navigation property '${expandNavName}' in entity type '${dbSeg.entityType.name}'`);
|
|
450
439
|
}
|
|
451
|
-
|
|
440
|
+
const association = this.getAssociation(navigation);
|
|
452
441
|
|
|
453
|
-
|
|
454
|
-
|
|
442
|
+
const endTo = this.getTargetEnd(navigation, association, dbSeg);
|
|
443
|
+
const endFrom = this.getFromEnd(navigation, association, dbSeg);
|
|
455
444
|
|
|
456
|
-
|
|
445
|
+
const targetEntity = this.gModel.getEntityType(endTo.type);
|
|
457
446
|
|
|
458
|
-
|
|
447
|
+
const dbSegNew = new dbSegments.DbSegment(dbSegments.DBS_Navigation, targetEntity, this.tableCount++);
|
|
459
448
|
dbSegNew.previousDBSegment = dbSeg;
|
|
460
449
|
dbSegNew.setFrom(endFrom);
|
|
461
450
|
dbSegNew.setTo(endTo);
|
|
@@ -475,14 +464,13 @@ ResourcePathReader.prototype._createNavigationSegment = function (dbSeg, expandN
|
|
|
475
464
|
ResourcePathReader.prototype.addSelExpTree = function (dbSeg, tree) {
|
|
476
465
|
//first add all known expanded navigation properties
|
|
477
466
|
if (tree.expandAllAvailExpands === true) {
|
|
478
|
-
for (
|
|
467
|
+
for (const expandNavName in tree.availableExpands) {
|
|
479
468
|
if (tree.availableExpands.hasOwnProperty(expandNavName)) {
|
|
480
469
|
this.addExpand(dbSeg, expandNavName, tree.availableExpands[expandNavName]);
|
|
481
470
|
}
|
|
482
471
|
}
|
|
483
472
|
} else {
|
|
484
|
-
for (
|
|
485
|
-
var name = tree.expandNavigations[i];
|
|
473
|
+
for (const name of tree.expandNavigations) {
|
|
486
474
|
this.addExpand(dbSeg, name, tree.availableExpands[name]);
|
|
487
475
|
}
|
|
488
476
|
}
|
|
@@ -492,11 +480,10 @@ ResourcePathReader.prototype.addSelExpTree = function (dbSeg, tree) {
|
|
|
492
480
|
this.checkOtherProperties(dbSeg, tree.properties);
|
|
493
481
|
dbSeg.addAllProperties();
|
|
494
482
|
} else {
|
|
495
|
-
for (
|
|
496
|
-
var selectedProperty = tree.properties[i1];
|
|
483
|
+
for (const selectedProperty of tree.properties) {
|
|
497
484
|
dbSeg.addSelectProperties(selectedProperty);
|
|
498
485
|
if (dbSeg.isNavigationProperty(selectedProperty) && !dbSeg.getRelevantNavigationSegments()[selectedProperty]) {
|
|
499
|
-
|
|
486
|
+
const relevantNavigationSegment = this._createNavigationSegment(dbSeg, selectedProperty);
|
|
500
487
|
dbSeg.addRelevantNavigationSegment(selectedProperty, relevantNavigationSegment);
|
|
501
488
|
}
|
|
502
489
|
}
|
|
@@ -504,10 +491,8 @@ ResourcePathReader.prototype.addSelExpTree = function (dbSeg, tree) {
|
|
|
504
491
|
};
|
|
505
492
|
|
|
506
493
|
ResourcePathReader.prototype.checkOtherProperties = function (dbSeg, properties) {
|
|
507
|
-
|
|
508
|
-
for (
|
|
509
|
-
var propertyName = properties[i1];
|
|
510
|
-
|
|
494
|
+
const entityType = dbSeg.entityType;
|
|
495
|
+
for (const propertyName of properties) {
|
|
511
496
|
if (!(entityType.propertiesMap[propertyName] || entityType.navPropertiesMap[propertyName]) &&
|
|
512
497
|
entityType.keys.generatedKey !== propertyName) {
|
|
513
498
|
throw(new Http400_BadRequest('property "' + propertyName + '" not allowed'));
|
|
@@ -521,9 +506,9 @@ ResourcePathReader.prototype.buildODataTreeTrunk = function () {
|
|
|
521
506
|
|
|
522
507
|
ResourcePathReader.prototype.insertODataNavTreeCrone = function (queryParameters) {
|
|
523
508
|
//first check for the $expend and $select parameters.
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
509
|
+
const expands = queryParameters.expand;
|
|
510
|
+
const selects = queryParameters.select;
|
|
511
|
+
const expSelTree = sel.processExpandSelectTree(expands, selects);
|
|
527
512
|
this.addSelExpTree(this.lastDBSegment, expSelTree);
|
|
528
513
|
if (this.firstDBSegment.isLinks) {
|
|
529
514
|
this.addSelExpTree(this.firstDBSegment, expSelTree);
|
|
@@ -532,7 +517,7 @@ ResourcePathReader.prototype.insertODataNavTreeCrone = function (queryParameters
|
|
|
532
517
|
|
|
533
518
|
ResourcePathReader.prototype.insertQueryParameters = function (queryParameters) {
|
|
534
519
|
//first check for the $expend and $select parameters.
|
|
535
|
-
for (
|
|
520
|
+
for (const name in queryParameters) {
|
|
536
521
|
if (queryParameters.hasOwnProperty(name)) {
|
|
537
522
|
//do checks here
|
|
538
523
|
this.lastDBSegment.systemQueryParameter[name] = queryParameters[name];
|
|
@@ -542,7 +527,7 @@ ResourcePathReader.prototype.insertQueryParameters = function (queryParameters)
|
|
|
542
527
|
|
|
543
528
|
exports.parseResourcePath = function (context, odata) {
|
|
544
529
|
|
|
545
|
-
|
|
530
|
+
const resourcePathReader = new ResourcePathReader(context, odata.segments);
|
|
546
531
|
// Creates the dbSegment line from the URI up to the "?"
|
|
547
532
|
resourcePathReader.buildODataTreeTrunk();
|
|
548
533
|
// Evaluate the $select and $expand system query parameter and build a tree
|
|
@@ -574,7 +559,7 @@ exports.parseResourcePath = function (context, odata) {
|
|
|
574
559
|
};
|
|
575
560
|
}
|
|
576
561
|
// The corresponding association for the given request will be needed many times for custom exits processing
|
|
577
|
-
|
|
562
|
+
const association = odata.dbSegmentLast.association;
|
|
578
563
|
odata.links.association = association;
|
|
579
564
|
if (odata.dbSegmentLast.entityType.name === association.principal.type) {
|
|
580
565
|
odata.links.principal = odata.dbSegmentLast;
|
package/lib/uri/uriType.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const oDataUriParser = require('../../lib/uri/oDataUriParser');
|
|
4
|
+
const DBSegment = require('../db/dbSegment');
|
|
5
5
|
|
|
6
6
|
exports.URI0 = 0; // scheme serviceRoot
|
|
7
7
|
exports.URI1 = 1; // scheme serviceRoot "/" entitySet
|
|
@@ -34,8 +34,8 @@ exports.UNKNOWN_URI = -1; // "fallback" uri type, which is used when uri type ca
|
|
|
34
34
|
* @returns {number} OData URI type (e.g. URI1 having number value of 1).
|
|
35
35
|
*/
|
|
36
36
|
exports.determineUriType = function determineUriType(context) {
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
const uriKind = context.oData.kind;
|
|
38
|
+
let dbSegmentLast,
|
|
39
39
|
isCollection,
|
|
40
40
|
isCount,
|
|
41
41
|
isValue,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const ModelFileError = require('./errors/modelFileError');
|
|
4
4
|
|
|
5
5
|
function clone(objectToClone) {
|
|
6
6
|
return JSON.parse(JSON.stringify(objectToClone));
|
|
@@ -16,7 +16,7 @@ module.exports = {
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
function getTargetEnd(navigation, association, entityType) {
|
|
19
|
-
|
|
19
|
+
let ret = null;
|
|
20
20
|
if (!navigation.from) {
|
|
21
21
|
if (association.principal.type === association.dependent.type) {
|
|
22
22
|
throw new ModelFileError('No "from" clause given', context);
|
|
@@ -43,7 +43,7 @@ function getTargetEnd(navigation, association, entityType) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function getFromEnd(navigation, association, entityType) {
|
|
46
|
-
|
|
46
|
+
let ret = null;
|
|
47
47
|
if (!navigation.from) {
|
|
48
48
|
if (association.principal.type === association.dependent.type) {
|
|
49
49
|
throw new ModelFileError('No "from" clause given', context);
|
|
@@ -71,7 +71,7 @@ function getFromEnd(navigation, association, entityType) {
|
|
|
71
71
|
|
|
72
72
|
function makeStringCreator(getAssociationEnd) {
|
|
73
73
|
return function createAssociationEndString(navigation, association, entityType) {
|
|
74
|
-
|
|
74
|
+
const associationEnd = getAssociationEnd(navigation, association, entityType);
|
|
75
75
|
return associationEnd.type + createPrincipalDependantString(associationEnd, association);
|
|
76
76
|
};
|
|
77
77
|
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
3
|
+
const async = require('async');
|
|
4
|
+
|
|
5
|
+
const applyUriChecks = require('./../../uri/applyChecks');
|
|
6
|
+
const authorizationProcessor = require('./../../processor/authorizationProcessor');
|
|
7
|
+
const batchConst = require('./batchConst');
|
|
8
|
+
const configuration = require('./../../configuration');
|
|
9
|
+
const errorProcessor = require('./../../processor/errorProcessor');
|
|
10
|
+
const json = require('./../../serializer/jsonSerializer');
|
|
11
|
+
const metadataDbReader = require('./../../model/metadataReader');
|
|
12
|
+
const oDataUriParser = require('./../../uri/oDataUriParser');
|
|
13
|
+
const oDataProcessor = require('./../../processor/processor');
|
|
14
|
+
const uriChecks = require('./../../uri/checks');
|
|
15
|
+
const uriKeyValueParser = require('./../../parsers/uriKeyValue');
|
|
16
|
+
const uriProcessor = require('./../../http/uriParser');
|
|
17
|
+
const utils = require('./../utils');
|
|
18
|
+
const xsodataFileReader = require('./../../model/xsodataReader');
|
|
19
|
+
|
|
20
|
+
const ConditionalHttpHandler = require('./../../http/conditionalHttpHandler');
|
|
21
|
+
const DebugInfo = require('./../errors/debugInfo');
|
|
22
|
+
const RequestContext = require('./../requestContext');
|
|
23
|
+
const TestError = require('./../errors/testError');
|
|
24
24
|
|
|
25
25
|
exports.processPrePostCommitRun = function (request, response, batchContext, context, done) {
|
|
26
26
|
context.logger.silly('batchProcessor', 'processPrePostCommitRun');
|
|
@@ -38,7 +38,7 @@ exports.processPrePostCommitRun = function (request, response, batchContext, con
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
if (err instanceof DebugInfo) {
|
|
41
|
-
|
|
41
|
+
const serializer = new json.JsonSerializer(context, 65536, 200);
|
|
42
42
|
serializer.write(err.message);
|
|
43
43
|
serializer.flush();
|
|
44
44
|
} else {
|
|
@@ -72,8 +72,8 @@ exports.processPrePostCommitRun = function (request, response, batchContext, con
|
|
|
72
72
|
// STEP batch create tables --> after createNewContentIdFromRecordMapFromPayload
|
|
73
73
|
// move the contentId information to app.contentID which is an link to the corresponding id in part.contentIds
|
|
74
74
|
function fillContentID(context, asyncDone) {
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
const batchContext = context.batchContext;
|
|
76
|
+
const app = context.app;
|
|
77
77
|
if (batchContext.inChangeSet) {
|
|
78
78
|
|
|
79
79
|
if (app.contentId) {
|
|
@@ -90,12 +90,12 @@ function fillContentID(context, asyncDone) {
|
|
|
90
90
|
// (in the process step) this key values values must be updated with the calculated values.
|
|
91
91
|
// Updated are only the values in the dbsegment, not in the Uri, also reparsing the Uri MUST be avoided.
|
|
92
92
|
function updateContextIdKeyValues(context, asyncDone) {
|
|
93
|
-
|
|
93
|
+
const batchContext = context.batchContext;
|
|
94
94
|
if (!batchContext.inChangeSet) {
|
|
95
95
|
return asyncDone(null, context);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
let updateDbSegment = null;
|
|
99
99
|
const firstSegment = context.oData.dbSegment;
|
|
100
100
|
if (firstSegment.isLinks === true) {
|
|
101
101
|
// no error if there is only one segment or it is a $links segment and there is only one more segment after the $links segment
|
|
@@ -110,32 +110,30 @@ function updateContextIdKeyValues(context, asyncDone) {
|
|
|
110
110
|
updateDbSegment = firstSegment;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
const part = batchContext.processedPart;
|
|
114
|
+
const contentIds = part.contentIds.list;
|
|
115
115
|
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
const contentIdInfo = findContentIdInfo(context.request.urlOrig, contentIds);
|
|
118
118
|
if (!contentIdInfo) {
|
|
119
119
|
return asyncDone(null, context);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
const newKeyNV = contentIdInfo.key_nv;
|
|
123
|
+
const newKeysNames = Object.keys(newKeyNV);
|
|
124
124
|
|
|
125
125
|
// instead of rewriting the uri and reparsing the uri, the already parsed keys are directly modified
|
|
126
126
|
if (newKeysNames.length !== updateDbSegment._KeyValues.length) {
|
|
127
127
|
return asyncDone(new Error('The key list of the referenced ContentIDs must fit to the parsed key list'), context);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
let keyName;
|
|
131
|
+
let i;
|
|
132
|
+
let newValue, newValueUri, newValueParsed;
|
|
133
133
|
for (i = 0; i < updateDbSegment._KeyValues.length; i++) {
|
|
134
134
|
keyName = updateDbSegment._KeyValues[i].name;
|
|
135
|
-
keyProperty = updateDbSegment.entityType.propertiesMap[keyName];
|
|
136
|
-
oldValue = updateDbSegment._KeyValues[i].value;
|
|
137
135
|
newValue = newKeyNV[keyName];
|
|
138
|
-
newValueUri = newValue;
|
|
136
|
+
newValueUri = newValue;
|
|
139
137
|
|
|
140
138
|
if (newKeyNV[keyName] === undefined) {
|
|
141
139
|
return asyncDone(new Error('The key ' + keyName + 'has not been set by the referenced request'), context);
|
|
@@ -149,8 +147,8 @@ function updateContextIdKeyValues(context, asyncDone) {
|
|
|
149
147
|
|
|
150
148
|
|
|
151
149
|
function findContentIdInfo(urlOrig, contentIds) {
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
let contentIdName;
|
|
151
|
+
let contentIdIndex;
|
|
154
152
|
for (contentIdIndex = 0; contentIdIndex < contentIds.length; contentIdIndex++) {
|
|
155
153
|
contentIdName = '$' + contentIds[contentIdIndex].id;
|
|
156
154
|
if (urlOrig.indexOf(contentIdName) > -1) {
|
|
@@ -167,19 +165,19 @@ function findContentIdInfo(urlOrig, contentIds) {
|
|
|
167
165
|
function replaceUriContendIds(context, asyncDone) {
|
|
168
166
|
context.logger.silly('batchExecutor', 'check uri for contentID');
|
|
169
167
|
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
let uri = context.request.url;
|
|
169
|
+
const batchContext = context.batchContext;
|
|
172
170
|
if (!batchContext.inChangeSet) {
|
|
173
171
|
return asyncDone(null, context);
|
|
174
172
|
}
|
|
175
|
-
|
|
176
|
-
|
|
173
|
+
const part = batchContext.processedPart;
|
|
174
|
+
const contentIds = part.contentIds.list;
|
|
177
175
|
|
|
178
|
-
|
|
179
|
-
for (
|
|
180
|
-
id = '$' +
|
|
176
|
+
let id;
|
|
177
|
+
for (const contentId of contentIds) {
|
|
178
|
+
id = '$' + contentId.id;
|
|
181
179
|
if (uri.indexOf(id) > -1) {
|
|
182
|
-
uri = uri.replace(id,
|
|
180
|
+
uri = uri.replace(id, contentId.value);
|
|
183
181
|
}
|
|
184
182
|
}//TODO add check if not all $ are replaced
|
|
185
183
|
|
|
@@ -195,7 +193,7 @@ exports.processCreateTables = function (app, request, response, batchContext, do
|
|
|
195
193
|
'batchExecutor', 'process step: ' + batchContext.status + ' ' + batchConst.runStateText[batchContext.status]
|
|
196
194
|
);
|
|
197
195
|
|
|
198
|
-
|
|
196
|
+
const context = new RequestContext(
|
|
199
197
|
batchContext.parentContext.networkContext,
|
|
200
198
|
batchContext.parentContext.networkContext.requestOptions
|
|
201
199
|
);
|
|
@@ -240,7 +238,7 @@ exports.processCreateTables = function (app, request, response, batchContext, do
|
|
|
240
238
|
}
|
|
241
239
|
}
|
|
242
240
|
if (err instanceof DebugInfo) {
|
|
243
|
-
|
|
241
|
+
const serializer = new json.JsonSerializer(context, 65536, 200);
|
|
244
242
|
serializer.write(err.message);
|
|
245
243
|
serializer.flush();
|
|
246
244
|
} else {
|
|
@@ -274,7 +272,7 @@ exports.processCreateTables = function (app, request, response, batchContext, do
|
|
|
274
272
|
exports.process = function (request, response, batchContext, context, done) {
|
|
275
273
|
context.logger.silly('batchExecutor', 'process step: ' + batchContext.status + ' ' + batchConst.runStateText[batchContext.status]);
|
|
276
274
|
|
|
277
|
-
|
|
275
|
+
const app = context.app;
|
|
278
276
|
|
|
279
277
|
try {
|
|
280
278
|
async.waterfall(
|
|
@@ -294,7 +292,7 @@ exports.process = function (request, response, batchContext, context, done) {
|
|
|
294
292
|
}
|
|
295
293
|
}
|
|
296
294
|
if (err instanceof DebugInfo) {
|
|
297
|
-
|
|
295
|
+
const serializer = new json.JsonSerializer(context, 65536, 200);
|
|
298
296
|
serializer.write(err.message);
|
|
299
297
|
serializer.flush();
|
|
300
298
|
} else {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const generatedKey = require('./../keyGenerator');
|
|
5
|
+
const NotSupported = require('./../errors/http/notSupported');
|
|
6
6
|
exports.Batch = Batch;
|
|
7
7
|
function Batch(type) {
|
|
8
8
|
this.type = type;
|
|
@@ -24,7 +24,7 @@ Batch.prototype.write = function (context, response) {
|
|
|
24
24
|
this.changeSetErrorResponse.writeToBatchResponse(response);
|
|
25
25
|
} else {
|
|
26
26
|
response.statusCode = 200;
|
|
27
|
-
|
|
27
|
+
const boundary = 'batch_' + generatedKey.createBoundary(context);
|
|
28
28
|
if (this.isChangeSet) {
|
|
29
29
|
response.write('Content-Type: multipart/mixed; boundary=' + boundary + '\r\n');
|
|
30
30
|
response.write('\r\n'); //end of header
|
|
@@ -33,7 +33,7 @@ Batch.prototype.write = function (context, response) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
response.write('--' + boundary + '\r\n');
|
|
36
|
-
for (
|
|
36
|
+
for (let i = 0; i < this.parts.length; i++) {
|
|
37
37
|
if (i !== 0) {
|
|
38
38
|
response.write('\r\n--' + boundary + '\r\n');
|
|
39
39
|
}
|
|
@@ -90,13 +90,13 @@ exports.BatchContent = BatchContent;
|
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
function split(input) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
const LF = '\n';
|
|
94
|
+
const CRLF = '\r\n';
|
|
95
|
+
const a = [];
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
let pL = 0;
|
|
98
|
+
let p1 = input.indexOf(CRLF, pL);
|
|
99
|
+
let p2 = input.indexOf(LF, pL);
|
|
100
100
|
|
|
101
101
|
while (p1 !== -1 || p2 !== -1) {
|
|
102
102
|
if (p1 !== -1 && p1 <= p2) {
|