@sap/xsodata 7.4.4 → 7.5.5

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 CHANGED
@@ -8,6 +8,33 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
8
8
 
9
9
  ## Unreleased
10
10
 
11
+ ## [7.5.5] - 2022-04-21
12
+
13
+ * On calc view: Stable sort order with $skip and $top usage for subsequent requests via "order by" of key fields in SQL statement
14
+
15
+ ## [7.5.4] - 2022-04-21
16
+
17
+ Build infrastructure fix
18
+
19
+ ## [7.5.1] - [7.5.3] - 2022-04-20
20
+
21
+ Build infrastructure fixes
22
+
23
+ ## [7.5.0] - 2022-03-22
24
+
25
+ * Support of node version 16
26
+ * Update module dependencies
27
+ * Update of system query options and xsodata-settings help text
28
+ * Minor changes: Error reporting
29
+
30
+ ## [7.4.5] - 2021-12-15
31
+
32
+ * Suppress $metadata annotation <code>sap:aggregation-role="dimension"</code> on calculation view property if it is used as description property referenced by annotation <code>sap:text</code> by another property of the calulation view. The annotation is only supressed if the corresponding xsodata-file has <code>settings</code> containing this: <code>noDimensionAnnoOnTextProperty true;</code>
33
+ * Improvements on URI parsing errors:
34
+ * reporting URI resource path character position on parsing error, if possible
35
+ * Invalid navigation property on <code>$expand</code> system query option returns 400 (Bad Request) instead of 500 (Internal Server Error)
36
+ * Removed support for NodeJS version 10
37
+
11
38
  ## [7.4.4] - 2021-07-20
12
39
 
13
40
  * HANA client API usage changed: 'execQuery' used for read requests, change requests remain on 'exec'
package/lib/db/connect.js CHANGED
@@ -238,10 +238,10 @@ function _connectInternal(context, asyncDone) {
238
238
  exports.connect = function (context, asyncDone) {
239
239
  context.db = context.db || {};
240
240
  if (context.db.client && (context.db.connectionInitialized === true)) {
241
- context.logger.debug('connect - db', 'connect already done');
241
+ context.logger.info('connect - db', 'connect already done');
242
242
  return asyncDone(null, context);
243
243
  }
244
- context.logger.debug('connect - db', 'connect');
244
+ context.logger.info('connect - db', 'connect');
245
245
 
246
246
  return _connectInternal(context, function (err) {
247
247
  if (err) {
@@ -268,7 +268,12 @@ exports.disconnect = function (context, cb) {
268
268
  if (context.db.openedConnection) {
269
269
  context.logger.info('connect - db', 'disconnect done');
270
270
  if (context.db.client) {
271
- context.db.client.end();
271
+ context.db.client.end((err) => {
272
+ if (err) {
273
+ context.logger.error('connect - db', `disconnect failed (callback): ${err}`);
274
+ }
275
+ context.logger.info('connect - db', 'disconnect done (callback)');
276
+ });
272
277
  }
273
278
  context.db.openedConnection = false;
274
279
  return cb();
@@ -92,6 +92,13 @@ function DbSegment(kind, entityType, nr) {
92
92
  * @type {Array<String>}
93
93
  */
94
94
  this._SelectedPropertiesOrdered = null;
95
+
96
+ /**
97
+ * For CV: (real) key names with alias
98
+ * @type {Array<String,string>}
99
+ */
100
+ this._aliasedKeyPropertiesOnCalcView = [];
101
+
95
102
  /**
96
103
  * Store names existing of navigation properties
97
104
  * @type {Array<String>}
@@ -247,7 +254,7 @@ DbSegment.prototype.setRecordFromPostPayload = function (context, record) {
247
254
  (modifyBy && key === 'MODIFIED_BY') ||
248
255
  (modifyAt && key === 'MODIFIED_AT'))
249
256
  ) {
250
- throw new BadRequest('The serialized resource has an missing value for member ' + key);
257
+ throw new BadRequest('The serialized resource has a missing value for member ' + key);
251
258
  }
252
259
  }
253
260
  dbValue = null;
@@ -336,7 +343,7 @@ DbSegment.prototype.setRecordFromPutPayload = function (context, record) {
336
343
  // skip optional calc view parameters
337
344
  (this.entityType.propertiesMap[property] && this.entityType.propertiesMap[property].MANDATORY === 0)
338
345
  )) {
339
- throw new BadRequest('The serialized resource has an missing value for member ' + property);
346
+ throw new BadRequest('The serialized resource has a missing value for member ' + property);
340
347
  }
341
348
 
342
349
  }
@@ -593,6 +600,50 @@ DbSegment.prototype.getKeyProperties0123ForSelectAs0123 = function (noTable) {
593
600
  return ret;
594
601
  };
595
602
 
603
+ DbSegment.prototype.getKeyProperties0123ForSelectOnCalcViewAs0123 = function (noTable) {
604
+ let ret = [];
605
+ let keyNames;
606
+ let keyName;
607
+ let property;
608
+ let selectProperty;
609
+ let propertyType;
610
+ let i;
611
+ let j = -1;
612
+
613
+ keyNames = this.entityType.keyNamesOrdered;
614
+
615
+ for (i = 0; i < keyNames.length; i++) {
616
+ keyName = keyNames[i];
617
+ property = this.entityType.propertiesMap[keyName];
618
+ selectProperty = null;
619
+
620
+ if (property.KIND !== EntityType.entityKind.inputParameters) {
621
+ j = j + 1; // for real key properties use numbering: 0,1,2, ... (skip CV input params)
622
+ propertyType = property.aggregate ? null : property.DATA_TYPE_NAME;
623
+ selectProperty = new sqlStatement.SelectProperty(noTable ? null : this._Alias, keyName, propertyType, j.toString());
624
+ ret.push(selectProperty);
625
+ }
626
+ }
627
+ return ret;
628
+ };
629
+
630
+ DbSegment.prototype.setAliasedKeyPropertiesOnCalcView = function(selectProperties) {
631
+ this._aliasedKeyPropertiesOnCalcView = selectProperties;
632
+ };
633
+
634
+ DbSegment.prototype.hasAliasedKeyPropertiesOnCalcView = function() {
635
+ return this._aliasedKeyPropertiesOnCalcView.length !== 0;
636
+ };
637
+
638
+ DbSegment.prototype.getAliasedKeyPropertyOnCalcView = function(propertyName) {
639
+ for (let i = 0; i < this._aliasedKeyPropertiesOnCalcView.length; i++) {
640
+ if (this._aliasedKeyPropertiesOnCalcView[i].property === propertyName) {
641
+ return this._aliasedKeyPropertiesOnCalcView[i];
642
+ }
643
+ }
644
+ return null;
645
+ };
646
+
596
647
  /**
597
648
  * Returns a selectProperty for usage in the select part of sql statements
598
649
  * The property are named "0","1","2",... and have as type the type of the corresponding key ( ordered by position
@@ -649,7 +700,30 @@ DbSegment.prototype.getKeyProperties0123ForOrderBy = function (noTable) {
649
700
  return ret;
650
701
  };
651
702
 
652
- DbSegment.prototype.getKeyPropertiesNotSelectedForSelect = function (noTable) {
703
+ DbSegment.prototype.getKeyProperties0123ForOrderByCalcView = function (noTable) {
704
+ let ret = [];
705
+ let keyName;
706
+ let property;
707
+ let j = -1;
708
+
709
+ let keyNames = this.entityType.keyNamesOrdered;
710
+
711
+ for (let i = 0; i < keyNames.length; i++) {
712
+
713
+ keyName = keyNames[i];
714
+ property = this.entityType.propertiesMap[keyName];
715
+
716
+ if (property.KIND !== EntityType.entityKind.inputParameters) {
717
+ j = j + 1;
718
+ let newSortOrder = new typedObjects.SortOrder(new typedObjects.Property(j.toString(), noTable ? null : this._Alias), 'ASC');
719
+ newSortOrder.setPropertyName(property.COLUMN_NAME);
720
+ ret.push(newSortOrder);
721
+ }
722
+ }
723
+ return ret;
724
+ };
725
+
726
+ DbSegment.prototype.getKeyPropertiesNotSelectedForSelect = function (noTable = undefined, inputParameters = null) {
653
727
  let ret = [];
654
728
  let keyNames;
655
729
  let i;
@@ -659,6 +733,18 @@ DbSegment.prototype.getKeyPropertiesNotSelectedForSelect = function (noTable) {
659
733
 
660
734
  keyNames = this.entityType.keyNamesOrdered;
661
735
 
736
+ // remove input params from key list
737
+ if (inputParameters !== null) {
738
+ for (let inputParameterName in inputParameters) {
739
+ if (inputParameters.hasOwnProperty(inputParameterName)) {
740
+ let indexKeyName = keyNames.indexOf(inputParameterName);
741
+ if (indexKeyName > -1) {
742
+ keyNames.splice(indexKeyName, 1);
743
+ }
744
+ }
745
+ }
746
+ }
747
+
662
748
  for (i = 0; i < keyNames.length; i++) {
663
749
  keyName = keyNames[i];
664
750
  key = this.entityType.propertiesMap[keyName];
@@ -613,7 +613,7 @@ settingscontent = sl:( OWS settingsconfig OWS ";")*
613
613
  return ret;
614
614
  }
615
615
  settingsconfig = s:(settings_meta_cache / settings_content / settings_enable / settings_support /
616
- settings_hints / settings_admindata / settings_limits )
616
+ settings_hints / settings_admindata / settings_limits / settings_noDimensionAnnoOnTextProperty )
617
617
  { return s; }
618
618
  settings_meta_cache = "metadata" MWS ( "cache.control" / "cache-control") MWS qs:quotedstring
619
619
  { return {
@@ -635,6 +635,15 @@ settings_enable = "enable" MWS string
635
635
  { return { name : "enable", value : s }; }
636
636
  settings_support = "support" MWS s:string
637
637
  { return { name : "support", value : s }; }
638
+
639
+ settings_noDimensionAnnoOnTextProperty = "noDimensionAnnoOnTextProperty" MWS s:string
640
+ {
641
+ return {
642
+ name : "noDimensionAnnoOnTextProperty",
643
+ value : s
644
+ };
645
+ }
646
+
638
647
  settings_hints = "hints" MWS hl:("null" / hintlist)
639
648
  {
640
649
  var value = hl === 'null' ? [] : hl
@@ -120,6 +120,9 @@ function setPropertyAggregationRole(entityType, property, propertyAnnotations) {
120
120
  (entityType.kind !== EntityType.entityKind.inputParameters &&
121
121
  (entityType.hasAggregates() || entityType.hasMeasureProperties())
122
122
  ) && entityType.isInBimcDimensionView(property.COLUMN_NAME)) {
123
+ if (property.suppressAnnotationDimension && property.suppressAnnotationDimension === true) {
124
+ return; // property is used as description text for other property: do not add annotation
125
+ }
123
126
  propertyAnnotations["sap:aggregation-role"] = "dimension";
124
127
  }
125
128
  }
@@ -189,6 +189,19 @@ function loadCalcViewInfo(context, entityType, cb) {
189
189
  entityType.setCalculationViewDimensionData(rows, { cube: cubeName }, context.logger); // e.g. sap:label is fill with calculation view dimension data
190
190
  entityType.resolveAggregates();
191
191
 
192
+ entityType.properties.forEach((property) => {
193
+
194
+ // suppressing annotation "sap:aggregation-role" depends on xsodata-file "setting"
195
+ if (entityType._settings.noDimensionAnnoOnTextProperty && entityType._settings.noDimensionAnnoOnTextProperty === 'true') {
196
+ if (property.DESC_NAME && property.DESC_NAME !== property.COLUMN_NAME) {
197
+ for (let i = 0; i < entityType.properties.length; i++) {
198
+ if (entityType.properties[i].COLUMN_NAME === property.DESC_NAME) {
199
+ entityType.properties[i].suppressAnnotationDimension = true;
200
+ }
201
+ }
202
+ }
203
+ }
204
+ });
192
205
 
193
206
  var parameters = entityType.getParameters();
194
207
  if (!parameters) {