@sap/cds 5.4.6 → 5.5.0
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 +208 -2
- package/apis/ql.d.ts +17 -15
- package/app/index.js +1 -1
- package/bin/build/buildTaskEngine.js +26 -42
- package/bin/build/buildTaskFactory.js +6 -10
- package/bin/build/buildTaskHandler.js +2 -4
- package/bin/build/buildTaskProvider.js +3 -1
- package/bin/build/buildTaskProviderFactory.js +9 -15
- package/bin/build/constants.js +15 -3
- package/bin/build/index.js +5 -4
- package/bin/build/mtaUtil.js +8 -11
- package/bin/build/provider/buildTaskHandlerEdmx.js +63 -6
- package/bin/build/provider/buildTaskHandlerInternal.js +2 -34
- package/bin/build/provider/buildTaskProviderInternal.js +16 -42
- package/bin/build/provider/fiori/index.js +13 -24
- package/bin/build/provider/hana/2migration.js +17 -15
- package/bin/build/provider/hana/2tabledata.js +52 -48
- package/bin/build/provider/hana/index.js +27 -25
- package/bin/build/provider/hana/migrationtable.js +91 -67
- package/bin/build/provider/java-cf/index.js +14 -24
- package/bin/build/provider/mtx/index.js +12 -14
- package/bin/build/provider/node-cf/index.js +18 -32
- package/bin/cds.js +5 -5
- package/bin/serve.js +29 -23
- package/bin/version.js +0 -1
- package/lib/compile/etc/_localized.js +4 -9
- package/lib/compile/for/sql.js +5 -2
- package/lib/compile/parse.js +25 -17
- package/lib/compile/to/srvinfo.js +2 -1
- package/lib/connect/bindings.js +2 -1
- package/lib/connect/index.js +48 -49
- package/lib/core/classes.js +1 -1
- package/lib/core/reflect.js +10 -2
- package/lib/deploy.js +26 -23
- package/lib/env/defaults.js +13 -6
- package/lib/env/index.js +73 -78
- package/lib/env/requires.js +38 -19
- package/lib/index.js +9 -10
- package/lib/lazy.js +2 -2
- package/lib/log/index.js +33 -45
- package/lib/log/service/index.js +2 -2
- package/lib/ql/CREATE.js +14 -9
- package/lib/ql/DELETE.js +6 -5
- package/lib/ql/DROP.js +12 -9
- package/lib/ql/INSERT.js +40 -16
- package/lib/ql/Query.js +67 -40
- package/lib/ql/SELECT.js +162 -127
- package/lib/ql/UPDATE.js +74 -42
- package/lib/ql/Whereable.js +77 -87
- package/lib/ql/index.js +36 -24
- package/lib/ql/parse.js +35 -0
- package/lib/req/context.js +44 -8
- package/lib/req/locale.js +7 -7
- package/lib/serve/Service-api.js +21 -14
- package/lib/serve/Service-dispatch.js +28 -12
- package/lib/serve/Transaction.js +22 -10
- package/lib/serve/index.js +16 -11
- package/lib/utils/axios.js +23 -16
- package/lib/utils/data.js +35 -0
- package/lib/utils/tests.js +27 -18
- package/libx/_runtime/audit/generic/personal/access.js +81 -0
- package/libx/_runtime/audit/generic/personal/constants.js +4 -0
- package/libx/_runtime/audit/generic/personal/index.js +50 -0
- package/libx/_runtime/audit/generic/personal/modification.js +138 -0
- package/libx/_runtime/audit/generic/personal/utils.js +186 -0
- package/libx/_runtime/audit/utils/v2.js +10 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +5 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +5 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +5 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +2 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +4 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +7 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +59 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +11 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +6 -10
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +3 -46
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +2 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/createToCQN.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/deleteToCQN.js +4 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectHelper.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +16 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityType.js +6 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/format/RepresentationKind.js +4 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/OdataRequest.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +15 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/OperationValidator.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +8 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +6 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +12 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +1 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +7 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +14 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +13 -13
- package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +2 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +2 -2
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +2 -4
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +4 -2
- package/libx/_runtime/cds-services/services/Service.js +40 -5
- package/libx/_runtime/cds-services/services/utils/columns.js +13 -7
- package/libx/_runtime/cds-services/services/utils/compareJson.js +88 -4
- package/libx/_runtime/cds-services/services/utils/differ.js +24 -6
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +2 -2
- package/libx/_runtime/common/composition/data.js +44 -55
- package/libx/_runtime/common/composition/delete.js +97 -71
- package/libx/_runtime/common/composition/index.js +2 -1
- package/libx/_runtime/common/composition/insert.js +34 -11
- package/libx/_runtime/common/composition/tree.js +119 -92
- package/libx/_runtime/common/composition/update.js +4 -1
- package/libx/_runtime/common/composition/utils.js +1 -3
- package/libx/_runtime/common/constants/draft.js +12 -1
- package/libx/_runtime/common/generic/auth.js +6 -22
- package/libx/_runtime/common/generic/crud.js +14 -13
- package/libx/_runtime/common/generic/input.js +23 -26
- package/libx/_runtime/common/generic/put.js +1 -1
- package/libx/_runtime/common/generic/sorting.js +16 -16
- package/libx/_runtime/common/i18n/index.js +1 -1
- package/libx/_runtime/common/i18n/messages.properties +4 -0
- package/libx/_runtime/common/utils/backlinks.js +12 -5
- package/libx/_runtime/common/utils/cqn.js +6 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +102 -101
- package/libx/_runtime/common/utils/csn.js +47 -4
- package/libx/_runtime/common/utils/data.js +0 -37
- package/libx/_runtime/common/utils/enrichWithKeysFromWhere.js +1 -1
- package/libx/_runtime/common/utils/entityFromCqn.js +7 -24
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +39 -7
- package/libx/_runtime/common/utils/generateOnCond.js +11 -12
- package/libx/_runtime/common/utils/onlyKeysRemain.js +10 -0
- package/libx/_runtime/common/utils/path.js +35 -0
- package/libx/_runtime/common/utils/postProcessing.js +86 -0
- package/libx/_runtime/common/utils/quotingStyles.js +37 -26
- package/libx/_runtime/common/utils/resolveView.js +223 -171
- package/libx/_runtime/common/utils/rewriteAsterisk.js +46 -26
- package/libx/_runtime/common/utils/structured.js +6 -12
- package/libx/_runtime/common/utils/template.js +10 -5
- package/libx/_runtime/common/utils/templateDelimiter.js +1 -0
- package/libx/_runtime/common/utils/templateProcessor.js +22 -30
- package/libx/_runtime/common/utils/union.js +31 -0
- package/libx/_runtime/common/utils/unionCqnTemplate.js +184 -0
- package/libx/_runtime/db/Service.js +1 -1
- package/libx/_runtime/db/data-conversion/timestamp.js +2 -9
- package/libx/_runtime/db/expand/expandCQNToJoin.js +204 -297
- package/libx/_runtime/db/expand/index.js +3 -3
- package/libx/_runtime/db/expand/rawToExpanded.js +36 -7
- package/libx/_runtime/db/generic/index.js +1 -1
- package/libx/_runtime/db/generic/input.js +5 -7
- package/libx/_runtime/db/generic/integrity.js +1 -1
- package/libx/_runtime/db/generic/rewrite.js +2 -10
- package/libx/_runtime/db/generic/update.js +13 -5
- package/libx/_runtime/db/generic/virtual.js +22 -58
- package/libx/_runtime/db/query/delete.js +7 -4
- package/libx/_runtime/db/query/insert.js +6 -4
- package/libx/_runtime/db/query/read.js +13 -20
- package/libx/_runtime/db/query/run.js +4 -1
- package/libx/_runtime/db/query/update.js +5 -4
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +35 -2
- package/libx/_runtime/db/sql-builder/FunctionBuilder.js +17 -2
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +6 -5
- package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +10 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +35 -24
- package/libx/_runtime/db/sql-builder/UpdateBuilder.js +14 -4
- package/libx/_runtime/db/sql-builder/arrayed.js +4 -0
- package/libx/_runtime/db/utils/deep.js +8 -0
- package/libx/_runtime/db/utils/generateAliases.js +2 -1
- package/libx/_runtime/fiori/generic/activate.js +19 -15
- package/libx/_runtime/fiori/generic/before.js +3 -11
- package/libx/_runtime/fiori/generic/cancel.js +1 -1
- package/libx/_runtime/fiori/generic/delete.js +3 -1
- package/libx/_runtime/fiori/generic/edit.js +12 -2
- package/libx/_runtime/fiori/generic/new.js +5 -5
- package/libx/_runtime/fiori/generic/patch.js +0 -18
- package/libx/_runtime/fiori/generic/read.js +241 -189
- package/libx/_runtime/fiori/utils/delete.js +36 -7
- package/libx/_runtime/fiori/utils/handler.js +43 -44
- package/libx/_runtime/fiori/utils/where.js +30 -15
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +4 -6
- package/libx/_runtime/hana/execute.js +2 -2
- package/libx/_runtime/hana/localized.js +4 -4
- package/libx/_runtime/hana/pool.js +29 -14
- package/libx/_runtime/hana/search2cqn4sql.js +2 -1
- package/libx/_runtime/hana/searchToContains.js +18 -14
- package/libx/_runtime/index.js +0 -5
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +13 -5
- package/libx/_runtime/messaging/common-utils/naming-conventions.js +4 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +31 -19
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -2
- package/libx/_runtime/messaging/enterprise-messaging.js +6 -4
- package/libx/_runtime/messaging/service.js +7 -6
- package/libx/_runtime/odata/cqn2odata.js +110 -43
- package/libx/_runtime/odata/index.js +26 -48
- package/libx/_runtime/odata/odata2cqn.js +1 -6154
- package/libx/_runtime/odata/odata2cqn.pegjs +559 -0
- package/libx/_runtime/odata/readToCqn.js +94 -64
- package/libx/_runtime/remote/Service.js +74 -21
- package/libx/_runtime/remote/cqn2odata/index.js +1 -5
- package/libx/_runtime/remote/utils/client.js +24 -101
- package/libx/_runtime/remote/utils/dataConversion.js +27 -12
- package/libx/_runtime/sqlite/Service.js +3 -5
- package/libx/_runtime/sqlite/execute.js +23 -24
- package/libx/_runtime/sqlite/localized.js +12 -7
- package/libx/_runtime/types/api.js +10 -0
- package/package.json +1 -1
- package/server.js +16 -2
- package/lib/ql/grammar.pegjs +0 -208
- package/lib/ql/parser.js +0 -1
- package/lib/ql/rt/DELETE.js +0 -29
- package/lib/ql/rt/INSERT.js +0 -23
- package/lib/ql/rt/Query.js +0 -84
- package/lib/ql/rt/SELECT.js +0 -174
- package/lib/ql/rt/UPDATE.js +0 -119
- package/lib/ql/rt/_helpers.js +0 -91
- package/lib/ql/rt/index.js +0 -32
- package/libx/_runtime/audit/generic/personal.js +0 -260
- package/libx/_runtime/cds-services/statements/BaseStatement.js +0 -72
- package/libx/_runtime/cds-services/statements/Create.js +0 -57
- package/libx/_runtime/cds-services/statements/Delete.js +0 -33
- package/libx/_runtime/cds-services/statements/Drop.js +0 -42
- package/libx/_runtime/cds-services/statements/Insert.js +0 -201
- package/libx/_runtime/cds-services/statements/Select.js +0 -826
- package/libx/_runtime/cds-services/statements/Update.js +0 -181
- package/libx/_runtime/cds-services/statements/Where.js +0 -726
- package/libx/_runtime/cds-services/statements/index.js +0 -25
- package/libx/_runtime/common/generic/resolve-mock.js +0 -9
|
@@ -27,11 +27,8 @@ const _createNavGroupBy = pathSegments => {
|
|
|
27
27
|
let name = pathSegments[0].getNavigationProperty().getName()
|
|
28
28
|
for (let i = 1; i < pathSegments.length; i++) {
|
|
29
29
|
name += pathSegments[i].getProperty()
|
|
30
|
-
? '.
|
|
31
|
-
: '.
|
|
32
|
-
}
|
|
33
|
-
for (let i = 1; i < pathSegments.length; i++) {
|
|
34
|
-
name += '}'
|
|
30
|
+
? '.' + pathSegments[i].getProperty().getName()
|
|
31
|
+
: '.' + pathSegments[i].getNavigationProperty().getName()
|
|
35
32
|
}
|
|
36
33
|
return name
|
|
37
34
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
const { INSERT } =
|
|
1
|
+
const cds = require('../../../../cds')
|
|
2
|
+
const { INSERT } = cds.ql
|
|
3
3
|
|
|
4
4
|
const { getFeatureNotSupportedError } = require('../../../util/errors')
|
|
5
5
|
const { convertUrlPathToCqn } = require('./utils')
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
const { UPDATE, DELETE } =
|
|
1
|
+
const cds = require('../../../../cds')
|
|
2
|
+
const { UPDATE, DELETE } = cds.ql
|
|
3
3
|
|
|
4
4
|
const { getFeatureNotSupportedError } = require('../../../util/errors')
|
|
5
5
|
const { convertUrlPathToCqn } = require('./utils')
|
|
6
6
|
|
|
7
|
-
const { ENTITY, NAVIGATION_TO_ONE } = require('../okra/odata-server').uri.UriResource.ResourceKind
|
|
7
|
+
const { ENTITY, NAVIGATION_TO_ONE, SINGLETON } = require('../okra/odata-server').uri.UriResource.ResourceKind
|
|
8
8
|
|
|
9
9
|
const SUPPORTED_KINDS = {
|
|
10
10
|
[ENTITY]: 1,
|
|
11
|
+
[SINGLETON]: 1,
|
|
11
12
|
[NAVIGATION_TO_ONE]: 1
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -191,10 +191,9 @@ const _getItemCQN = (model, name, navigationProperty, expandItem) => {
|
|
|
191
191
|
orderByToCQN(item, orderBy)
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
// REVISIT: expand on hana (window function) breaks without setting dummy limit
|
|
195
194
|
const top = expandItem.getOption(QueryOptions.TOP)
|
|
196
195
|
if (navigationProperty.isCollection())
|
|
197
|
-
addLimit(item, top != null ? top :
|
|
196
|
+
addLimit(item, top != null ? top : null, expandItem.getOption(QueryOptions.SKIP) || 0)
|
|
198
197
|
|
|
199
198
|
_filter(item, expandItem.getOption(QueryOptions.FILTER))
|
|
200
199
|
|
|
@@ -25,7 +25,6 @@ const deleteToCQN = require('./deleteToCQN')
|
|
|
25
25
|
*/
|
|
26
26
|
module.exports = (component, service, target, data, odataReq, upsert) => {
|
|
27
27
|
const odata2cqn = cds.env.features.odata_new_parser
|
|
28
|
-
if (odata2cqn && !cds.odata) cds.odata = require('../../../../odata')
|
|
29
28
|
|
|
30
29
|
switch (component) {
|
|
31
30
|
case DATA_CREATE_HANDLER:
|
|
@@ -70,7 +70,7 @@ const enhanceCqnWithSubSelects = (cqn, pathSegments, csn, SELECT) => {
|
|
|
70
70
|
let currentCqn
|
|
71
71
|
|
|
72
72
|
if (isLastElement) {
|
|
73
|
-
cqn.
|
|
73
|
+
cqn.SELECT.from = { ref: [entityName], as: tableAlias }
|
|
74
74
|
_addKeysToWhereIfNeeded(cqn, keys, tableAlias)
|
|
75
75
|
} else {
|
|
76
76
|
currentCqn = SELECT.from(`${entityName} as ${tableAlias}`, [1])
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
const { UPDATE } =
|
|
1
|
+
const cds = require('../../../../cds')
|
|
2
|
+
const { UPDATE } = cds.ql
|
|
3
3
|
|
|
4
4
|
const { getFeatureNotSupportedError } = require('../../../util/errors')
|
|
5
5
|
const { isStreaming } = require('../utils/stream')
|
|
@@ -79,34 +79,32 @@ const isSameArray = (arr1, arr2) => {
|
|
|
79
79
|
return arr1.length === arr2.length && arr1.every((element, index) => element === arr2[index])
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
const _getStructKeys = (
|
|
82
|
+
const _getStructKeys = (key, prefix, joinStructured) => {
|
|
83
83
|
const structKeys = []
|
|
84
|
-
for (const
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
for (const keyName in key.elements) {
|
|
85
|
+
const keyElement = key.elements[keyName]
|
|
86
|
+
if (keyElement._isStructured) {
|
|
87
|
+
structKeys.push(..._getStructKeys(keyElement, [...prefix, keyName], joinStructured))
|
|
87
88
|
continue
|
|
88
89
|
}
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
structKeys.push(
|
|
90
|
+
if (keyElement.isAssociation) continue
|
|
91
|
+
const newKey = joinStructured ? [...prefix, keyName].join('_') : [...prefix, keyName]
|
|
92
|
+
structKeys.push(newKey)
|
|
92
93
|
}
|
|
93
|
-
|
|
94
94
|
return structKeys
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
const getAllKeys = entity => {
|
|
97
|
+
const getAllKeys = (entity, joinStructured = true) => {
|
|
98
98
|
const allKeys = []
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
allKeys.push(..._getStructKeys(
|
|
105
|
-
|
|
99
|
+
if (entity && entity.elements) {
|
|
100
|
+
// in elements because of aspects
|
|
101
|
+
for (const keyName in entity.elements) {
|
|
102
|
+
const key = entity.elements[keyName]
|
|
103
|
+
if (!key.key || key.isAssociation || key.isComposition) continue
|
|
104
|
+
if (key._isStructured) allKeys.push(..._getStructKeys(key, [keyName], joinStructured))
|
|
105
|
+
else allKeys.push(keyName)
|
|
106
106
|
}
|
|
107
|
-
allKeys.push(entity.keys[key].name)
|
|
108
107
|
}
|
|
109
|
-
|
|
110
108
|
return allKeys
|
|
111
109
|
}
|
|
112
110
|
|
|
@@ -107,9 +107,12 @@ class EdmEntityType extends AbstractEdmStructuredType {
|
|
|
107
107
|
* @returns {boolean} whether this entity type is a media entity type
|
|
108
108
|
*/
|
|
109
109
|
hasStream () {
|
|
110
|
-
if (this.csdlStructuredType.hasStream) return
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
if (this.csdlStructuredType.hasStream) return true
|
|
111
|
+
if (this.getBaseType() && this.getBaseType().hasStream()) return true
|
|
112
|
+
const streamProp = this.csdlStructuredType &&
|
|
113
|
+
this.csdlStructuredType.properties &&
|
|
114
|
+
this.csdlStructuredType.properties.find(prop => prop.type && prop.type.namespace + '.' + prop.type.name === 'Edm.Stream')
|
|
115
|
+
return !!streamProp
|
|
113
116
|
}
|
|
114
117
|
}
|
|
115
118
|
|
package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/format/RepresentationKind.js
CHANGED
|
@@ -162,7 +162,10 @@ class RepresentationKind {
|
|
|
162
162
|
case ResourceKind.COUNT:
|
|
163
163
|
return RepresentationKind.Kinds.COUNT
|
|
164
164
|
case ResourceKind.VALUE:
|
|
165
|
-
if (uriInfo.getFinalEdmType().getKind() === EdmTypeKind.ENTITY)
|
|
165
|
+
if (uriInfo.getFinalEdmType().getKind() === EdmTypeKind.ENTITY) {
|
|
166
|
+
uriInfo.getLastSegment()._isStreamByDollarValue = true
|
|
167
|
+
return RepresentationKind.Kinds.BINARY
|
|
168
|
+
}
|
|
166
169
|
return uriInfo.getFinalEdmType() === EdmPrimitiveTypeKind.Binary
|
|
167
170
|
? RepresentationKind.Kinds.BINARY
|
|
168
171
|
: RepresentationKind.Kinds.PRIMITIVE_VALUE
|
|
@@ -425,8 +425,21 @@ class SerializerFactory {
|
|
|
425
425
|
const uriInfo = context.getRequest().getUriInfo()
|
|
426
426
|
let type = uriInfo.getFinalEdmType()
|
|
427
427
|
if (type.getKind() === EdmTypeKind.DEFINITION) type = type.getUnderlyingType()
|
|
428
|
-
|
|
429
|
-
|
|
428
|
+
|
|
429
|
+
let propertyOrReturnType
|
|
430
|
+
if (uriInfo.getLastSegment()._isStreamByDollarValue) {
|
|
431
|
+
for (const [propertyName, property] of uriInfo.getLastSegment(-1).getEdmType().getOwnProperties()) {
|
|
432
|
+
if (property.getType() === EdmPrimitiveTypeKind.Stream) {
|
|
433
|
+
propertyOrReturnType = property
|
|
434
|
+
break
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
type = EdmPrimitiveTypeKind.Stream
|
|
438
|
+
} else {
|
|
439
|
+
const segment = uriInfo.getLastSegment(type === EdmPrimitiveTypeKind.Stream ? 0 : -1)
|
|
440
|
+
propertyOrReturnType = segment.getProperty() || (segment.getFunction() || segment.getAction()).getReturnType()
|
|
441
|
+
}
|
|
442
|
+
|
|
430
443
|
let value = data.value
|
|
431
444
|
|
|
432
445
|
if (value === null || value === undefined) {
|
|
@@ -3,7 +3,7 @@ const Dispatcher = require('./Dispatcher')
|
|
|
3
3
|
const cds = require('../../../cds')
|
|
4
4
|
|
|
5
5
|
const to = service => {
|
|
6
|
-
const edm = cds.compile.to.edm(service.model, { service: service.
|
|
6
|
+
const edm = cds.compile.to.edm(service.model, { service: service.definition.name })
|
|
7
7
|
const odata = new OData(edm, service.model, service.options)
|
|
8
8
|
|
|
9
9
|
odata.addCDSServiceToChannel(service)
|
|
@@ -97,7 +97,11 @@ function _entityOrTypeName(navSourceSegment) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
// TODO do it similar for both cases below?
|
|
100
|
-
return (
|
|
100
|
+
return (
|
|
101
|
+
navSourceSegment.getEntitySet()
|
|
102
|
+
? navSourceSegment.getEntitySet()
|
|
103
|
+
: navSourceSegment.getNavigationProperty() || navSourceSegment.getSingleton()
|
|
104
|
+
)
|
|
101
105
|
.getEntityType()
|
|
102
106
|
.getFullQualifiedName()
|
|
103
107
|
}
|
|
@@ -207,6 +211,9 @@ const getData = (component, odataReq, service) => {
|
|
|
207
211
|
}
|
|
208
212
|
|
|
209
213
|
if (component === DATA_DELETE_HANDLER || component === DATA_READ_HANDLER) {
|
|
214
|
+
if (component === DATA_DELETE_HANDLER && lastSegment.getKind() === 'PRIMITIVE.PROPERTY') {
|
|
215
|
+
return Object.assign(keyValues, { [lastSegment.getProperty().getName()]: null })
|
|
216
|
+
}
|
|
210
217
|
return keyValues
|
|
211
218
|
}
|
|
212
219
|
|
|
@@ -3,7 +3,7 @@ const { SELECT } = cds.ql
|
|
|
3
3
|
const { isCustomOperation } = require('./request')
|
|
4
4
|
const expandToCQN = require('../odata-to-cqn/expandToCQN')
|
|
5
5
|
const QueryOptions = require('../okra/odata-server').QueryOptions
|
|
6
|
-
const { COMPLEX_PROPERTY } = require('../okra/odata-server').uri.UriResource.ResourceKind
|
|
6
|
+
const { COMPLEX_PROPERTY, PRIMITIVE_PROPERTY } = require('../okra/odata-server').uri.UriResource.ResourceKind
|
|
7
7
|
|
|
8
8
|
const _selectForFunction = (selectColumns, result, opReturnType) => {
|
|
9
9
|
if (!Array.isArray(result)) result = [result]
|
|
@@ -104,6 +104,11 @@ const resolveStructuredName = (pathSegments, index, nameArr = []) => {
|
|
|
104
104
|
const prop = pathSegments[index].getProperty()
|
|
105
105
|
nameArr.unshift(prop.getName())
|
|
106
106
|
return resolveStructuredName(pathSegments, --index, nameArr)
|
|
107
|
+
} else if (
|
|
108
|
+
pathSegments[index].getKind() === PRIMITIVE_PROPERTY &&
|
|
109
|
+
pathSegments[index - 1].getKind() === COMPLEX_PROPERTY
|
|
110
|
+
) {
|
|
111
|
+
return resolveStructuredName(pathSegments, --index, nameArr)
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
return nameArr
|
|
@@ -10,7 +10,7 @@ const hasOmitValuesPreference = (preferHeader, preference) => {
|
|
|
10
10
|
* omitted from the response payload.
|
|
11
11
|
*
|
|
12
12
|
* @param {import('../okra/odata-server/core/OdataResponse')} response
|
|
13
|
-
* @param {Map | null} omitValuesPreference
|
|
13
|
+
* @param {Map<string, boolean> | null} omitValuesPreference
|
|
14
14
|
*/
|
|
15
15
|
const applyOmitValuesPreference = (response, omitValuesPreference) => {
|
|
16
16
|
if (!omitValuesPreference || omitValuesPreference.size === 0 || !response) return
|
|
@@ -40,20 +40,27 @@ const applyOmitValuesPreference = (response, omitValuesPreference) => {
|
|
|
40
40
|
*
|
|
41
41
|
* **REVISIT**: The handling of delta payloads and instance annotations is not currently
|
|
42
42
|
* implemented, as the runtime does not yet support those features.
|
|
43
|
-
* In the future, you might want to use the `pathSegments` argument for the
|
|
44
|
-
* of delta payloads.
|
|
43
|
+
* In the future, you might want to use the `processArgs.pathSegments` argument for the
|
|
44
|
+
* implementation of delta payloads.
|
|
45
|
+
*
|
|
46
|
+
* @param {import('../../../../types/api').templateProcessorProcessFnArgs} processArgs
|
|
47
|
+
* @param {import('../../../../cds-services/adapter/odata-v4/ODataRequest')} request
|
|
48
|
+
* @param {Map<string, boolean> | null} omitValuesPreference
|
|
49
|
+
* @param {object | undefined} previousRow
|
|
45
50
|
*/
|
|
46
|
-
const omitValue = (request, omitValuesPreference, previousRow
|
|
51
|
+
const omitValue = (processArgs, request, omitValuesPreference, previousRow) => {
|
|
47
52
|
const preferHeader = request.headers.prefer
|
|
48
53
|
if (!preferHeader || !omitValuesPreference) return
|
|
49
54
|
|
|
55
|
+
const { row, key, element, isRoot } = processArgs
|
|
50
56
|
const defaultValue = element.default && element.default.val ? element.default.val : null
|
|
51
57
|
const responseValue = row[key]
|
|
52
58
|
const isDefaultValue = responseValue === defaultValue
|
|
53
59
|
|
|
54
60
|
if (isDefaultValue) {
|
|
55
61
|
// Don't omit the response value if the request is an update operation and it has changed it
|
|
56
|
-
|
|
62
|
+
// REVISIT: We don't have access to deep previous rows, therefore we always ignore default values in deep operations
|
|
63
|
+
if (request.event === 'UPDATE' && isRoot) {
|
|
57
64
|
if (previousRow === undefined) return
|
|
58
65
|
if (responseValue !== previousRow[key]) return
|
|
59
66
|
}
|
|
@@ -3,35 +3,29 @@ const { SELECT } = cds.ql
|
|
|
3
3
|
|
|
4
4
|
const { getDeepSelect } = require('../../../services/utils/handlerUtils')
|
|
5
5
|
const { DRAFT_COLUMNS } = require('../../../../common/constants/draft')
|
|
6
|
-
const { getVirtuals, getVirtualFromTarget, postProcessVirtuals } = require('../../../../db/generic/virtual')
|
|
7
6
|
const { filterKeys } = require('../../../../fiori/utils/handler')
|
|
8
7
|
|
|
9
8
|
const _getColumns = target => {
|
|
10
9
|
const columns = []
|
|
11
10
|
for (const k in target.elements) {
|
|
12
|
-
if (!target.elements[k].isAssociation && !
|
|
11
|
+
if (!target.elements[k].isAssociation && !DRAFT_COLUMNS.includes(k)) columns.push(k)
|
|
13
12
|
}
|
|
14
13
|
return columns
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
module.exports = async (req, srv) => {
|
|
18
17
|
let deepSelect
|
|
19
|
-
let virtuals = []
|
|
20
18
|
if (req.event === 'draftActivate') {
|
|
21
19
|
const where = filterKeys(req.target.keys).reduce((w, k) => {
|
|
22
20
|
w[k] = req.data[k]
|
|
23
21
|
return w
|
|
24
22
|
}, {})
|
|
25
23
|
deepSelect = SELECT.from(req.target).columns(_getColumns(req.target)).where(where)
|
|
26
|
-
virtuals = getVirtualFromTarget(req)
|
|
27
24
|
} else if (req.event === 'UPDATE') {
|
|
28
25
|
deepSelect = SELECT.from(req.query.UPDATE.entity, _getColumns(req.target))
|
|
29
|
-
virtuals = getVirtualFromTarget(req)
|
|
30
26
|
} else {
|
|
31
27
|
deepSelect = getDeepSelect(req)
|
|
32
|
-
virtuals = getVirtuals({ query: deepSelect, target: req.target }, srv.model)
|
|
33
28
|
}
|
|
34
29
|
const result = await cds.tx(req).run(deepSelect)
|
|
35
|
-
postProcessVirtuals(virtuals, result)
|
|
36
30
|
return result
|
|
37
31
|
}
|
|
@@ -33,15 +33,15 @@ const isCustomOperation = (pathSegments, includingBound = true) => {
|
|
|
33
33
|
* Validate resource path length and autoexposed entities.
|
|
34
34
|
* It will throw an error in case the maximum is exceeded or top entity is autoexposed.
|
|
35
35
|
*
|
|
36
|
-
* @param {object}
|
|
37
|
-
* @param {object}
|
|
38
|
-
* @param model
|
|
36
|
+
* @param {object} odataReq
|
|
37
|
+
* @param {object} service
|
|
39
38
|
*/
|
|
40
|
-
const validateResourcePath = (
|
|
41
|
-
const segment =
|
|
39
|
+
const validateResourcePath = (odataReq, service) => {
|
|
40
|
+
const segment = odataReq.getUriInfo().getPathSegments()[0]
|
|
42
41
|
if (segment.getKind() === ENTITY || segment.getKind() === ENTITY_COLLECTION) {
|
|
43
42
|
const name = segment.getEntitySet().getName()
|
|
44
|
-
|
|
43
|
+
// REVISIT: This validation is violating all principles of locality
|
|
44
|
+
const entity = service.model.definitions[`${service.definition.name}.${name}`]
|
|
45
45
|
if (!entity) return
|
|
46
46
|
|
|
47
47
|
/*
|
|
@@ -51,7 +51,7 @@ const validateResourcePath = (req, options, model) => {
|
|
|
51
51
|
*/
|
|
52
52
|
if (entity._isDraftEnabled) return
|
|
53
53
|
if (entity['@cds.autoexposed']) {
|
|
54
|
-
if (entity['@cds.autoexpose'] &&
|
|
54
|
+
if (entity['@cds.autoexpose'] && odataReq.getIncomingRequest().method === 'GET') {
|
|
55
55
|
// combination GET && @cds.autoexposed && @cds.autoexpose is OK
|
|
56
56
|
return
|
|
57
57
|
}
|
|
@@ -71,14 +71,6 @@ const toODataResult = (result, arg) => {
|
|
|
71
71
|
return odataResult
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
const getVirtualsFromResult = ({ elements }, result) => {
|
|
75
|
-
const virtuals = {}
|
|
76
|
-
for (const k in elements) {
|
|
77
|
-
if (elements[k].virtual) virtuals[k] = result[k]
|
|
78
|
-
}
|
|
79
|
-
return virtuals
|
|
80
|
-
}
|
|
81
|
-
|
|
82
74
|
const addEtags = (row, key) => {
|
|
83
75
|
row['*@odata.etag'] = row[key]
|
|
84
76
|
}
|
|
@@ -121,8 +113,14 @@ const addAssociationToRow = (row, foreignKey, foreignKeyElement) => {
|
|
|
121
113
|
delete row[foreignKey]
|
|
122
114
|
}
|
|
123
115
|
|
|
124
|
-
const _processCategory = (category,
|
|
116
|
+
const _processCategory = (category, processArgs, req, options, previousResult) => {
|
|
117
|
+
const { row, key, element } = processArgs
|
|
118
|
+
|
|
125
119
|
switch (category) {
|
|
120
|
+
case '@odata.omitValues':
|
|
121
|
+
omitValue(processArgs, req, options.omitValuesPreference, previousResult)
|
|
122
|
+
break
|
|
123
|
+
|
|
126
124
|
case '@odata.etag':
|
|
127
125
|
addEtags(row, key)
|
|
128
126
|
break
|
|
@@ -143,16 +141,13 @@ const _processCategory = (category, row, key, element, options) => {
|
|
|
143
141
|
}
|
|
144
142
|
}
|
|
145
143
|
|
|
146
|
-
const _processorFn = (req, previousResult, options) =>
|
|
144
|
+
const _processorFn = (req, previousResult, options) => processArgs => {
|
|
145
|
+
const { row, key, plain } = processArgs
|
|
147
146
|
if (typeof row !== 'object' || !Object.prototype.hasOwnProperty.call(row, key)) return
|
|
148
|
-
|
|
149
|
-
omitValue(req, options.omitValuesPreference, previousResult, row, key, element, plain, isRowRoot, pathSegments)
|
|
150
|
-
|
|
151
147
|
const categories = plain.categories
|
|
152
|
-
if (!categories) return
|
|
153
148
|
|
|
154
149
|
for (const category of categories) {
|
|
155
|
-
_processCategory(category,
|
|
150
|
+
_processCategory(category, processArgs, req, options, previousResult)
|
|
156
151
|
}
|
|
157
152
|
}
|
|
158
153
|
|
|
@@ -207,9 +202,8 @@ const _pick = options => (element, target, parent) => {
|
|
|
207
202
|
if (element['@odata.etag']) categories.push('@odata.etag')
|
|
208
203
|
if (element.type === 'cds.Decimal') categories.push('@cds.Decimal')
|
|
209
204
|
categories.push(..._assocs(element, target, parent))
|
|
210
|
-
|
|
205
|
+
if (options.omitValuesPreference) categories.push('@odata.omitValues')
|
|
211
206
|
if (categories.length) return { categories }
|
|
212
|
-
if (options.omitValuesPreference) return true
|
|
213
207
|
}
|
|
214
208
|
|
|
215
209
|
const _getPostProcessOptions = headers => {
|
|
@@ -223,11 +217,13 @@ const _getPostProcessOptions = headers => {
|
|
|
223
217
|
// REVISIT: options ie headers are not used in _pick since its cached
|
|
224
218
|
// consequently, all decimals are always picked even w/o these headers
|
|
225
219
|
const acceptHeader = headers.accept
|
|
220
|
+
|
|
226
221
|
if (acceptHeader && acceptHeader.includes('IEEE754Compatible=true')) {
|
|
227
222
|
options.decimals = { exponential: acceptHeader.includes('ExponentialDecimals=true') }
|
|
228
223
|
}
|
|
229
224
|
|
|
230
225
|
const preferHeader = headers.prefer
|
|
226
|
+
|
|
231
227
|
if (preferHeader && preferHeader.includes('omit-values=')) {
|
|
232
228
|
options.omitValuesPreference = new Map()
|
|
233
229
|
}
|
|
@@ -252,6 +248,7 @@ const postProcess = (req, res, service, result, previousResult) => {
|
|
|
252
248
|
|
|
253
249
|
// process each row
|
|
254
250
|
const processFn = _processorFn(req, previousResult, options)
|
|
251
|
+
|
|
255
252
|
for (const row of rows) {
|
|
256
253
|
const args = {
|
|
257
254
|
processFn,
|
|
@@ -270,6 +267,5 @@ const postProcess = (req, res, service, result, previousResult) => {
|
|
|
270
267
|
|
|
271
268
|
module.exports = {
|
|
272
269
|
toODataResult,
|
|
273
|
-
getVirtualsFromResult,
|
|
274
270
|
postProcess
|
|
275
271
|
}
|
|
@@ -18,7 +18,9 @@ const _getProperties = async (properties, req) => {
|
|
|
18
18
|
const cqn = cqn2cqn4sql(SELECT.one(req.query.SELECT.from), req._model).columns(properties)
|
|
19
19
|
|
|
20
20
|
// REVISIT: renaming of media type property (e.g., mimeType as MimeType in AFC) not reflected in @Core.MediaType
|
|
21
|
-
if (req.target.query &&
|
|
21
|
+
if (req.target.query && req.target.query._target && !req.target.drafts) {
|
|
22
|
+
cqn.SELECT.from.ref[0] = req.target.query._target.name
|
|
23
|
+
}
|
|
22
24
|
|
|
23
25
|
adaptStreamCQN(cqn)
|
|
24
26
|
|
|
@@ -45,26 +47,24 @@ const getStreamProperties = async (segments, srv, req) => {
|
|
|
45
47
|
// REVISIT: we need to read direcly from db, which might not be there!
|
|
46
48
|
if (!cds.db) return {}
|
|
47
49
|
|
|
48
|
-
const propertyName = segments[segments.length - 1].getProperty().getName()
|
|
49
|
-
|
|
50
50
|
let contentType, entityName, namespace, contentDisposition
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
const previous = segments[segments.length - 2]
|
|
52
|
+
if (previous.getKind() === 'ENTITY') {
|
|
53
|
+
entityName = previous.getEntitySet().getName()
|
|
54
|
+
namespace = previous.getEdmType().getFullQualifiedName().namespace
|
|
55
|
+
} else if (previous.getKind() === 'NAVIGATION.TO.ONE') {
|
|
56
|
+
entityName = previous.getTarget().getName()
|
|
57
|
+
namespace = previous.getTarget().getEntityType().getFullQualifiedName().namespace
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
if (entityName) {
|
|
60
61
|
const entityDefinition = findCsnTargetFor(entityName, srv.model, namespace)
|
|
61
62
|
if (entityDefinition._hasPersistenceSkip) return {}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
const mediaProperty = Object.values(entityDefinition.elements).find(ele => ele['@Core.MediaType'])
|
|
65
|
+
contentType = mediaProperty['@Core.MediaType']
|
|
64
66
|
// @Core.ContentDisposition.Filename is correct, but we released with @Core.ContentDisposition, so we should stay compatible
|
|
65
|
-
contentDisposition =
|
|
66
|
-
entityDefinition.elements[`${propertyName}`]['@Core.ContentDisposition.Filename'] ||
|
|
67
|
-
entityDefinition.elements[`${propertyName}`]['@Core.ContentDisposition']
|
|
67
|
+
contentDisposition = mediaProperty['@Core.ContentDisposition.Filename'] || mediaProperty['@Core.ContentDisposition']
|
|
68
68
|
// contentDisposition can be only dynamic
|
|
69
69
|
if (typeof contentType === 'object' || contentDisposition) {
|
|
70
70
|
const properties = _getDynamicProperties(contentType, contentDisposition)
|
|
@@ -54,7 +54,6 @@ module.exports = service => {
|
|
|
54
54
|
try {
|
|
55
55
|
const reqs = data.map(d => new RestRequest(parsed, d, restReq, restRes, service))
|
|
56
56
|
result = await Promise.all(reqs.map(req => tx.dispatch(req)))
|
|
57
|
-
result = result.map(res => res[0])
|
|
58
57
|
|
|
59
58
|
_transformToComplex(result, data)
|
|
60
59
|
bufferToBase64(result, target)
|
|
@@ -5,6 +5,7 @@ const RestRequest = require('../RestRequest')
|
|
|
5
5
|
const getData = require('../utils/data')
|
|
6
6
|
const { validateReturnType } = require('../utils/validation-checks')
|
|
7
7
|
const { bufferToBase64 } = require('../utils/binary')
|
|
8
|
+
const { toRestResult } = require('../utils/result')
|
|
8
9
|
|
|
9
10
|
const _convertCustomOperationReturnValue = (returns, result) => {
|
|
10
11
|
if (returns.items) {
|
|
@@ -56,7 +57,7 @@ module.exports = service => {
|
|
|
56
57
|
else {
|
|
57
58
|
// only set status if not yet modified
|
|
58
59
|
if (restRes.statusCode === 200 && status) restRes.status(status)
|
|
59
|
-
restRes.send(body)
|
|
60
|
+
restRes.send(toRestResult(body))
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
}
|
|
@@ -22,10 +22,10 @@ module.exports = service => {
|
|
|
22
22
|
const tx = service.tx({ user: restReq.user, req: restReq, _model: service.model })
|
|
23
23
|
cds.context = tx
|
|
24
24
|
|
|
25
|
-
const req = new RestRequest(parsed, data, restReq, restRes, service)
|
|
26
|
-
|
|
27
25
|
let result, err, commit
|
|
28
26
|
try {
|
|
27
|
+
const req = new RestRequest(parsed, data, restReq, restRes, service)
|
|
28
|
+
|
|
29
29
|
result = await tx.dispatch(req)
|
|
30
30
|
|
|
31
31
|
if (result == null) {
|
|
@@ -2,8 +2,7 @@ const cds = require('../../../../cds')
|
|
|
2
2
|
|
|
3
3
|
const { _newReadToCQN } = require('../../../../odata/readToCqn')
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
const { INSERT, SELECT, UPDATE, DELETE } = require('../../../statements')
|
|
5
|
+
const { INSERT, SELECT, UPDATE, DELETE } = cds.ql
|
|
7
6
|
|
|
8
7
|
const { createCqlString } = require('./utils')
|
|
9
8
|
const { getColumns } = require('../../../services/utils/columns')
|
|
@@ -38,7 +37,6 @@ const _readToCQN = ({ isCollection, segments }, target, restReq) => {
|
|
|
38
37
|
*/
|
|
39
38
|
module.exports = (parsed, data, restReq, service) => {
|
|
40
39
|
const odata2cqn = cds.env.features.rest_new_parser
|
|
41
|
-
if (odata2cqn && !cds.odata) cds.odata = require('../../../../odata')
|
|
42
40
|
|
|
43
41
|
const { event, segments, target } = parsed
|
|
44
42
|
|
|
@@ -47,7 +45,7 @@ module.exports = (parsed, data, restReq, service) => {
|
|
|
47
45
|
|
|
48
46
|
switch (event) {
|
|
49
47
|
case 'CREATE':
|
|
50
|
-
return
|
|
48
|
+
return INSERT.into(target).entries(data)
|
|
51
49
|
case 'READ':
|
|
52
50
|
return odata2cqn ? _newReadToCQN(service, target, restReq) : _readToCQN(parsed, target, restReq)
|
|
53
51
|
case 'UPDATE':
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Convert any result to the
|
|
2
|
+
* Convert any result to the format expected of rest.
|
|
3
3
|
*
|
|
4
4
|
* @param {*} result
|
|
5
|
-
* @returns {string | object}
|
|
5
|
+
* @returns {string | object | boolean}
|
|
6
6
|
*/
|
|
7
7
|
const toRestResult = result => {
|
|
8
8
|
let restResult = result
|
|
@@ -13,6 +13,8 @@ const toRestResult = result => {
|
|
|
13
13
|
count: result.$count,
|
|
14
14
|
value: result
|
|
15
15
|
}
|
|
16
|
+
} else if (typeof result === 'number') {
|
|
17
|
+
restResult = result.toString()
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
return restResult
|