@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
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
const async = require('async');
|
|
4
|
+
const connect = require('../db/connect');
|
|
5
|
+
const contentIdHelper = require('./contentIdHelper');
|
|
6
|
+
const contentTypeCheck = require('./../utils/checkContentType');
|
|
7
|
+
const dataCollectorGet = require('./../sql/dataCollectorGet');
|
|
8
|
+
const dataCollectorPut = require('./../sql/dataCollectorPut');
|
|
9
|
+
const exitProcessor = require('./exitProcessor');
|
|
10
|
+
const serializer = require('./../serializer/serializer');
|
|
11
|
+
const sqlPut = require('./../sql/createPutStatements');
|
|
12
|
+
const utils = require('./../utils/utils');
|
|
13
|
+
|
|
14
|
+
const AtomXmlSerializer = require('./../serializer/atomXmlToJsonSerializer');
|
|
15
|
+
const BadRequestError = require('./../utils/errors/http/badRequest');
|
|
16
|
+
const InternalError = require('./../utils/errors/internalError');
|
|
17
|
+
const UnsupportedMediaType = require('./../utils/errors/http/unsupportedMediaType');
|
|
18
18
|
|
|
19
19
|
function movePayloadToDbSegment_RecordNV(context, asyncDone) {
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const req = context.request;
|
|
22
|
+
const contentType = req.headers['content-type'];
|
|
23
23
|
|
|
24
24
|
try {
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ function movePayloadToDbSegment_RecordNV(context, asyncDone) {
|
|
|
27
27
|
|
|
28
28
|
if (contentType) {
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
const isSupportedContentType = contentTypeCheck.isSupportedContentType(contentType);
|
|
31
31
|
|
|
32
32
|
if (isSupportedContentType === false) {
|
|
33
33
|
throw new UnsupportedMediaType('Content-Type ' + contentType + ' not supported.');
|
|
@@ -54,15 +54,15 @@ function movePayloadToDbSegment_RecordNV(context, asyncDone) {
|
|
|
54
54
|
}
|
|
55
55
|
try {
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
const dbSeg = context.oData.dbSegmentLast;
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
const data = buffer.toString('utf-8');
|
|
60
60
|
|
|
61
61
|
if (contentTypeCheck.isContentTypeXml(contentType) === true && utils.isXml(data) === true) {
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
const typeModel = dbSeg.entityType.propertiesMap;
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
const serializer = new AtomXmlSerializer(data, typeModel);
|
|
66
66
|
|
|
67
67
|
return serializer.serialize(function (err, innerContext) {
|
|
68
68
|
|
|
@@ -71,17 +71,17 @@ function movePayloadToDbSegment_RecordNV(context, asyncDone) {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
if (!Array.isArray(innerContext.result)) {
|
|
74
|
-
|
|
74
|
+
const err1 = InternalError("Serialization result is not an array", context);
|
|
75
75
|
return asyncDone(err1, context);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
const len = innerContext.result.length;
|
|
79
79
|
if (len !== 1) {
|
|
80
|
-
|
|
80
|
+
const err2 = InternalError("Serialization result length must be 1 but is " + len, context);
|
|
81
81
|
return asyncDone(err2, context);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
const result = innerContext.result[0];
|
|
85
85
|
|
|
86
86
|
dbSeg.setRecordFromPutPayload(context, result);
|
|
87
87
|
|
|
@@ -92,7 +92,7 @@ function movePayloadToDbSegment_RecordNV(context, asyncDone) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
if (contentTypeCheck.isContentTypeJson(contentType) === true) {
|
|
95
|
-
|
|
95
|
+
let json;
|
|
96
96
|
|
|
97
97
|
try {
|
|
98
98
|
json = JSON.parse(data);
|
|
@@ -116,17 +116,13 @@ function movePayloadToDbSegment_RecordNV(context, asyncDone) {
|
|
|
116
116
|
} catch (err) {
|
|
117
117
|
return asyncDone(err, context);
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
return asyncDone(null, context);
|
|
121
119
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
120
|
}
|
|
125
121
|
|
|
126
122
|
|
|
127
123
|
function eventBefore(context, asyncDone) {
|
|
128
124
|
context.logger.info('update', 'event start before');
|
|
129
|
-
|
|
125
|
+
const eventFunction = exitProcessor.eventHandler('before', 'update');
|
|
130
126
|
eventFunction(context, function (err, context) {
|
|
131
127
|
context.logger.info('modify event end', 'before');
|
|
132
128
|
if (err) {
|
|
@@ -138,7 +134,7 @@ function eventBefore(context, asyncDone) {
|
|
|
138
134
|
|
|
139
135
|
function eventAfter(context, asyncDone) {
|
|
140
136
|
context.logger.info('update', 'event start after');
|
|
141
|
-
|
|
137
|
+
const eventFunction = exitProcessor.eventHandler('after', 'update');
|
|
142
138
|
eventFunction(context, function (err, context) {
|
|
143
139
|
context.logger.info('modify event end', 'after');
|
|
144
140
|
if (err) {
|
|
@@ -150,7 +146,7 @@ function eventAfter(context, asyncDone) {
|
|
|
150
146
|
|
|
151
147
|
function eventPreCommit(context, asyncDone) {
|
|
152
148
|
context.logger.info('update', 'event start precommit');
|
|
153
|
-
|
|
149
|
+
const eventFunction = exitProcessor.eventHandler('precommit', 'update');
|
|
154
150
|
eventFunction(context, function (err, context) {
|
|
155
151
|
context.logger.info('modify event end', 'precommit');
|
|
156
152
|
if (err) {
|
|
@@ -162,7 +158,7 @@ function eventPreCommit(context, asyncDone) {
|
|
|
162
158
|
|
|
163
159
|
function eventPostCommit(context, asyncDone) {
|
|
164
160
|
context.logger.info('update', 'event start postcommit');
|
|
165
|
-
|
|
161
|
+
const eventFunction = exitProcessor.eventHandler('postcommit', 'update');
|
|
166
162
|
eventFunction(context, function (err, context) {
|
|
167
163
|
context.logger.info('modify event end', 'postcommit');
|
|
168
164
|
if (err) {
|
|
@@ -173,9 +169,9 @@ function eventPostCommit(context, asyncDone) {
|
|
|
173
169
|
}
|
|
174
170
|
|
|
175
171
|
function insertTmpTableToRealTables(context, asyncDone) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
172
|
+
const dbSeg = context.oData.dbSegmentLast;
|
|
173
|
+
const entityType = dbSeg.entityType;
|
|
174
|
+
const create = (entityType.modifications || {}).update || {};
|
|
179
175
|
|
|
180
176
|
if (create.using) {
|
|
181
177
|
exitProcessor.executeExit(create.using, 'using', 'update', context, asyncDone);
|
|
@@ -232,7 +228,7 @@ exports.process = function (context, asyncDone) {
|
|
|
232
228
|
],
|
|
233
229
|
function (err, context) {
|
|
234
230
|
if (err) {
|
|
235
|
-
|
|
231
|
+
const dbClient = context.db.client;
|
|
236
232
|
if (dbClient) {
|
|
237
233
|
//ROLLBack the changes
|
|
238
234
|
return connect.dbRollback(context, dbClient, function (errDB) {
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
const async = require('async');
|
|
4
|
+
const connect = require('../db/connect');
|
|
5
|
+
const sqlPutPostLinks = require('./../sql/createPutPostLinksStatements');
|
|
6
|
+
const dataCollectorLinks = require('./../sql/dataCollectorLinks');
|
|
7
|
+
const dataCollectorPutPostLinks = require('./../sql/dataCollectorPutPostLinks');
|
|
8
|
+
const DBSegment = require('./../db/dbSegment');
|
|
9
|
+
const serializer = require('./../serializer/serializer');
|
|
10
|
+
const exitProcessor = require('./exitProcessor');
|
|
11
|
+
const utils = require('./../utils/utils');
|
|
12
|
+
const contenTypeCheck = require('./../utils/checkContentType');
|
|
13
|
+
const oDataSegmentParser = require('../parsers/jison_segment_parser');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
const UnsupportedMediaType = require('./../utils/errors/http/unsupportedMediaType');
|
|
17
|
+
const BadRequest = require('./../utils/errors/http/badRequest');
|
|
18
18
|
|
|
19
19
|
function movePayloadToDbSegment(context, asyncDone) {
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const req = context.request;
|
|
22
|
+
const contentType = req.headers['content-type'];
|
|
23
23
|
|
|
24
24
|
try {
|
|
25
25
|
context.logger.silly('resourceProcessorPutPostLinks', 'movePayloadToDbSegment');
|
|
@@ -75,7 +75,6 @@ function movePayloadToDbSegment(context, asyncDone) {
|
|
|
75
75
|
} catch (err) {
|
|
76
76
|
return asyncDone(err, context);
|
|
77
77
|
}
|
|
78
|
-
return asyncDone(null, context);
|
|
79
78
|
}
|
|
80
79
|
}
|
|
81
80
|
|
|
@@ -91,8 +90,8 @@ function getKeyFromPostPutDeleteLinksUrl(linksPayload, refEntity, baseUrl) {
|
|
|
91
90
|
throw new BadRequest('Error in Payload: Missing URI parameter');
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
|
|
95
|
-
for (
|
|
93
|
+
let count = 0;
|
|
94
|
+
for (const p in linksPayload) {
|
|
96
95
|
if (linksPayload.hasOwnProperty(p)) {
|
|
97
96
|
count++;
|
|
98
97
|
}
|
|
@@ -103,9 +102,9 @@ function getKeyFromPostPutDeleteLinksUrl(linksPayload, refEntity, baseUrl) {
|
|
|
103
102
|
|
|
104
103
|
linksPayload.uri = decodeURIComponent(linksPayload.uri);
|
|
105
104
|
|
|
106
|
-
|
|
105
|
+
const lastSegIndexBegin = linksPayload.uri.lastIndexOf("/");
|
|
107
106
|
if (lastSegIndexBegin > 0) { // Absolute URL
|
|
108
|
-
|
|
107
|
+
const payloadBaseUrl = linksPayload.uri.substring(0, lastSegIndexBegin + 1);
|
|
109
108
|
if (payloadBaseUrl !== baseUrl) {
|
|
110
109
|
throw new BadRequest('Error in Payload: The base URL does not match the request base URL.');
|
|
111
110
|
}
|
|
@@ -129,7 +128,7 @@ function getKeyFromPostPutDeleteLinksUrl(linksPayload, refEntity, baseUrl) {
|
|
|
129
128
|
|
|
130
129
|
function eventBefore(context, asyncDone) {
|
|
131
130
|
context.logger.info(context.oData.links.sOperation, 'event start before');
|
|
132
|
-
|
|
131
|
+
const eventFunction = exitProcessor.eventHandler('before', context.oData.links.sOperation);
|
|
133
132
|
eventFunction(context, function (err, context) {
|
|
134
133
|
context.logger.info('modify event end', 'before');
|
|
135
134
|
if (err) {
|
|
@@ -141,7 +140,7 @@ function eventBefore(context, asyncDone) {
|
|
|
141
140
|
|
|
142
141
|
function eventAfter(context, asyncDone) {
|
|
143
142
|
context.logger.info(context.oData.links.sOperation, 'event start after');
|
|
144
|
-
|
|
143
|
+
const eventFunction = exitProcessor.eventHandler('after', context.oData.links.sOperation);
|
|
145
144
|
eventFunction(context, function (err, context) {
|
|
146
145
|
context.logger.info('modify event end', 'after');
|
|
147
146
|
if (err) {
|
|
@@ -153,7 +152,7 @@ function eventAfter(context, asyncDone) {
|
|
|
153
152
|
|
|
154
153
|
function eventPrecommit(context, asyncDone) {
|
|
155
154
|
context.logger.info(context.oData.links.sOperation, 'event start precommit');
|
|
156
|
-
|
|
155
|
+
const eventFunction = exitProcessor.eventHandler('precommit', context.oData.links.sOperation);
|
|
157
156
|
eventFunction(context, function (err, context) {
|
|
158
157
|
context.logger.info('modify event end', 'precommit');
|
|
159
158
|
if (err) {
|
|
@@ -165,7 +164,7 @@ function eventPrecommit(context, asyncDone) {
|
|
|
165
164
|
|
|
166
165
|
function eventPostCommit(context, asyncDone) {
|
|
167
166
|
context.logger.info(context.oData.links.sOperation, 'event start postcommit');
|
|
168
|
-
|
|
167
|
+
const eventFunction = exitProcessor.eventHandler('postcommit', context.oData.links.sOperation);
|
|
169
168
|
eventFunction(context, function (err, context) {
|
|
170
169
|
context.logger.info('modify event end', 'postcommit');
|
|
171
170
|
if (err) {
|
|
@@ -176,9 +175,9 @@ function eventPostCommit(context, asyncDone) {
|
|
|
176
175
|
}
|
|
177
176
|
|
|
178
177
|
function insertTmpTableToRealTable(context, asyncDone) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
178
|
+
const dbSeg = context.oData.dbSegmentLast;
|
|
179
|
+
const entityType = dbSeg.entityType;
|
|
180
|
+
const create = (entityType.modifications || {}).update || {};
|
|
182
181
|
|
|
183
182
|
if (create.using) {
|
|
184
183
|
exitProcessor.executeExit(create.using, 'using', context.oData.links.sOperation, context, asyncDone);
|
|
@@ -188,10 +187,10 @@ function insertTmpTableToRealTable(context, asyncDone) {
|
|
|
188
187
|
}
|
|
189
188
|
|
|
190
189
|
function insertTmpTableToRealMNTable(context, asyncDone) {
|
|
191
|
-
|
|
190
|
+
const dbSeg = context.oData.links.toBeUpdated;
|
|
192
191
|
|
|
193
|
-
|
|
194
|
-
|
|
192
|
+
const entityType = dbSeg.entityType;
|
|
193
|
+
const create = (entityType.modifications || {}).create || {};
|
|
195
194
|
if (create.using) {
|
|
196
195
|
exitProcessor.executeExit(create.using, 'using', 'create', context, asyncDone);
|
|
197
196
|
} else {
|
|
@@ -214,8 +213,8 @@ exports.process = function (context, asyncDone) {
|
|
|
214
213
|
context.oData.links.sOperation = 'update';
|
|
215
214
|
}
|
|
216
215
|
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
let execArr;
|
|
217
|
+
const m2n = (context.oData.dbSegmentLast.getOver() !== undefined);
|
|
219
218
|
if (m2n) { // INSERT into 3rd table
|
|
220
219
|
context.oData.dbSegmentLast.m2n = true;
|
|
221
220
|
execArr = [
|
|
@@ -299,7 +298,7 @@ exports.process = function (context, asyncDone) {
|
|
|
299
298
|
execArr,
|
|
300
299
|
function (err, context) {
|
|
301
300
|
if (err) {
|
|
302
|
-
|
|
301
|
+
const dbClient = context.db.client;
|
|
303
302
|
if (dbClient) {
|
|
304
303
|
//ROLLBack the changes
|
|
305
304
|
return connect.dbRollback(context, dbClient, function (errDB) {
|
|
@@ -320,8 +319,8 @@ exports.process = function (context, asyncDone) {
|
|
|
320
319
|
exports.processInBatchCreateTables = function (context, asyncDone) {
|
|
321
320
|
context.logger.silly('resourceProcessorPutPostLinks', 'processInBatchCreateTables');
|
|
322
321
|
|
|
323
|
-
|
|
324
|
-
|
|
322
|
+
let execArr;
|
|
323
|
+
const m2n = (context.oData.dbSegmentLast.getOver() !== undefined);
|
|
325
324
|
if (m2n) { // INSERT into 3rd table
|
|
326
325
|
context.oData.dbSegmentLast.m2n = true;
|
|
327
326
|
execArr = [
|
|
@@ -355,8 +354,8 @@ exports.processInBatchCreateTables = function (context, asyncDone) {
|
|
|
355
354
|
exports.processInBatch = function (context, asyncDone) {
|
|
356
355
|
context.logger.silly('resourceProcessorPutPostLinks', 'processInBatch');
|
|
357
356
|
|
|
358
|
-
|
|
359
|
-
|
|
357
|
+
let execArr;
|
|
358
|
+
const m2n = (context.oData.dbSegmentLast.getOver() !== undefined);
|
|
360
359
|
if (m2n) { // INSERT into 3rd table
|
|
361
360
|
context.oData.dbSegmentLast.m2n = true;
|
|
362
361
|
execArr = [
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const BadRequestError = require("../utils/errors/http/badRequest");
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const xsenv = require('@sap/xsenv');
|
|
6
|
+
const xssec = require("@sap/xssec");
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Validates and extracts the authorization token from OData context without prefixes.
|
|
@@ -40,7 +40,7 @@ exports.getAuthToken = function getAuthToken(context) {
|
|
|
40
40
|
exports.checkScopes = function checkScopes(context, token, scopes, callback) {
|
|
41
41
|
|
|
42
42
|
// The UAA service is read (using xsenv module) from the default-services.json file at root-dir
|
|
43
|
-
|
|
43
|
+
const uaaService = xsenv.getServices({ uaa: { tag: 'xsuaa' } }).uaa || xsenv.getServices({ uaa: 'uaa' }).uaa;
|
|
44
44
|
|
|
45
45
|
xssec.createSecurityContext(token, uaaService, function (err, externalSecurityContext) {
|
|
46
46
|
|
|
@@ -54,7 +54,7 @@ exports.checkScopes = function checkScopes(context, token, scopes, callback) {
|
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
let isAuthorized = true;
|
|
58
58
|
scopes.forEach(function (scope) {
|
|
59
59
|
if (externalSecurityContext.checkLocalScope(scope) !== true) {
|
|
60
60
|
isAuthorized = false;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
const XMLWriter = require('xml-writer');
|
|
3
|
+
const InternalError = require('./../utils/errors/internalError');
|
|
4
|
+
const typeConverter = require('./../utils/typeConverter');
|
|
5
|
+
const dbSegment = require('./../db/dbSegment');
|
|
6
|
+
const Http404_NotFound = require('./../utils/errors/http/notFound');
|
|
7
|
+
const associationsUtil = require('./../utils/associations');
|
|
8
|
+
const NotImplemented = require('./../utils/errors/http/notImplemented');
|
|
9
9
|
|
|
10
10
|
module.exports = AtomSerializer;
|
|
11
11
|
|
|
@@ -31,7 +31,7 @@ function startDocument(xmlWriter) {
|
|
|
31
31
|
AtomSerializer.prototype.serializeFeed = function(dbSegment, inlineCount) {
|
|
32
32
|
startDocument(this._xmlWriter);
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
const feedInfo = createRootFeedInfo(this._context, dbSegment);
|
|
35
35
|
_serializeFeed(this._context, this._xmlWriter, feedInfo, dbSegment, inlineCount);
|
|
36
36
|
|
|
37
37
|
this._xmlWriter.endDocument();
|
|
@@ -46,8 +46,8 @@ AtomSerializer.prototype.serializeFeed = function(dbSegment, inlineCount) {
|
|
|
46
46
|
AtomSerializer.prototype.serializeEntity = function(dbSegment) {
|
|
47
47
|
startDocument(this._xmlWriter);
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const entity = getEntityFromSegment(dbSegment);
|
|
50
|
+
const converters = createConverters(dbSegment);
|
|
51
51
|
_serializeEntry(this._context, this._xmlWriter, dbSegment, entity, converters, createNamespaceAttributes(this._context));
|
|
52
52
|
|
|
53
53
|
this._xmlWriter.endDocument();
|
|
@@ -70,9 +70,9 @@ function _serializeFeed(context, xmlWriter, feedInfo, segment, inlineCount) {
|
|
|
70
70
|
createFeedHeader(context, xmlWriter, feedInfo);
|
|
71
71
|
addInlineCount(xmlWriter, inlineCount);
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
for (
|
|
75
|
-
_serializeEntry(context, xmlWriter, segment,
|
|
73
|
+
const converters = createConverters(segment);
|
|
74
|
+
for (const feedInfoEntry of feedInfo.entries) {
|
|
75
|
+
_serializeEntry(context, xmlWriter, segment, feedInfoEntry, converters);
|
|
76
76
|
}
|
|
77
77
|
xmlWriter.endElement();
|
|
78
78
|
}
|
|
@@ -141,7 +141,7 @@ function _serializeEntry(context, xmlWriter, segment, entity, converters, attrib
|
|
|
141
141
|
* required entity.
|
|
142
142
|
*/
|
|
143
143
|
function getEntityFromSegment(dbSegment) {
|
|
144
|
-
|
|
144
|
+
const entities = dbSegment.getRowsWithGenKey();
|
|
145
145
|
if(!entities || !entities.length || entities.length === 0) {
|
|
146
146
|
throw new Http404_NotFound('Entity not found.');
|
|
147
147
|
}
|
|
@@ -149,9 +149,8 @@ function getEntityFromSegment(dbSegment) {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
function serializeNavigationProperties(context, xmlWriter, segment, entity) {
|
|
152
|
-
for (
|
|
153
|
-
|
|
154
|
-
var navigationSegment = segment.getRelevantNavigationSegments()[selectedNavigation];
|
|
152
|
+
for (const selectedNavigation of segment._SelectedNavigations) {
|
|
153
|
+
const navigationSegment = segment.getRelevantNavigationSegments()[selectedNavigation];
|
|
155
154
|
serializeNavigationProperty(context, xmlWriter, segment, navigationSegment, entity, selectedNavigation);
|
|
156
155
|
}
|
|
157
156
|
}
|
|
@@ -165,14 +164,14 @@ function isNavigationCollection(context, parentSegment, navPropertyName, navigat
|
|
|
165
164
|
return navigationSegment.isCollection;
|
|
166
165
|
}
|
|
167
166
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
const navigation = parentSegment.entityType.getNavigation(navPropertyName);
|
|
168
|
+
const association = context.gModel.getAssociation(navigation.association);
|
|
169
|
+
const targetEnd = associationsUtil.getTargetEnd(navigation, association, parentSegment.entityType);
|
|
171
170
|
return targetEnd.multiplicity === "*";
|
|
172
171
|
}
|
|
173
172
|
|
|
174
173
|
function serializeNavigationProperty(context, xmlWriter, parentSegment, navigationSegment, parentEntity, navPropertyName) {
|
|
175
|
-
|
|
174
|
+
const isCollection = isNavigationCollection(context, parentSegment, navPropertyName, navigationSegment);
|
|
176
175
|
startNavigationLink(xmlWriter, parentSegment, navPropertyName, isCollection, parentEntity);
|
|
177
176
|
|
|
178
177
|
if(navigationSegment && navigationSegment.isExpand && navigationSegment.kind === dbSegment.DBS_Navigation) {
|
|
@@ -197,14 +196,14 @@ function serializeNavigationProperty(context, xmlWriter, parentSegment, navigati
|
|
|
197
196
|
* @returns JSON object containing all the required info for the serialization of the multi-valued navigation property.
|
|
198
197
|
*/
|
|
199
198
|
function createFeedInfoForNavProperty(navPropertyName, navigationSegment, parentSegment, parentEntity) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
const navigationEntities = getNavigationEntities(navigationSegment, parentEntity['1row']);
|
|
200
|
+
const parentEntityHref = createEntityRelativeUrl(parentSegment, parentEntity);
|
|
201
|
+
const feedHref = parentEntityHref + "/" + navPropertyName;
|
|
203
202
|
return createFeedInfo(navPropertyName, feedHref, navigationEntities);
|
|
204
203
|
}
|
|
205
204
|
|
|
206
205
|
function serializeNavigationCollection(context, xmlWriter, navPropertyName, navigationSegment, parentSegment, parentEntity) {
|
|
207
|
-
|
|
206
|
+
const feedInfo = createFeedInfoForNavProperty(navPropertyName, navigationSegment, parentSegment, parentEntity);
|
|
208
207
|
if(feedInfo.entries.length === 0) {
|
|
209
208
|
return;
|
|
210
209
|
}
|
|
@@ -213,14 +212,14 @@ function serializeNavigationCollection(context, xmlWriter, navPropertyName, navi
|
|
|
213
212
|
}
|
|
214
213
|
|
|
215
214
|
function startNavigationLink(xmlWriter, parentSegment, navPropertyName, isNavigationCollection, parentEntity) {
|
|
216
|
-
|
|
215
|
+
const type = isNavigationCollection ? "feed" : "entry";
|
|
217
216
|
|
|
218
217
|
xmlWriter.startElement('link');
|
|
219
218
|
xmlWriter.writeAttribute('rel', "http://schemas.microsoft.com/ado/2007/08/dataservices/related/" + navPropertyName);
|
|
220
219
|
xmlWriter.writeAttribute('type', "application/atom+xml;type=" + type);
|
|
221
220
|
xmlWriter.writeAttribute('title', navPropertyName);
|
|
222
221
|
|
|
223
|
-
|
|
222
|
+
const parentEntityUrl = createEntityRelativeUrl(parentSegment, parentEntity);
|
|
224
223
|
xmlWriter.writeAttribute('href', parentEntityUrl + '/' + navPropertyName);
|
|
225
224
|
}
|
|
226
225
|
|
|
@@ -230,25 +229,26 @@ function startNavigationLink(xmlWriter, parentSegment, navPropertyName, isNaviga
|
|
|
230
229
|
* @param parentId - ID of the parent entity. i.e. of the entity, which contains the navigation property.
|
|
231
230
|
*/
|
|
232
231
|
function getNavigationEntities(navigationSegment, parentId) {
|
|
233
|
-
|
|
234
|
-
|
|
232
|
+
const entities = navigationSegment.getRowsWithGenKey();
|
|
233
|
+
const navigationEntities = [];
|
|
235
234
|
|
|
236
|
-
|
|
237
|
-
while(
|
|
235
|
+
let navigationEntity = entities[navigationSegment.sql.readPosition];
|
|
236
|
+
while(navigationEntity && (navigationEntity['0row'] === parentId)) {
|
|
238
237
|
navigationEntities.push(navigationEntity);
|
|
239
238
|
navigationSegment.sql.readPosition++;
|
|
239
|
+
navigationEntity = entities[navigationSegment.sql.readPosition];
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
return navigationEntities;
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
function serializeNavigationEntity(context, xmlWriter, navigationSegment, parentId) {
|
|
246
|
-
|
|
246
|
+
const entity = getNavigationEntity(navigationSegment, parentId);
|
|
247
247
|
if(!entity) {
|
|
248
248
|
return;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
|
|
251
|
+
const converters = createConverters(navigationSegment);
|
|
252
252
|
_serializeEntry(context, xmlWriter, navigationSegment, entity, converters);
|
|
253
253
|
}
|
|
254
254
|
|
|
@@ -258,9 +258,8 @@ function serializeNavigationEntity(context, xmlWriter, navigationSegment, parent
|
|
|
258
258
|
* @param parentId - ID of the parent OData entity.
|
|
259
259
|
*/
|
|
260
260
|
function getNavigationEntity(navigationSegment, parentId) {
|
|
261
|
-
|
|
262
|
-
for(
|
|
263
|
-
var entity = entities[i];
|
|
261
|
+
const entities = navigationSegment.getRowsWithGenKey();
|
|
262
|
+
for(const entity of entities) {
|
|
264
263
|
if(entity["0row"] === parentId) {
|
|
265
264
|
return entity;
|
|
266
265
|
}
|
|
@@ -273,11 +272,11 @@ function serializePrimitiveProperties(context, xmlWriter, segment, entity, conve
|
|
|
273
272
|
xmlWriter.writeAttribute("type", "application/xml");
|
|
274
273
|
xmlWriter.startElement("m:properties");
|
|
275
274
|
|
|
276
|
-
|
|
277
|
-
for(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
275
|
+
const selectedProperties = segment.getSelectedPropsWithGenKey();
|
|
276
|
+
for(let i = 0; i < selectedProperties.length; i++) {
|
|
277
|
+
const propertyName = selectedProperties[i];
|
|
278
|
+
const propertyValue = converters[i](entity[propertyName]);
|
|
279
|
+
const propertyType = getEdmPropertyType(segment, propertyName);
|
|
281
280
|
serializeEntityProperty(xmlWriter, propertyName, propertyType, propertyValue);
|
|
282
281
|
}
|
|
283
282
|
|
|
@@ -288,20 +287,20 @@ function serializePrimitiveProperties(context, xmlWriter, segment, entity, conve
|
|
|
288
287
|
function writeCategory(context, xmlWriter, segment) {
|
|
289
288
|
xmlWriter.startElement("category");
|
|
290
289
|
|
|
291
|
-
|
|
290
|
+
const term = context.gModel.getNamespace() + "." + segment.entityType.name + "Type";
|
|
292
291
|
xmlWriter.writeAttribute("term", term);
|
|
293
292
|
xmlWriter.writeAttribute("scheme", "http://schemas.microsoft.com/ado/2007/08/dataservices/scheme");
|
|
294
293
|
xmlWriter.endElement();
|
|
295
294
|
}
|
|
296
295
|
|
|
297
296
|
function getEdmPropertyType(segment, propertyName) {
|
|
298
|
-
|
|
297
|
+
const dbType = getPropertyDBType(segment, propertyName);
|
|
299
298
|
return typeConverter.dbTypeNameToODataTypeName[dbType];
|
|
300
299
|
}
|
|
301
300
|
|
|
302
301
|
function getPropertyDBType(segment, propertyName) {
|
|
303
|
-
|
|
304
|
-
|
|
302
|
+
const entityType = segment.entityType;
|
|
303
|
+
const property = entityType.propertiesMap[propertyName];
|
|
305
304
|
if(property) {
|
|
306
305
|
return property.DATA_TYPE_NAME;
|
|
307
306
|
}
|
|
@@ -335,7 +334,7 @@ function serializeEntityProperty(xmlWriter, propertyName, propertyType, property
|
|
|
335
334
|
* Creates top level XML elements for the Atom entry element.
|
|
336
335
|
*/
|
|
337
336
|
function createEntryHeader(context, xmlWriter, segment, entry) {
|
|
338
|
-
|
|
337
|
+
const entityUrl = createEntityAbsoluteUrl(context, segment, entry);
|
|
339
338
|
xmlWriter.writeElement("id", entityUrl);
|
|
340
339
|
createTitleElement(xmlWriter);
|
|
341
340
|
createAuthorElement(xmlWriter);
|
|
@@ -343,7 +342,7 @@ function createEntryHeader(context, xmlWriter, segment, entry) {
|
|
|
343
342
|
}
|
|
344
343
|
|
|
345
344
|
function createEntityEditLink(xmlWriter, segment, entity) {
|
|
346
|
-
|
|
345
|
+
const entityRelativeUrl = createEntityRelativeUrl(segment, entity);
|
|
347
346
|
createLink(xmlWriter, "edit", segment.entityType.name, entityRelativeUrl);
|
|
348
347
|
}
|
|
349
348
|
|
|
@@ -352,8 +351,8 @@ function createEntityAbsoluteUrl(context, segment, entity) {
|
|
|
352
351
|
}
|
|
353
352
|
|
|
354
353
|
function createEntityRelativeUrl(segment, entity) {
|
|
355
|
-
|
|
356
|
-
|
|
354
|
+
let relativeUrl = segment.entityType.name;
|
|
355
|
+
const keysProperties = segment.getKeysProperties();
|
|
357
356
|
|
|
358
357
|
relativeUrl += '(';
|
|
359
358
|
|
|
@@ -362,7 +361,7 @@ function createEntityRelativeUrl(segment, entity) {
|
|
|
362
361
|
return relativeUrl + ')';
|
|
363
362
|
|
|
364
363
|
function toValues(keyProperty, index, array) {
|
|
365
|
-
|
|
364
|
+
const value = typeConverter.serializeDbValueToUriLiteral(entity[index.toString()]/*keys[index]*/, keyProperty);
|
|
366
365
|
if (array.length === 1) {
|
|
367
366
|
return value;
|
|
368
367
|
}
|
|
@@ -378,19 +377,19 @@ function createConverters(segment) {
|
|
|
378
377
|
}
|
|
379
378
|
|
|
380
379
|
function createRootFeedInfo(context, segment) {
|
|
381
|
-
|
|
382
|
-
|
|
380
|
+
const feedTitle = getLastUriSegment(context);
|
|
381
|
+
const feedInfo = createFeedInfo(feedTitle, feedTitle, segment.getRowsWithGenKey());
|
|
383
382
|
feedInfo.attributes = createNamespaceAttributes(context);
|
|
384
383
|
return feedInfo;
|
|
385
384
|
}
|
|
386
385
|
|
|
387
386
|
function getLastUriSegment(context) {
|
|
388
|
-
|
|
387
|
+
const uriSegments = context.uriTree.segments.decoded;
|
|
389
388
|
return uriSegments[uriSegments.length - 1];
|
|
390
389
|
}
|
|
391
390
|
|
|
392
391
|
function createFeedInfo(title, href, entries) {
|
|
393
|
-
|
|
392
|
+
const feedInfo = {};
|
|
394
393
|
feedInfo.title = title;
|
|
395
394
|
feedInfo.href = href;
|
|
396
395
|
feedInfo.entries = entries;
|
|
@@ -409,7 +408,7 @@ function createNamespaceAttributes(context) {
|
|
|
409
408
|
|
|
410
409
|
function addAttributes(xmlWriter, attributes) {
|
|
411
410
|
/*jshint forin: false */
|
|
412
|
-
for(
|
|
411
|
+
for(const attributeName in attributes) {
|
|
413
412
|
xmlWriter.writeAttribute(attributeName, attributes[attributeName]);
|
|
414
413
|
}
|
|
415
414
|
}
|