@sap/cds 6.2.3 → 6.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 +57 -0
- package/apis/connect.d.ts +1 -1
- package/apis/cqn.d.ts +1 -1
- package/apis/internal/inference.d.ts +14 -0
- package/apis/ql.d.ts +40 -36
- package/apis/services.d.ts +23 -6
- package/bin/build/buildTaskEngine.js +15 -12
- package/bin/build/buildTaskHandler.js +3 -3
- package/bin/build/constants.js +2 -0
- package/bin/build/provider/buildTaskHandlerEdmx.js +1 -1
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +4 -3
- package/bin/build/provider/buildTaskHandlerInternal.js +2 -2
- package/bin/build/provider/java/index.js +2 -1
- package/bin/build/provider/mtx/index.js +2 -1
- package/bin/build/provider/mtx/resourcesTarBuilder.js +3 -2
- package/bin/build/provider/mtx-extension/index.js +2 -1
- package/bin/build/provider/mtx-sidecar/index.js +3 -1
- package/bin/build/util.js +2 -2
- package/bin/deploy/to-hana/cfUtil.js +46 -62
- package/lib/auth/index.js +2 -1
- package/lib/auth/jwt-auth.js +64 -3
- package/lib/auth/xsuaa-auth.js +2 -3
- package/lib/compile/cdsc.js +1 -0
- package/lib/compile/etc/_localized.js +1 -0
- package/lib/dbs/cds-deploy.js +2 -1
- package/lib/env/cds-env.js +14 -49
- package/lib/env/cds-requires.js +13 -7
- package/lib/env/defaults.js +4 -0
- package/lib/i18n/localize.js +11 -8
- package/lib/index.js +1 -1
- package/lib/log/cds-log.js +2 -2
- package/lib/log/format/cf.js +16 -0
- package/lib/log/format/kibana.js +15 -2
- package/lib/ql/INSERT.js +12 -11
- package/lib/ql/Query.js +14 -7
- package/lib/ql/UPSERT.js +1 -0
- package/lib/ql/Whereable.js +6 -2
- package/lib/ql/cds-ql.js +2 -4
- package/lib/req/request.js +2 -0
- package/lib/srv/bindings.js +1 -0
- package/lib/srv/middlewares/cds-context.js +1 -1
- package/lib/srv/srv-dispatch.js +1 -0
- package/lib/srv/srv-tx.js +3 -3
- package/lib/utils/cds-utils.js +75 -30
- package/lib/utils/inflect.js +24 -0
- package/libx/_runtime/auth/strategies/ias-auth.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +9 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +23 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/validator/ValueValidator.js +27 -15
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +1 -1
- package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -10
- package/libx/_runtime/cds-services/services/utils/differ.js +6 -4
- package/libx/_runtime/common/composition/data.js +29 -40
- package/libx/_runtime/common/composition/update.js +6 -19
- package/libx/_runtime/common/generic/paging.js +1 -1
- package/libx/_runtime/common/utils/resolveView.js +7 -13
- package/libx/_runtime/db/utils/generateAliases.js +1 -0
- package/libx/_runtime/fiori/generic/before.js +5 -2
- package/libx/_runtime/fiori/generic/read.js +11 -4
- package/libx/_runtime/hana/execute.js +2 -2
- package/libx/_runtime/hana/search2Contains.js +3 -1
- package/libx/_runtime/hana/search2cqn4sql.js +1 -0
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +5 -2
- package/libx/_runtime/messaging/enterprise-messaging.js +7 -1
- package/libx/_runtime/messaging/file-based.js +1 -1
- package/libx/_runtime/messaging/message-queuing.js +5 -2
- package/libx/_runtime/messaging/outbox/utils.js +1 -1
- package/libx/_runtime/messaging/service.js +5 -3
- package/libx/odata/cqn2odata.js +4 -1
- package/libx/odata/utils.js +8 -7
- package/libx/rest/RestAdapter.js +1 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,61 @@
|
|
|
4
4
|
- The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
5
5
|
- This project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
|
|
7
|
+
## Version 6.3.1 - 2022-11-04
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- `cds build` no longer reports false positive validation errors for built-in MTX models like `@sap/cds/srv/mtx` or `@sap/cds-mtxs/srv/bootstrap`
|
|
11
|
+
- `cds deploy` handles empty result from `cf` call correctly
|
|
12
|
+
- `$search` fails on columns composed by a CQL expression that uses the SAP HANA `coalesce` predicate
|
|
13
|
+
- Draft ownership was erroneously checked for bound actions on active instances
|
|
14
|
+
- `cds watch/run/serve --with-mocks` no longer start randomly with missing mocked services. This could happen if previous runs crashed with errors and left bad state in the local service registry.
|
|
15
|
+
|
|
16
|
+
## Version 6.3.0 - 2022-10-28
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Additional type signatures for service methods in the query API
|
|
21
|
+
- In case of error in a batch request, the @Core.ContentID is added to the details of the error message
|
|
22
|
+
- Extensibility: Use i18n files from extensions in edmx calculation
|
|
23
|
+
- In messaging, you can listen to all messages in a queue by subscribing to `'*'`
|
|
24
|
+
- Improved Log formatting for Cloud Foundry
|
|
25
|
+
- In remote services: Correct OData type conversion when using an imported csn
|
|
26
|
+
- Types for `SELECT.forUpdate({wait})`
|
|
27
|
+
|
|
28
|
+
- `cds.ql` now provides a dedicated method `.alias()` to choose table aliases, e.g.:
|
|
29
|
+
```js
|
|
30
|
+
SELECT.from(Authors).alias(a)
|
|
31
|
+
```
|
|
32
|
+
> Note: unfortunately we can't use method `.as()` instead of `.alias()` for compatibility reasons
|
|
33
|
+
|
|
34
|
+
- `cds.ql` now supports constructing queries with `where exists` clauses, e.g.:
|
|
35
|
+
```js
|
|
36
|
+
SELECT.from(Authors).where({exists:'books'})
|
|
37
|
+
SELECT.from(Authors).where({'not exists':'books'})
|
|
38
|
+
SELECT.from(Authors).alias('a').where({ exists: // or 'not exists'
|
|
39
|
+
SELECT.from(Books).where({author_ID:{ref:['a','ID']}})
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
> Note: last query is equivalent to first
|
|
43
|
+
- `cds compile` and `cds deploy` now also support dialect `h2`
|
|
44
|
+
- New (easier) `jwt` and `xsuaa` authentication middleware for pluggable middlewares
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- In `enterprise-messaging`, emitting CloudEvents messages sets the HTTP header `Content-Type: application/cloudevents+json`
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- Change signature of cqn `SELECT.limit.offset` and `SELECT.limit.rows` to `val` instead of `number`
|
|
53
|
+
- Parsing of store procedure SQL calls including the schema name. For example, `CALL "SCHEMA"."PROC"(?)` and `CALL SCHEMA.PROC(?)`
|
|
54
|
+
- Add property name in the error message on validation of the value
|
|
55
|
+
- Kibana and Cloud Foundry formatter: do not log cookie header value
|
|
56
|
+
- Missing SQL aliases for `$search` queries combined with `$orderBy` query option
|
|
57
|
+
- The return value of `cds.connect` is now correctly typed as a `Promise`
|
|
58
|
+
- `req.data` is no longer modified for remote services in the case of `odata-v2` inserts
|
|
59
|
+
- `cds.localize` no longer ignores i18n files defined within CDS model scope and outside project scope
|
|
60
|
+
- Don't modify query in `fioriGenericRead` handler
|
|
61
|
+
|
|
7
62
|
## Version 6.2.3 - 2022-10-21
|
|
8
63
|
|
|
9
64
|
### Fixed
|
|
@@ -88,6 +143,8 @@
|
|
|
88
143
|
- `cds deploy` and `cds run/serve/watch` no longer print terminal escape sequences (`x1b...`) if they run non-interactively.
|
|
89
144
|
- Some fields in entities like `path` generated invalid sql
|
|
90
145
|
|
|
146
|
+
### Removed
|
|
147
|
+
|
|
91
148
|
## Version 6.1.3 - 2022-09-13
|
|
92
149
|
|
|
93
150
|
### Added
|
package/apis/connect.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ declare class cds {
|
|
|
15
15
|
* Connects the primary datasource.
|
|
16
16
|
* @see [capire](https://cap.cloud.sap/docs/node.js/api#cds-connect)
|
|
17
17
|
*/
|
|
18
|
-
(options?: string | ConnectOptions) : typeof cds //> cds.connect(<options>)
|
|
18
|
+
(options?: string | ConnectOptions) : Promise<typeof cds> //> cds.connect(<options>)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
package/apis/cqn.d.ts
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Types in this file are not part of the API.
|
|
2
|
+
// They are merely meant as definitions that are used
|
|
3
|
+
// in several places within the API.
|
|
4
|
+
|
|
5
|
+
// any class (not value) of array to represent plural types used in cds-typer.
|
|
6
|
+
// Mainly used as pattern match for SingularType
|
|
7
|
+
//type ArrayConstructable = Constructable<Array<unknown>>
|
|
8
|
+
export interface ArrayConstructable<T = any[]> {
|
|
9
|
+
new(...args: any[]): T[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// concrete singular type.
|
|
13
|
+
// `SingularType<Books>` == `Book`.
|
|
14
|
+
export type SingularType<T extends ArrayConstructable<T>> = InstanceType<T>[number]
|
package/apis/ql.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {Definition} from "./csn"
|
|
2
2
|
import * as CQN from "./cqn"
|
|
3
|
+
import { ArrayConstructable, SingularType } from "./internal/inference"
|
|
3
4
|
|
|
4
5
|
export type Query = CQN.Query
|
|
5
6
|
|
|
@@ -12,7 +13,7 @@ interface Constructable<T> {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export class cds_ql {
|
|
15
|
-
ql:QL & ((context:object) => QL)
|
|
16
|
+
ql:QL<any> & ((context:object) => QL<any>)
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export type PK = number | string | object
|
|
@@ -48,25 +49,14 @@ type Proxy_<T> = {
|
|
|
48
49
|
get: (path: string) => any // Proxy<unknown>
|
|
49
50
|
} & QLExtensions
|
|
50
51
|
|
|
51
|
-
type Proxy<T> = (T extends Subqueryable<infer U>
|
|
52
|
+
export type Proxy<T> = (T extends Subqueryable<infer U>
|
|
52
53
|
? (Omit<T, ""> & Subqueryable<Proxy<U>>) // drop ((x: T) => T) in favour of (x: Proxy<T>) => Proxy<T>)
|
|
53
54
|
: (Proxy_<T>))
|
|
54
55
|
& QLExtensions
|
|
55
56
|
|
|
56
|
-
// any class (not value) of array to represent plural types used in cds-typer.
|
|
57
|
-
// Mainly used as pattern match for SingularType
|
|
58
|
-
//type ArrayConstructable = Constructable<Array<unknown>>
|
|
59
|
-
interface ArrayConstructable<T> {
|
|
60
|
-
new(...args: any[]): T
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// concrete singular type.
|
|
64
|
-
// `SingularType<Books>` == `Book`.
|
|
65
|
-
type SingularType<T extends ArrayConstructable<T>> = InstanceType<T>[number]
|
|
66
|
-
|
|
67
57
|
// Alias for projections
|
|
68
58
|
// https://cap.cloud.sap/docs/node.js/cds-ql?q=projection#projection-functions
|
|
69
|
-
type Projection<T> = (e:T)=>void
|
|
59
|
+
export type Projection<T> = (e:T)=>void
|
|
70
60
|
|
|
71
61
|
// Type for query pieces that can either be chained to build more complex queries or
|
|
72
62
|
// awaited to materialise the result:
|
|
@@ -80,7 +70,7 @@ type Projection<T> = (e:T)=>void
|
|
|
80
70
|
// `Awaitable<T> = T extends unknown<infer I> ? (T & Promise<I>) : never`
|
|
81
71
|
// (at the time of writing, infering the first generic parameter of ANY type
|
|
82
72
|
// does not seem to be possible.)
|
|
83
|
-
type Awaitable<T, I> = T & Promise<I>
|
|
73
|
+
export type Awaitable<T, I> = T & Promise<I>
|
|
84
74
|
|
|
85
75
|
// all the functionality of an instance of SELECT, but directly callable:
|
|
86
76
|
// new SELECT(...).(...) == SELECT(...)
|
|
@@ -91,7 +81,7 @@ export type StaticSELECT<T> = typeof SELECT
|
|
|
91
81
|
& SELECT_one // as it is not directly quantified, ...
|
|
92
82
|
& SELECT_from // ...we should expect both a scalar and a list
|
|
93
83
|
|
|
94
|
-
declare class QL {
|
|
84
|
+
declare class QL<T> {
|
|
95
85
|
SELECT : StaticSELECT<T>
|
|
96
86
|
INSERT : typeof INSERT
|
|
97
87
|
& ((...entries:object[]) => INSERT<any>) & ((entries:object[]) => INSERT<any>)
|
|
@@ -107,7 +97,7 @@ declare class QL {
|
|
|
107
97
|
// when run in strict mode.
|
|
108
98
|
// This signature has to be added to a method as intersection type.
|
|
109
99
|
// Defining overloads with it will override preceding signatures and the other way around.
|
|
110
|
-
type TaggedTemplateQueryPart<T> = (strings: TemplateStringsArray, ...params
|
|
100
|
+
type TaggedTemplateQueryPart<T> = (strings: TemplateStringsArray, ...params: unknown[]) => T
|
|
111
101
|
|
|
112
102
|
export class SELECT<T> extends ConstructedQuery {
|
|
113
103
|
static one : SELECT_one & { from: SELECT_one }
|
|
@@ -134,19 +124,32 @@ export class SELECT<T> extends ConstructedQuery {
|
|
|
134
124
|
& ((...expr : string[]) => this)
|
|
135
125
|
limit: TaggedTemplateQueryPart<this>
|
|
136
126
|
& ((rows : number, offset? : number) => this)
|
|
137
|
-
|
|
138
|
-
forUpdate () : this
|
|
127
|
+
forShareLock () : this
|
|
128
|
+
forUpdate ({wait}? : {wait?: number}) : this
|
|
129
|
+
|
|
130
|
+
// Not yet public
|
|
131
|
+
// fullJoin (other: string, as: string) : this
|
|
132
|
+
// leftJoin (other: string, as: string) : this
|
|
133
|
+
// rightJoin (other: string, as: string) : this
|
|
134
|
+
// innerJoin (other: string, as: string) : this
|
|
135
|
+
// join (other: string, as: string, kind?: string) : this
|
|
136
|
+
// on : TaggedTemplateQueryPart<this>
|
|
137
|
+
// & ((...expr : string[]) => this)
|
|
138
|
+
// & ((predicate:object) => this)
|
|
139
|
+
|
|
139
140
|
SELECT : CQN.SELECT
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
|
|
143
144
|
type SELECT_one =
|
|
145
|
+
TaggedTemplateQueryPart<Awaitable<SELECT<unknown>, InstanceType<any>>>
|
|
146
|
+
&
|
|
144
147
|
// calling with class
|
|
145
|
-
(<T extends ArrayConstructable
|
|
148
|
+
(<T extends ArrayConstructable<any>>
|
|
146
149
|
(entityType: T, projection?: Projection<Proxy<SingularType<T>>>)
|
|
147
150
|
=> Awaitable<SELECT<SingularType<T>>, SingularType<T>>)
|
|
148
151
|
&
|
|
149
|
-
(<T extends ArrayConstructable
|
|
152
|
+
(<T extends ArrayConstructable<any>>
|
|
150
153
|
(entityType: T, primaryKey : PK, projection?: Projection<Proxy<SingularType<T>>>)
|
|
151
154
|
=> Awaitable<SELECT<SingularType<T>>, SingularType<T>>)
|
|
152
155
|
|
|
@@ -158,14 +161,14 @@ type SELECT_one =
|
|
|
158
161
|
|
|
159
162
|
type SELECT_from =
|
|
160
163
|
// tagged template
|
|
161
|
-
TaggedTemplateQueryPart<Awaitable<SELECT<unknown>, InstanceType<
|
|
164
|
+
TaggedTemplateQueryPart<Awaitable<SELECT<unknown>, InstanceType<any>>>
|
|
162
165
|
&
|
|
163
166
|
// calling with class
|
|
164
|
-
(<T extends ArrayConstructable
|
|
167
|
+
(<T extends ArrayConstructable<any>>
|
|
165
168
|
(entityType: T, projection?: Projection<Proxy<SingularType<T>>>)
|
|
166
169
|
=> Awaitable<SELECT<T>, InstanceType<T>>)
|
|
167
170
|
&
|
|
168
|
-
(<T extends ArrayConstructable
|
|
171
|
+
(<T extends ArrayConstructable<any>>
|
|
169
172
|
(entityType: T, primaryKey : PK, projection?: Projection<SingularType<T>>)
|
|
170
173
|
=> Awaitable<SELECT<T>, InstanceType<T>>)
|
|
171
174
|
// calling with definition
|
|
@@ -176,16 +179,15 @@ type SELECT_from =
|
|
|
176
179
|
|
|
177
180
|
|
|
178
181
|
export class INSERT<T> extends ConstructedQuery {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
into (entity : Definition | string) : this
|
|
182
|
+
static into : (<T extends ArrayConstructable<any>> (entity:T, entries? : object | object[]) => INSERT<SingularType<T>>)
|
|
183
|
+
& (TaggedTemplateQueryPart<INSERT<unknown>>)
|
|
184
|
+
& ((entity : Definition | string, entries? : object | object[]) => INSERT<any>)
|
|
185
|
+
& (<T> (entity:Constructable<T>, entries? : object | object[]) => INSERT<T>)
|
|
186
|
+
& (<T> (entity:T, entries? : T | object | object[]) => INSERT<T>)
|
|
187
|
+
|
|
188
|
+
into: (<T extends ArrayConstructable> (entity:T) => this)
|
|
189
|
+
& TaggedTemplateQueryPart<this>
|
|
190
|
+
& ((entity : Definition | string) => this)
|
|
189
191
|
data (block : (e:T)=>void) : this
|
|
190
192
|
entries (...entries : object[]) : this
|
|
191
193
|
columns (...col: string[]) : this
|
|
@@ -195,7 +197,9 @@ export class INSERT<T> extends ConstructedQuery {
|
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
export class DELETE<T> extends ConstructedQuery {
|
|
198
|
-
static from
|
|
200
|
+
static from:
|
|
201
|
+
TaggedTemplateQueryPart<Awaitable<SELECT<unknown>, InstanceType<any>>>
|
|
202
|
+
& ((entity : Definition | string | ArrayConstructable, primaryKey? : PK) => DELETE<any>)
|
|
199
203
|
byKey (primaryKey? : PK) : this
|
|
200
204
|
where (predicate:object) : this
|
|
201
205
|
where (...expr : any[]) : this
|
|
@@ -206,7 +210,7 @@ export class DELETE<T> extends ConstructedQuery {
|
|
|
206
210
|
|
|
207
211
|
export class UPDATE<T> extends ConstructedQuery {
|
|
208
212
|
// cds-typer plural
|
|
209
|
-
static entity <T extends ArrayConstructable
|
|
213
|
+
static entity <T extends ArrayConstructable<any>> (entity:T, primaryKey? : PK) : UPDATE<SingularType<T>>
|
|
210
214
|
|
|
211
215
|
static entity (entity : Definition | string, primaryKey? : PK) : UPDATE<any>
|
|
212
216
|
static entity <T> (entity:Constructable<T>, primaryKey? : PK) : UPDATE<T>
|
package/apis/services.d.ts
CHANGED
|
@@ -1,34 +1,50 @@
|
|
|
1
1
|
import { SELECT, INSERT, UPDATE, DELETE, Query, ConstructedQuery } from './ql'
|
|
2
|
+
import { Projection, Proxy, Awaitable } from './ql'
|
|
3
|
+
import { SingularType, ArrayConstructable } from './internal/inference'
|
|
2
4
|
import { LinkedModel, Definition, Definitions } from './reflect'
|
|
3
5
|
import { csn, type } from "./csn"
|
|
4
6
|
// import { Service } from './cds'
|
|
5
7
|
|
|
6
|
-
|
|
7
8
|
export class QueryAPI {
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run)
|
|
11
12
|
*/
|
|
12
|
-
read
|
|
13
|
+
read: {
|
|
14
|
+
<T extends ArrayConstructable<any>>(entity : T, key?: any) : Awaitable<SELECT<T>, InstanceType<T>>
|
|
15
|
+
<T>(entity : Definition | string, key?: any) : SELECT<T>
|
|
16
|
+
}
|
|
13
17
|
|
|
14
18
|
/**
|
|
15
19
|
* @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run)
|
|
16
20
|
*/
|
|
17
|
-
create
|
|
21
|
+
create: {
|
|
22
|
+
<T extends ArrayConstructable<any>>(entity : T, key?: any) : INSERT<T>
|
|
23
|
+
<T>(entity : Definition | string, key?: any) : INSERT<T>
|
|
24
|
+
}
|
|
18
25
|
|
|
19
26
|
/**
|
|
20
27
|
* @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run)
|
|
21
28
|
*/
|
|
22
|
-
insert
|
|
29
|
+
insert: {
|
|
30
|
+
<T extends ArrayConstructable<any>>(data : T) : INSERT<T>
|
|
31
|
+
<T>(data : object | object[]) : INSERT<T>
|
|
32
|
+
}
|
|
23
33
|
|
|
24
34
|
/**
|
|
25
35
|
* @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run)
|
|
26
36
|
*/
|
|
27
|
-
update
|
|
37
|
+
update: {
|
|
38
|
+
<T extends ArrayConstructable<any>>(entity : T, key?: any) : UPDATE<T>
|
|
39
|
+
<T>(entity : Definition | string, key?: any) : UPDATE<T>
|
|
40
|
+
}
|
|
28
41
|
|
|
29
42
|
/**
|
|
30
43
|
* @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run)
|
|
31
44
|
*/
|
|
45
|
+
// as delete is the only one of the CRUD methods from QueryAPI
|
|
46
|
+
// that is extended in Service, we have to add the second signature down there
|
|
47
|
+
// (TS error 2425)
|
|
32
48
|
delete <T>(entity : Definition | string, key?: any) : DELETE<T>
|
|
33
49
|
|
|
34
50
|
/**
|
|
@@ -44,7 +60,7 @@ export class QueryAPI {
|
|
|
44
60
|
/**
|
|
45
61
|
* @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run-sql)
|
|
46
62
|
*/
|
|
47
|
-
|
|
63
|
+
run (query : string, args? : any[]|object) : Promise<ResultSet | any>
|
|
48
64
|
|
|
49
65
|
/**
|
|
50
66
|
* @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run)
|
|
@@ -184,6 +200,7 @@ export class Service extends QueryAPI {
|
|
|
184
200
|
/**
|
|
185
201
|
* @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run)
|
|
186
202
|
*/
|
|
203
|
+
delete <T extends ArrayConstructable<any>>(entity : T, key?: any): DELETE<T>
|
|
187
204
|
delete <T>(entity : Definition | string, key?: any) : DELETE<T>
|
|
188
205
|
|
|
189
206
|
// The central method to dispatch events
|
|
@@ -2,8 +2,8 @@ const fs = require('fs')
|
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const _cds = require('./cds'), { log } = _cds.exec
|
|
4
4
|
const { sortMessagesSeverityAware, deduplicateMessages, CompilationError } = require('@sap/cds-compiler')
|
|
5
|
-
const { relativePaths, BuildError, BuildMessage, resolveRequiredSapModels } = require('./util')
|
|
6
|
-
const { OUTPUT_MODE_DEFAULT, SEVERITIES, LOG_LEVELS, LOG_MODULE_NAMES } = require('./constants')
|
|
5
|
+
const { relativePaths, BuildError, BuildMessage, resolveRequiredSapModels, hasJavaNature } = require('./util')
|
|
6
|
+
const { OUTPUT_MODE_DEFAULT, SEVERITIES, LOG_LEVELS, LOG_MODULE_NAMES, CDS_MODEL_EXCLUDE_LIST } = require('./constants')
|
|
7
7
|
const BuildTaskProviderFactory = require('./buildTaskProviderFactory')
|
|
8
8
|
const BuildTaskHandlerInternal = require('./provider/buildTaskHandlerInternal')
|
|
9
9
|
|
|
@@ -28,6 +28,7 @@ class BuildTaskEngine {
|
|
|
28
28
|
|
|
29
29
|
async processTasks(tasks, buildOptions, clean = true) {
|
|
30
30
|
const startTime = Date.now()
|
|
31
|
+
const messages = []
|
|
31
32
|
|
|
32
33
|
if (buildOptions) {
|
|
33
34
|
// clone as data may be stored as part of the buildOptions object
|
|
@@ -48,14 +49,16 @@ class BuildTaskEngine {
|
|
|
48
49
|
buildOptions.target = path.resolve(buildOptions.root, this.env.build.target)
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
// Java projects don't have node modules installed on project root level
|
|
53
|
+
if (!hasJavaNature([buildOptions.root])) {
|
|
54
|
+
// validate required @sap namespace models - log only
|
|
55
|
+
const { unresolved, missing } = this._resolveRequiredSapServices(tasks)
|
|
56
|
+
if (unresolved.length > 0) {
|
|
57
|
+
messages.push(new BuildMessage(`Required CDS service models [${unresolved.join(', ')}] cannot be resolved. Make sure to install the missing npm modules.`))
|
|
58
|
+
}
|
|
59
|
+
if (missing.length > 0) {
|
|
60
|
+
messages.push(new BuildMessage(`Required CDS service models [${missing.join(', ')}] are missing in custom build tasks. Make sure to add the missing models.`))
|
|
61
|
+
}
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
// create build task handlers
|
|
@@ -85,7 +88,7 @@ class BuildTaskEngine {
|
|
|
85
88
|
return buildResult
|
|
86
89
|
} catch (error) {
|
|
87
90
|
this._logBuildOutput(handlers, buildOptions)
|
|
88
|
-
|
|
91
|
+
|
|
89
92
|
// cds CLI layer logs in case of an exception if invoked from CLI
|
|
90
93
|
if (!buildOptions.cli) {
|
|
91
94
|
this._logMessages(buildOptions, [...BuildTaskEngine._getErrorMessages([error]), ...messages])
|
|
@@ -336,7 +339,7 @@ class BuildTaskEngine {
|
|
|
336
339
|
|
|
337
340
|
const unresolved = resolveRequiredSapModels(this.cds, [...taskModelPaths])
|
|
338
341
|
// are the required service models contained in the task's options.model
|
|
339
|
-
const missing = srvModelPaths.filter(m => m.startsWith('@sap/') && !taskModelPaths.has(m) && !unresolved.find(u => u === m))
|
|
342
|
+
const missing = srvModelPaths.filter(m => m.startsWith('@sap/') && !CDS_MODEL_EXCLUDE_LIST.includes(m) && !taskModelPaths.has(m) && !unresolved.find(u => u === m))
|
|
340
343
|
|
|
341
344
|
return { unresolved, missing }
|
|
342
345
|
}
|
|
@@ -117,7 +117,7 @@ class BuildTaskHandler {
|
|
|
117
117
|
// relative to build task's destination path
|
|
118
118
|
dest = path.resolve(this.task.dest, dest)
|
|
119
119
|
}
|
|
120
|
-
this.
|
|
120
|
+
this.pushFile(dest)
|
|
121
121
|
if (this._hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_DEFAULT)) {
|
|
122
122
|
await fs.mkdir(path.dirname(dest), { recursive: true })
|
|
123
123
|
await fs.writeFile(dest, typeof data === "object" && !Buffer.isBuffer(data) ? JSON.stringify(data, null, 2) : data)
|
|
@@ -151,7 +151,7 @@ class BuildTaskHandler {
|
|
|
151
151
|
// relative to build task's destination path
|
|
152
152
|
dest = path.resolve(this.task.dest, dest)
|
|
153
153
|
}
|
|
154
|
-
this.
|
|
154
|
+
this.pushFile(dest)
|
|
155
155
|
if (this._hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_DEFAULT)) {
|
|
156
156
|
if (fs.cp) { // Node.js >= 16.7
|
|
157
157
|
return fs.cp(src, dest, { recursive: true })
|
|
@@ -205,7 +205,7 @@ class BuildTaskHandler {
|
|
|
205
205
|
* Adds the given fully qualified file path to the list of files that are written by this build task.
|
|
206
206
|
* @param {string} filePath
|
|
207
207
|
*/
|
|
208
|
-
|
|
208
|
+
pushFile(filePath) {
|
|
209
209
|
this._written.add(filePath)
|
|
210
210
|
}
|
|
211
211
|
/**
|
package/bin/build/constants.js
CHANGED
|
@@ -45,6 +45,8 @@ exports.FOLDER_GEN = "gen"
|
|
|
45
45
|
exports.FILE_EXT_CDS = ".cds"
|
|
46
46
|
exports.MTX_SIDECAR_FOLDER = "mtx/sidecar" // default name of the mtx sidecar folder
|
|
47
47
|
exports.DEFAULT_CSN_FILE_NAME = "csn.json"
|
|
48
|
+
// REVISIT: the models are not required if a custom server.js file is used for MTX bootstrap
|
|
49
|
+
exports.CDS_MODEL_EXCLUDE_LIST = ['@sap/cds/srv/mtx', '@sap/cds-mtxs/srv/bootstrap']
|
|
48
50
|
|
|
49
51
|
exports.CDS_CONFIG_PATH_SEP = "/"
|
|
50
52
|
exports.SKIP_ASSERT_COMPILER_V2 = "skip-assert-compiler-v2"
|
|
@@ -26,7 +26,7 @@ class BuildTaskHandlerEdmx extends BuildTaskHandlerFeatureToggles {
|
|
|
26
26
|
const result = this.cds.compile.to.edmx(model, options)
|
|
27
27
|
|
|
28
28
|
if (result) {
|
|
29
|
-
let langs = this.task.options.lang || this.
|
|
29
|
+
let langs = this.task.options.lang || this.env.i18n.languages
|
|
30
30
|
if (langs.split) { // string to array
|
|
31
31
|
langs = langs.split(',')
|
|
32
32
|
}
|
|
@@ -43,8 +43,9 @@ class FeatureToggleBuilder extends BuildTaskHandlerInternal {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
async collectAllLanguageBundles(dictionary, paths, destBase, destFts) {
|
|
46
|
+
const i18nFolder = this.env.i18n.folders?.[0] || 'i18n'
|
|
46
47
|
// create language bundle for base model
|
|
47
|
-
const i18n = await this.collectLanguageBundles(dictionary.base, destBase)
|
|
48
|
+
const i18n = await this.collectLanguageBundles(dictionary.base, path.join(destBase, i18nFolder))
|
|
48
49
|
if (i18n) {
|
|
49
50
|
this._result.languageBundles = i18n.bundles
|
|
50
51
|
}
|
|
@@ -54,7 +55,7 @@ class FeatureToggleBuilder extends BuildTaskHandlerInternal {
|
|
|
54
55
|
for (const ftName in dictionary.features) {
|
|
55
56
|
// attach the sources information for i18n location reference
|
|
56
57
|
dictionary.features[ftName]['$sources'] = paths.features[ftName]
|
|
57
|
-
await this.collectLanguageBundles(dictionary.features[ftName], path.join(destFts, this.ftsName, ftName))
|
|
58
|
+
await this.collectLanguageBundles(dictionary.features[ftName], path.join(destFts, this.ftsName, ftName, i18nFolder))
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
}
|
|
@@ -108,7 +109,7 @@ class FeatureToggleBuilder extends BuildTaskHandlerInternal {
|
|
|
108
109
|
|
|
109
110
|
// replace require paths by base model path to ensure precedence of feature annotations
|
|
110
111
|
// see https://pages.github.tools.sap/cap/docs/cds/compiler-messages#anno-duplicate-unrelated-layer
|
|
111
|
-
ftCsn.requires = [path.join(path.relative(ftPath, destBase), DEFAULT_CSN_FILE_NAME).replace(/\\/g,'/')]
|
|
112
|
+
ftCsn.requires = [path.join(path.relative(ftPath, destBase), DEFAULT_CSN_FILE_NAME).replace(/\\/g, '/')]
|
|
112
113
|
|
|
113
114
|
await this.compileToJson(ftCsn, path.join(ftPath, DEFAULT_CSN_FILE_NAME))
|
|
114
115
|
await this._validateFeature(ftPath)
|
|
@@ -204,8 +204,8 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
|
|
|
204
204
|
bundles = {}
|
|
205
205
|
}
|
|
206
206
|
// copied from ../compile/i18n.js
|
|
207
|
-
const {
|
|
208
|
-
const file = path.join(bundleDest,
|
|
207
|
+
const { file: base = 'i18n' } = this.env.i18n
|
|
208
|
+
const file = path.join(bundleDest, base + '.json')
|
|
209
209
|
|
|
210
210
|
// bundleDest might be null
|
|
211
211
|
if (bundleDest && Object.keys(bundles).length > 0) {
|
|
@@ -48,7 +48,8 @@ class JavaModuleBuilder extends BuildTaskHandlerEdmx {
|
|
|
48
48
|
|
|
49
49
|
if (this.hasBuildOption(CONTENT_LANGUAGE_BUNDLES, true)) {
|
|
50
50
|
// collect and write language bundles into single i18n.json file
|
|
51
|
-
const
|
|
51
|
+
const i18nFolder = this.env.i18n.folders?.[0] || 'i18n'
|
|
52
|
+
const i18n = await this.collectLanguageBundles(model, path.join(this.task.dest, i18nFolder))
|
|
52
53
|
if (i18n) {
|
|
53
54
|
this._result.languageBundles = i18n.bundles
|
|
54
55
|
}
|
|
@@ -96,7 +96,8 @@ class ClassicMtxBuilder {
|
|
|
96
96
|
}))
|
|
97
97
|
|
|
98
98
|
// collect and write language bundles into single i18n.json file
|
|
99
|
-
const
|
|
99
|
+
const i18nFolder = this._handler.env.i18n.folders?.[0] || 'i18n'
|
|
100
|
+
const i18n = await this._handler.collectLanguageBundles(model, path.join(destSdc, i18nFolder))
|
|
100
101
|
if (i18n) {
|
|
101
102
|
this._handler._result.languageBundles = i18n.bundles
|
|
102
103
|
}
|
|
@@ -15,16 +15,17 @@ class ResourcesTarBuilder {
|
|
|
15
15
|
async createTar(dest, model) {
|
|
16
16
|
const { root, files } = await this._getResources(model)
|
|
17
17
|
if (files.length === 0) {
|
|
18
|
-
// packTarArchive
|
|
18
|
+
// packTarArchive fails otherwise
|
|
19
19
|
this.handler.pushMessage("No deployment resources found - skip resources.tgz", WARNING)
|
|
20
20
|
return
|
|
21
21
|
}
|
|
22
22
|
await this.writeTarFile(files, root, path.join(dest, DEFAULT_TAR_NAME))
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
async writeTarFile(files, root, tarFile) {
|
|
25
|
+
async writeTarFile(files, root, tarFile) {
|
|
26
26
|
const { tar } = require('../../../../lib').utils
|
|
27
27
|
await tar.czfd (tarFile, root, files) // REVISIT: tar.czfd was created for this case only -> it ensures the target's dir exists
|
|
28
|
+
this.handler.pushFile(tarFile)
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
async _getResources(model) {
|
|
@@ -33,7 +33,8 @@ class MtxExtensionModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
33
33
|
await this.compileToJson(extCsn, csnFile)
|
|
34
34
|
allFiles.push(csnFile)
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
// static i18n folder name as runtime does not use the CDS config of the extension project
|
|
37
|
+
const i18n = await this.collectLanguageBundles(extCsn, path.join(destExt, 'i18n'))
|
|
37
38
|
if (i18n) {
|
|
38
39
|
allFiles.push(i18n.file)
|
|
39
40
|
}
|
|
@@ -44,9 +44,11 @@ class MtxSidecarModuleBuilder extends NodeCfModuleBuilder {
|
|
|
44
44
|
async _buildNodeApp(sidecarEnv) {
|
|
45
45
|
const destSidecar = this.task.dest
|
|
46
46
|
const destSidecarSrc = path.join(destSidecar, this.env.folders.srv)
|
|
47
|
+
const i18nFolder = this.env.i18n.folders?.[0] || 'i18n'
|
|
47
48
|
const model = this._compileSidecarSync(sidecarEnv)
|
|
48
49
|
await this.compileToJson(model, path.join(destSidecarSrc, DEFAULT_CSN_FILE_NAME))
|
|
49
|
-
|
|
50
|
+
|
|
51
|
+
await this.collectLanguageBundles(model, path.join(destSidecarSrc, i18nFolder))
|
|
50
52
|
await this.copyProjectRootContent(this.task.src, destSidecar)
|
|
51
53
|
}
|
|
52
54
|
|
package/bin/build/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
|
-
const { SEVERITY_ERROR } = require('./constants')
|
|
3
|
+
const { SEVERITY_ERROR, CDS_MODEL_EXCLUDE_LIST } = require('./constants')
|
|
4
4
|
|
|
5
5
|
function getProperty(src, segments) {
|
|
6
6
|
segments = Array.isArray(segments) ? segments : segments.split('.')
|
|
@@ -142,7 +142,7 @@ function isStreamlinedMtx(cds) {
|
|
|
142
142
|
*/
|
|
143
143
|
function resolveRequiredSapModels(cds, modelPaths) {
|
|
144
144
|
return modelPaths.filter(p => {
|
|
145
|
-
if (p.startsWith('@sap/')) {
|
|
145
|
+
if (p.startsWith('@sap/') && !CDS_MODEL_EXCLUDE_LIST.includes(p)) {
|
|
146
146
|
const files = cds.resolve(p)
|
|
147
147
|
return !files || files.length === 0
|
|
148
148
|
}
|