@sap/cds 7.3.1 → 7.4.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +58 -3
  2. package/_i18n/i18n_es_MX.properties +110 -0
  3. package/apis/cds.d.ts +13 -12
  4. package/apis/core.d.ts +27 -108
  5. package/apis/cqn.d.ts +15 -18
  6. package/apis/csn.d.ts +95 -60
  7. package/apis/env.d.ts +25 -0
  8. package/apis/events.d.ts +124 -0
  9. package/apis/{reflect.d.ts → linked.d.ts} +27 -38
  10. package/apis/models.d.ts +60 -45
  11. package/apis/ql.d.ts +11 -5
  12. package/apis/{serve.d.ts → server.d.ts} +57 -31
  13. package/apis/services.d.ts +74 -145
  14. package/apis/test.d.ts +1 -1
  15. package/bin/serve.js +3 -0
  16. package/lib/compile/cds-compile.js +2 -2
  17. package/lib/compile/to/edm.js +8 -3
  18. package/lib/compile/to/gql.js +4 -0
  19. package/lib/dbs/cds-deploy.js +52 -4
  20. package/lib/env/cds-requires.js +27 -15
  21. package/lib/env/defaults.js +1 -0
  22. package/lib/env/schemas/index.js +10 -0
  23. package/lib/index.js +7 -4
  24. package/lib/linked/models.js +8 -5
  25. package/lib/ql/CREATE.js +2 -0
  26. package/lib/ql/DELETE.js +1 -0
  27. package/lib/ql/DROP.js +2 -0
  28. package/lib/ql/INSERT.js +2 -22
  29. package/lib/ql/Query.js +59 -22
  30. package/lib/ql/SELECT.js +5 -0
  31. package/lib/ql/STREAM.js +2 -0
  32. package/lib/ql/UPDATE.js +2 -0
  33. package/lib/ql/UPSERT.js +3 -1
  34. package/lib/ql/cds-ql.js +21 -5
  35. package/lib/ql/infer.js +129 -0
  36. package/lib/req/cds-context.js +8 -5
  37. package/lib/srv/cds-connect.js +3 -1
  38. package/lib/utils/axios.js +4 -2
  39. package/lib/utils/data.js +3 -0
  40. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +12 -0
  41. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +26 -8
  42. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/batch/BatchProcessor.js +1 -1
  43. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +11 -8
  44. package/libx/_runtime/common/code-ext/worker.js +5 -16
  45. package/libx/_runtime/common/generic/auth/capabilities.js +11 -2
  46. package/libx/_runtime/common/i18n/messages.properties +1 -0
  47. package/libx/_runtime/common/utils/postProcessing.js +1 -1
  48. package/libx/_runtime/common/utils/resolveView.js +20 -1
  49. package/libx/{common → _runtime/common}/utils/ucsn.js +19 -11
  50. package/libx/_runtime/db/expand/expandCQNToJoin.js +2 -2
  51. package/libx/_runtime/db/sql-builder/InsertBuilder.js +6 -1
  52. package/libx/_runtime/db/sql-builder/UpdateBuilder.js +6 -1
  53. package/libx/_runtime/db/sql-builder/dollar.js +7 -7
  54. package/libx/_runtime/fiori/generic/activate.js +2 -2
  55. package/libx/_runtime/fiori/generic/edit.js +25 -45
  56. package/libx/_runtime/fiori/generic/read.js +3 -5
  57. package/libx/_runtime/fiori/lean-draft.js +142 -64
  58. package/libx/_runtime/fiori/utils/delete.js +7 -1
  59. package/libx/_runtime/fiori/utils/handler.js +4 -6
  60. package/libx/_runtime/fiori/utils/lockInfo.js +27 -0
  61. package/libx/_runtime/fiori/utils/where.js +20 -1
  62. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +3 -2
  63. package/libx/_runtime/messaging/Outbox.js +12 -47
  64. package/libx/_runtime/messaging/common-utils/AMQPClient.js +1 -3
  65. package/libx/_runtime/messaging/common-utils/authorizedRequest.js +3 -0
  66. package/libx/_runtime/messaging/common-utils/connections.js +1 -1
  67. package/libx/_runtime/messaging/enterprise-messaging.js +12 -13
  68. package/libx/_runtime/messaging/file-based.js +7 -5
  69. package/libx/_runtime/messaging/redis-messaging.js +10 -11
  70. package/libx/_runtime/messaging/service.js +12 -26
  71. package/libx/_runtime/remote/Service.js +52 -36
  72. package/libx/_runtime/remote/utils/client.js +22 -123
  73. package/libx/odata/afterburner.js +14 -5
  74. package/libx/odata/grammar.peggy +26 -7
  75. package/libx/odata/metadata.js +18 -1
  76. package/libx/odata/parser.js +1 -1
  77. package/libx/odata/service-document.js +0 -1
  78. package/libx/odata/utils.js +19 -3
  79. package/libx/{_runtime/messaging/outbox/utils.js → outbox/index.js} +94 -24
  80. package/libx/rest/middleware/parse.js +1 -1
  81. package/package.json +2 -2
  82. package/apis/connect.d.ts +0 -39
  83. package/bin/utils/modules.js +0 -7
  84. package/bin/utils/term.js +0 -56
  85. package/lib/env/schema.js +0 -9
  86. package/lib/linked/queries.js +0 -41
  87. package/lib/srv/protocols/odata-v2-proxy.js +0 -3699
  88. package/libx/common/asserts.js +0 -0
  89. package/libx/common/crud.js +0 -0
  90. package/libx/common/etag.js +0 -0
  91. package/libx/common/localized.js +0 -0
  92. package/libx/common/managed.js +0 -0
  93. package/libx/common/paging.js +0 -0
  94. package/libx/common/readme.md +0 -4
  95. package/libx/common/sorting.js +0 -0
  96. package/libx/common/temporal.js +0 -0
  97. package/libx/connect/auth.js +0 -0
  98. package/libx/connect/perf.js +0 -0
  99. package/libx/connect/readme.md +0 -3
  100. package/libx/fiori/draft/readme.md +0 -1
  101. package/libx/fiori/readme.md +0 -1
  102. package/libx/hana/readme.md +0 -1
  103. package/libx/msg/readme.md +0 -3
  104. package/libx/readme.md +0 -1
  105. package/libx/sqlite/readme.md +0 -1
  106. /package/libx/_runtime/{messaging/common-utils → common/utils}/waitingTime.js +0 -0
  107. /package/libx/{_runtime/messaging/outbox → outbox}/OutboxRunner.js +0 -0
@@ -1,23 +1,21 @@
1
- import { SELECT, INSERT, UPDATE, DELETE, CQNQuery, Query, ConstructedQuery, UPSERT } from './ql'
1
+ import { SELECT, INSERT, UPDATE, DELETE, Query, ConstructedQuery, UPSERT } from './ql'
2
2
  import { Awaitable } from './ql'
3
3
  import { ArrayConstructable, Constructable } from './internal/inference'
4
- import { LinkedModel, Definition, Definitions } from './reflect'
5
- import { csn } from './csn'
6
- import { User } from './core'
7
- import * as express from "express"
8
- import { ref } from './cqn'
9
- // import { Service } from './cds'
4
+ import { LinkedCSN, LinkedDefinition, Definitions } from './linked'
5
+ import { CSN } from './csn'
6
+ import { EventContext } from './events'
7
+ import { Request } from './events'
10
8
 
11
9
  export class QueryAPI {
12
10
 
13
- entities : LinkedModel['entities']
11
+ entities : LinkedCSN['entities']
14
12
 
15
13
  /**
16
14
  * @see [docs](https://cap.cloud.sap/docs/node.js/core-services#crud-style-api)
17
15
  */
18
16
  read: {
19
17
  <T extends ArrayConstructable<any>>(entity: T, key?: any): Awaitable<SELECT<T>, InstanceType<T>>
20
- <T>(entity: Definition | string, key?: any): SELECT<T>
18
+ <T>(entity: LinkedDefinition | string, key?: any): SELECT<T>
21
19
  }
22
20
 
23
21
  /**
@@ -25,7 +23,7 @@ export class QueryAPI {
25
23
  */
26
24
  create: {
27
25
  <T extends ArrayConstructable<any>>(entity: T, key?: any): INSERT<T>
28
- <T>(entity: Definition | string, key?: any): INSERT<T>
26
+ <T>(entity: LinkedDefinition | string, key?: any): INSERT<T>
29
27
  }
30
28
 
31
29
  /**
@@ -49,7 +47,7 @@ export class QueryAPI {
49
47
  */
50
48
  update: {
51
49
  <T extends ArrayConstructable<any>>(entity: T, key?: any): UPDATE<T>
52
- <T>(entity: Definition | string, key?: any): UPDATE<T>
50
+ <T>(entity: LinkedDefinition | string, key?: any): UPDATE<T>
53
51
  }
54
52
 
55
53
  /**
@@ -64,7 +62,7 @@ export class QueryAPI {
64
62
  /**
65
63
  * @see [docs](https://cap.cloud.sap/docs/node.js/core-services#crud-style-api)
66
64
  */
67
- delete<T>(entity: Definition | string, key?: any): DELETE<T>
65
+ delete<T>(entity: LinkedDefinition | string, key?: any): DELETE<T>
68
66
 
69
67
  /**
70
68
  * @see [docs](https://cap.cloud.sap/docs/node.js/core-services#srv-foreach-entity)
@@ -76,7 +74,7 @@ export class QueryAPI {
76
74
  */
77
75
  stream: {
78
76
  (column: string): {
79
- from(entity: Definition | string): {
77
+ from(entity: LinkedDefinition | string): {
80
78
  where(filter: any): ReadableStream
81
79
  }
82
80
  }
@@ -93,7 +91,7 @@ export class QueryAPI {
93
91
  (context?: object): Transaction
94
92
  (context: object, fn: (tx: Transaction) => {}): Promise<unknown>
95
93
  }
96
-
94
+
97
95
  transaction: {
98
96
  (fn: (tx: Transaction) => {}): Promise<unknown>
99
97
  (context?: object): Transaction
@@ -103,20 +101,18 @@ export class QueryAPI {
103
101
  /**
104
102
  * @see [docs](https://cap.cloud.sap/docs/node.js/cds-tx#cds-spawn)
105
103
  */
106
- spawn(options: Options, fn: (tx: Transaction) => {}): SpawnEventEmitter
104
+ spawn(options: {
105
+ [key: string]: any
106
+ every?: number
107
+ after?: number
108
+ }, fn: (tx: Transaction) => {}): SpawnEventEmitter
107
109
 
108
110
  /**
109
111
  * @see [docs](https://cap.cloud.sap/docs/node.js/cds-tx#event-contexts
110
112
  */
111
- context: ContextProperties
113
+ context?: EventContext
112
114
  }
113
115
 
114
- type ContextProperties = {
115
- id?: string
116
- http?: {req: express.Request, res: express.Response}
117
- tenant? : string,
118
- user? : User | string
119
- }
120
116
 
121
117
  /**
122
118
  * Class cds.Service
@@ -125,7 +121,7 @@ type ContextProperties = {
125
121
  export class Service extends QueryAPI {
126
122
  constructor(
127
123
  name: string,
128
- model: csn,
124
+ model: CSN,
129
125
  options: {
130
126
  kind: string
131
127
  impl: string | ServiceImpl
@@ -141,7 +137,7 @@ export class Service extends QueryAPI {
141
137
  * The model from which the service's definition was loaded
142
138
  * @see [capire docs](https://cap.cloud.sap/docs/node.js/core-services)
143
139
  */
144
- model: LinkedModel
140
+ model: LinkedCSN
145
141
 
146
142
  /**
147
143
  * Provides access to the entities exposed by a service
@@ -179,8 +175,8 @@ export class Service extends QueryAPI {
179
175
  * @see [capire docs](https://cap.cloud.sap/docs/core-services#srv-emit-event)
180
176
  */
181
177
  emit: {
182
- <T = any>(details: { event: EventArg; data?: object; headers?: object }): Promise<T>
183
- <T = any>(event: EventArg, data?: object, headers?: object): Promise<T>
178
+ <T = any>(details: { event: types.event; data?: object; headers?: object }): Promise<T>
179
+ <T = any>(event: types.event, data?: object, headers?: object): Promise<T>
184
180
  }
185
181
 
186
182
  /**
@@ -188,93 +184,84 @@ export class Service extends QueryAPI {
188
184
  * @see [capire docs](https://cap.cloud.sap/docs/node.js/core-services#srv-send-request)
189
185
  */
190
186
  send: {
191
- <T = any>(event: EventArg, path: string, data?: object, headers?: object): Promise<T>
192
- <T = any>(event: EventArg, data?: object, headers?: object): Promise<T>
193
- <T = any>(details: { event: EventArg; data?: object; headers?: object }): Promise<T>
187
+ <T = any>(event: types.event, path: string, data?: object, headers?: object): Promise<T>
188
+ <T = any>(event: types.event, data?: object, headers?: object): Promise<T>
189
+ <T = any>(details: { event: types.event; data?: object; headers?: object }): Promise<T>
194
190
  <T = any>(details: { query: ConstructedQuery; data?: object; headers?: object }): Promise<T>
195
- <T = any>(details: { method: EventName; path: string; data?: object; headers?: object }): Promise<T>
196
- <T = any>(details: { event: EventName; entity: Definition | string; data?: object; params?: object }): Promise<T>
191
+ <T = any>(details: { method: types.eventName; path: string; data?: object; headers?: object }): Promise<T>
192
+ <T = any>(details: { event: types.eventName; entity: LinkedDefinition | string; data?: object; params?: object }): Promise<T>
197
193
  }
198
194
 
199
195
  /**
200
196
  * Constructs and sends a GET request.
201
197
  * @see [capire docs](https://cap.cloud.sap/docs/node.js/core-services#rest-style-api)
202
198
  */
203
- get<T = any>(entityOrPath: Target, data?: object): Promise<T>
199
+ get<T = any>(entityOrPath: types.target, data?: object): Promise<T>
204
200
  /**
205
201
  * Constructs and sends a POST request.
206
202
  * @see [capire docs](https://cap.cloud.sap/docs/node.js/core-services#rest-style-api)
207
203
  */
208
- post<T = any>(entityOrPath: Target, data?: object): Promise<T>
204
+ post<T = any>(entityOrPath: types.target, data?: object): Promise<T>
209
205
  /**
210
206
  * Constructs and sends a PUT request.
211
207
  * @see [capire docs](https://cap.cloud.sap/docs/node.js/core-services#rest-style-api)
212
208
  */
213
- put<T = any>(entityOrPath: Target, data?: object): Promise<T>
209
+ put<T = any>(entityOrPath: types.target, data?: object): Promise<T>
214
210
  /**
215
211
  * Constructs and sends a PATCH request.
216
212
  * @see [capire docs](https://cap.cloud.sap/docs/node.js/core-services#rest-style-api)
217
213
  */
218
- patch<T = any>(entityOrPath: Target, data?: object): Promise<T>
214
+ patch<T = any>(entityOrPath: types.target, data?: object): Promise<T>
219
215
  /**
220
216
  * Constructs and sends a DELETE request.
221
217
  */
222
218
  delete: {
223
- <T = any>(entityOrPath: Target, data?: object): DELETE<T>
219
+ <T = any>(entityOrPath: types.target, data?: object): DELETE<T>
224
220
  <T extends ArrayConstructable<any>>(entity: T, key?: any): DELETE<T>
225
- <T>(entity: Definition | string, key?: any): DELETE<T>
221
+ <T>(entity: LinkedDefinition | string, key?: any): DELETE<T>
226
222
  }
227
223
 
228
224
  // The central method to dispatch events
229
- dispatch(msg: Event): Promise<any>
225
+ dispatch(msg: types.event): Promise<any>
230
226
 
231
227
  // Provider API
232
228
  prepend(fn: ServiceImpl): Promise<this>
233
- on<T extends Constructable>(eve: EventArg, entity: T, handler: CRUDEventHandler.On<InstanceType<T>, InstanceType<T> | void | Error>): this
229
+ on<T extends Constructable>(eve: types.event, entity: T, handler: CRUDEventHandler.On<InstanceType<T>, InstanceType<T> | void | Error>): this
234
230
  on<F extends CdsFunction>(boundAction: F, service: string, handler: ActionEventHandler<F['__parameters'], void | Error | F['__returns']>): this
235
231
  on<F extends CdsFunction>(unboundAction: F, handler: ActionEventHandler<F['__parameters'], void | Error | F['__returns']>): this
236
- on(eve: EventArg, entity: Target, handler: OnEventHandler): this
237
- on(eve: EventArg, handler: OnEventHandler): this
238
-
239
-
240
- // onSucceeded (eve: Events, entity: Target, handler: EventHandler): this
241
- // onSucceeded (eve: Events, handler: EventHandler): this
242
- // onFailed (eve: Events, entity: Target, handler: EventHandler): this
243
- // onFailed (eve: Events, handler: EventHandler): this
244
- before<T extends Constructable>(eve: EventArg, entity: T, handler: CRUDEventHandler.Before<InstanceType<T>, InstanceType<T> | void | Error>): this
245
- before(eve: EventArg, entity: Target, handler: EventHandler): this
246
- before(eve: EventArg, handler: EventHandler): this
247
- after<T extends Constructable>(eve: EventArg, entity: T, handler: CRUDEventHandler.After<InstanceType<T>, InstanceType<T> | void | Error>): this
248
- after(eve: EventArg, entity: Target, handler: ResultsHandler): this
249
- after(eve: EventArg, handler: ResultsHandler): this
250
- reject(eves: EventArg, ...entity: Target[]): this
251
- }
252
-
253
- export interface Transaction extends Service {
254
- commit(): Promise<void>
255
- rollback(): Promise<void>
232
+ on(eve: types.event, entity: types.target, handler: OnEventHandler): this
233
+ on(eve: types.event, handler: OnEventHandler): this
234
+
235
+
236
+ // onSucceeded (eve: types.Events, entity: types.Target, handler: types.EventHandler): this
237
+ // onSucceeded (eve: types.Events, handler: types.EventHandler): this
238
+ // onFailed (eve: types.Events, entity: types.Target, handler: types.EventHandler): this
239
+ // onFailed (eve: types.Events, handler: types.EventHandler): this
240
+ before<T extends Constructable>(eve: types.event, entity: T, handler: CRUDEventHandler.Before<InstanceType<T>, InstanceType<T> | void | Error>): this
241
+ before(eve: types.event, entity: types.target, handler: EventHandler): this
242
+ before(eve: types.event, handler: EventHandler): this
243
+ after<T extends Constructable>(eve: types.event, entity: T, handler: CRUDEventHandler.After<InstanceType<T>, InstanceType<T> | void | Error>): this
244
+ after(eve: types.event, entity: types.target, handler: ResultsHandler): this
245
+ after(eve: types.event, handler: ResultsHandler): this
246
+ reject(eves: types.event, ...entity: types.target[]): this
256
247
  }
257
248
 
258
249
  export class ApplicationService extends Service {}
259
250
  export class MessagingService extends Service {}
260
251
  export class RemoteService extends Service {}
261
252
  export class DatabaseService extends Service {
262
- deploy(model?: csn | string): Promise<csn>
253
+ deploy(model?: CSN | string): Promise<CSN>
263
254
  begin(): Promise<void>
264
255
  commit(): Promise<void>
265
256
  rollback(): Promise<void>
266
257
  }
267
258
 
268
- export interface ResultSet extends Array<{}> {}
269
259
 
270
- declare class cds {
260
+ export default class cds {
271
261
  /**
272
262
  * @see [capire docs](https://cap.cloud.sap/docs/node.js/core-services)
273
263
  */
274
264
  Service: typeof Service
275
- Request: typeof Request
276
- Event: typeof Event
277
- EventContext: typeof EventContext
278
265
 
279
266
  /**
280
267
  * @see [capire docs](https://cap.cloud.sap/docs/node.js/app-services)
@@ -297,16 +284,24 @@ declare class cds {
297
284
  DatabaseService: typeof DatabaseService
298
285
  }
299
286
 
300
- export interface ServiceImpl {
287
+
288
+ interface Transaction extends Service {
289
+ commit(): Promise<void>
290
+ rollback(): Promise<void>
291
+ }
292
+
293
+ interface ResultSet extends Array<{}> {}
294
+
295
+ interface ServiceImpl {
301
296
  (this: Service, srv: Service): any
302
297
  }
303
298
 
304
- export interface EventHandler {
305
- // (msg : EventMessage) : Promise<any> | any | void
299
+ interface EventHandler {
300
+ // (msg : types.EventMessage) : Promise<any> | any | void
306
301
  (req: Request): Promise<any> | any | void
307
302
  }
308
303
 
309
- export interface OnEventHandler {
304
+ interface OnEventHandler {
310
305
  (req: Request, next: Function): Promise<any> | any | void
311
306
  }
312
307
 
@@ -335,7 +330,7 @@ type CdsFunction = {
335
330
  type TypedRequest<T> = Omit<Request, 'data'> & { data: T }
336
331
 
337
332
  // https://cap.cloud.sap/docs/node.js/core-services#srv-on-before-after
338
- export namespace CRUDEventHandler {
333
+ declare namespace CRUDEventHandler {
339
334
  type Before<P,R> = (req: TypedRequest<P>) => Promise<R> | R
340
335
  type On<P,R> = (req: TypedRequest<P>, next: (...args: any) => Promise<R> | R) => Promise<R> | R
341
336
  type After<P,R> = (data: undefined | P, req: TypedRequest<P>) => Promise<R> | R
@@ -345,7 +340,7 @@ export namespace CRUDEventHandler {
345
340
  // as strictly as possible and therefore have to remove
346
341
  // { data: any } (inherited EventMessage} with a more restricted
347
342
  // type, based on the parameters of the action.
348
- export interface ActionEventHandler<P,R> {
343
+ interface ActionEventHandler<P,R> {
349
344
  (req: Omit<Request, 'data'> & { data: P }, next: Function): Promise<R> | R
350
345
  }
351
346
 
@@ -361,27 +356,6 @@ interface ResultsHandler {
361
356
  (each: any, req: Request): void
362
357
  }
363
358
 
364
- /**
365
- * Represents the invocation context of incoming request and event messages.
366
- * @see [capire docs](https://cap.cloud.sap/docs/node.js/requests)
367
- */
368
- export class EventContext {
369
- timestamp: Date
370
- locale: string
371
- id: string
372
- user: User
373
- tenant: string
374
- }
375
-
376
- /**
377
- * @see [capire docs](https://cap.cloud.sap/docs/node.js/requests)
378
- */
379
- export class Event extends EventContext {
380
- event: string
381
- data: any
382
- headers: {}
383
- }
384
-
385
359
  interface SpawnEvents {
386
360
  'succeeded': (res: any) => void
387
361
  'failed': (error: any) => void
@@ -399,57 +373,12 @@ declare class SpawnEventEmitter {
399
373
  timer: any
400
374
  }
401
375
 
402
- interface Options {
403
- [key: string]: any
404
- every?: number
405
- after?: number
406
- }
407
-
408
- /**
409
- * @see [capire docs](https://cap.cloud.sap/docs/node.js/requests)
410
- */
411
- export class Request extends Event {
412
- params: (string | {})[]
413
- method: string
414
- path: string
415
- target: Definition
416
- /**
417
- * Shortcut to {@link target.name}
418
- *
419
- * @see https://cap.cloud.sap/docs/node.js/events#req-entity
420
- */
421
- entity: string
422
- query: CQNQuery
423
- subject: ref
424
-
425
- reply(results: any): void
426
-
427
- notify(code: number, message: string, target?: string, args?: {}): Error
428
- info(code: number, message: string, target?: string, args?: {}): Error
429
- warn(code: number, message: string, target?: string, args?: {}): Error
430
- error(code: number, message: string, target?: string, args?: {}): Error
431
- reject(code: number, message: string, target?: string, args?: {}): Error
432
-
433
- notify(message: string, target?: string, args?: {}): Error
434
- info(message: string, target?: string, args?: {}): Error
435
- warn(message: string, target?: string, args?: {}): Error
436
- error(message: string, target?: string, args?: {}): Error
437
- reject(message: string, target?: string, args?: {}): Error
438
-
439
- notify(message: { code?: number | string; message: string; target?: string; args?: {} }): Error
440
- info(message: { code?: number | string; message: string; target?: string; args?: {} }): Error
441
- warn(message: { code?: number | string; message: string; target?: string; args?: {} }): Error
442
- error(message: { code?: number | string; message: string; target?: string; args?: {}, status?: number }): Error
443
- reject(message: { code?: number | string; message: string; target?: string; args?: {}, status?: number }): Error
376
+ declare namespace types {
377
+ type event = eventName | eventName[]
378
+ type eventName = (string & {})
379
+ | 'CREATE' | 'READ' | 'UPDATE' | 'DELETE'
380
+ | 'NEW' | 'EDIT' | 'PATCH' | 'SAVE'
381
+ | 'GET' | 'PUT' | 'POST' | 'PATCH' | 'DELETE'
382
+ | 'COMMIT' | 'ROLLBACK'
383
+ type target = string | LinkedDefinition | ArrayConstructable<any>
444
384
  }
445
-
446
- export default cds
447
-
448
- type EventArg = EventName | EventName[]
449
- type EventName = (CRUD | TX | HTTP | DRAFT) | (CustomOp & {})
450
- type CRUD = 'CREATE' | 'READ' | 'UPDATE' | 'DELETE'
451
- type DRAFT = 'NEW' | 'EDIT' | 'PATCH' | 'SAVE'
452
- type HTTP = 'GET' | 'PUT' | 'POST' | 'PATCH' | 'DELETE'
453
- type TX = 'COMMIT' | 'ROLLBACK'
454
- type CustomOp = string
455
- type Target = string | Definition | ArrayConstructable<any>
package/apis/test.d.ts CHANGED
@@ -40,7 +40,7 @@ declare class Test extends Axios {
40
40
  get expect(): typeof chai.expect;
41
41
  get assert(): typeof chai.assert;
42
42
  get data(): DataUtil;
43
- get cds(): typeof import('./cds').default;
43
+ get cds(): typeof import('./cds')
44
44
 
45
45
  log() : {
46
46
  output: string
package/bin/serve.js CHANGED
@@ -191,6 +191,9 @@ async function serve (all=[], o={}) {
191
191
  // bootstrap server from project-local server.js or from @sap/cds/server.js
192
192
  const server = await cds_server(o)
193
193
 
194
+ // increase keep-alive timeout for CF (gorouter wants >90s)
195
+ if (process.env.VCAP_APPLICATION?.cf_api) server.keepAliveTimeout = 91 * 1000
196
+
194
197
  // return a promise which resolves to the created http server when listening
195
198
  return cds.server.listening = new Promise ((_resolve,_reject) => {
196
199
 
@@ -15,7 +15,6 @@ const compile = module.exports = Object.assign (cds_compile, {
15
15
  to: new class {
16
16
  get csn() { return super.csn = require('./to/csn') }
17
17
  get cdl() { return super.cdl = require('./to/cdl') }
18
- get gql() { return super.gql = require('./to/gql') }
19
18
  get yml() { return super.yml = require('./to/yaml') }
20
19
  get yaml() { return super.yaml = require('./to/yaml') }
21
20
  get json() { return super.json = require('./to/json') }
@@ -26,7 +25,8 @@ const compile = module.exports = Object.assign (cds_compile, {
26
25
  get hdbtable() { return super.hdbtable = compile.to.sql.hdbtable }
27
26
  get hdbtabledata() { return super.hdbtabledata = require('./to/hdbtabledata') }
28
27
  get serviceinfo() { return super.serviceinfo = require('./to/srvinfo') } //> REVISIT: move to CLI
29
- get graphql() { return super.graphql = require('./to/gql') } //> REVISIT: move to gql CLI plugin
28
+ get gql() { return super.gql = require('./to/gql') } //> REVISIT: moved to @cap-js/graphql, remove with cds^8
29
+ get graphql() { return super.graphql = require('./to/gql') } //> REVISIT: moved to @cap-js/graphql, remove with cds^8
30
30
  },
31
31
 
32
32
  })
@@ -3,9 +3,14 @@ const cds = require ('../../index')
3
3
 
4
4
  if (cds.env.features.precompile_edms !== false) {
5
5
  const _precompiled = new WeakMap
6
- cdsc.to.edm = Object.assign ((csn,o)=>{
7
- if (!_precompiled.has(csn)) _precompiled.set (csn, cdsc.to.edm.all (csn,o))
8
- return _precompiled.get(csn) [o.service]
6
+ cdsc.to.edm = Object.assign((csn, o) => {
7
+ if (o.to === 'openapi') return cdsc.to.edm.all(csn, o)[o.service]
8
+ if (!_precompiled.has(csn)) {
9
+ // only for services that are served via odata
10
+ const serviceNames = o.serviceNames || Object.values(csn.definitions).filter(d => d.kind === 'service' && d.endpoints?.some(e => e.kind.match(/odata/i))).map(d => d.name)
11
+ _precompiled.set(csn, cdsc.to.edm.all(csn, Object.assign({ serviceNames }, o)))
12
+ }
13
+ return _precompiled.get(csn)[o.service]
9
14
  }, { all: cdsc.to.edm.all })
10
15
  }
11
16
 
@@ -1,8 +1,12 @@
1
1
  const cds = require ('../..')
2
+ const LOG = cds.log()
2
3
  // eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
3
4
  const { SchemaGenerator } = require('@cap-js/graphql/lib/schema')
4
5
 
6
+ // REVISIT: remove module with cds^8
5
7
  function cds_compile_to_gql (csn) {
8
+ LOG._warn && LOG.warn('WARNING: cds.compile.to.gql and .to.graphql will require @cap-js/graphql >= 0.9.0 with an upcoming release. Please update your dependency.')
9
+
6
10
  const m = cds.linked(csn)
7
11
  const services = Object.fromEntries(m.services.map(s => [s.name, new cds.ApplicationService(s.name, m)]))
8
12
  return new SchemaGenerator().generate(services).printSchema()
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  const cds = require('../index'), { local } = cds.utils
3
+ const crypto = require('crypto')
3
4
  const COLORS = !!process.stdout.isTTY && !!process.stderr.isTTY && !process.env.NO_COLOR
4
5
  const GREY = COLORS ? '\x1b[2m' : ''
5
6
  const RESET = COLORS ? '\x1b[0m' : ''
@@ -211,7 +212,7 @@ exports.init = async function cds_deploy_init (db, csn=db.model, o, srces, log=(
211
212
  const m = tx.model = cds.compile.for.nodejs(csn) //> use correct model while deploying
212
213
  const data = await exports.data (m,srces)
213
214
  const query = _queries4 (db,m)
214
- const INSERT_from = INSERT_from4 (db,o)
215
+ const INSERT_from = INSERT_from4 (db,m,o)
215
216
 
216
217
  for await (let [ file, entity, src ] of data) {
217
218
  log (file)
@@ -344,21 +345,67 @@ const _queries4 = (db,csn) => !db.cqn2sql ? q => q : q => {
344
345
  }
345
346
 
346
347
 
347
- const INSERT_from4 = (db,o) => {
348
+ const INSERT_from4 = (db,m,o) => {
348
349
  const schevo = o?.schema_evolution === 'auto' || db.options.schema_evolution === 'auto'
349
350
  const INSERT_into = (schevo ? UPSERT : INSERT).into
350
351
  return (file) => ({
351
352
  '.json': { into (entity, json) {
352
353
  let records = JSON.parse(json)
353
- if (records.length > 0) return INSERT_into(entity).entries(records)
354
+ if (records.length > 0) {
355
+ fill_ID_texts_json(records, m, entity)
356
+ return INSERT_into(entity).entries(records)
357
+ }
354
358
  }},
355
359
  '.csv': { into (entity, csv) {
356
360
  let [cols, ...rows] = cds.parse.csv(csv)
357
- if (rows.length > 0) return INSERT_into(entity).columns(cols).rows(rows)
361
+ if (rows.length > 0) {
362
+ fill_ID_texts_csv(cols, rows, m, entity)
363
+ return INSERT_into(entity).columns(cols).rows(rows)
364
+ }
358
365
  }},
359
366
  }) [path.extname(file)]
360
367
  }
361
368
 
369
+ const fill_ID_texts_json = (records, m, entity) => {
370
+ const baseKey = idTextsBaseKey(m, entity)
371
+ if (baseKey) {
372
+ records.forEach(record => {
373
+ if (!record.ID_texts) {
374
+ record.ID_texts = hashedUUID(record[baseKey], record.locale)
375
+ }
376
+ })
377
+ }
378
+ }
379
+
380
+ const fill_ID_texts_csv = (cols, rows, m, entity) => {
381
+ const baseKey = idTextsBaseKey(m, entity)
382
+ if (baseKey && !cols.find(r => r.toLowerCase() === 'id_texts')) { // and no such column in csv?
383
+ DEBUG?.(`adding ID_texts for ${entity}`)
384
+ const indexBaseKey = cols.findIndex(c => c.toLowerCase() === baseKey.toLowerCase())
385
+ const indexLocale = cols.findIndex(c => c.toLowerCase() === 'locale')
386
+ rows.forEach(row => {
387
+ const idtexts = hashedUUID(row[indexBaseKey], row[indexLocale])
388
+ row.push(idtexts)
389
+ })
390
+ cols.push('ID_texts')
391
+ }
392
+ }
393
+
394
+ const idTextsBaseKey = (m, entity) => {
395
+ let base
396
+ if (m.definitions[entity]?.keys?.ID_texts // ID_text key?
397
+ && /(.+)[._]texts$/.test(entity) && (base = m.definitions[RegExp.$1])) { // in a .text entity?
398
+ const baseKey = Object.keys(base.keys)[0] // base entity's key is usually, but not always 'ID'
399
+ return baseKey
400
+ }
401
+ }
402
+
403
+ const hashedUUID = (...values) => {
404
+ const sum = values.reduce((acc, curr) => acc + curr, '')
405
+ const h = crypto.createHash('md5').update(sum).digest('hex')
406
+ return h.slice(0, 8) + '-' + h.slice(8, 12) + '-' + h.slice(12, 16) + '-' + h.slice(16, 20) + '-' + h.slice(20)
407
+ }
408
+
362
409
  const _skip = e => !e || e['@cds.persistence.skip'] === true
363
410
 
364
411
 
@@ -385,3 +432,4 @@ if (!module.parent) (async () => {
385
432
  await db?.disconnect?.()
386
433
  }
387
434
  })().catch(console.error)
435
+
@@ -160,6 +160,24 @@ const _databases = {
160
160
  }
161
161
 
162
162
 
163
+ const _outbox = {
164
+
165
+ outbox: {
166
+ kind: "persistent-outbox",
167
+ parallel: true
168
+ },
169
+
170
+ "in-memory-outbox": {},
171
+ "persistent-outbox": {
172
+ model: "@sap/cds/srv/outbox",
173
+ maxAttempts: 20,
174
+ chunkSize: 100,
175
+ storeLastError: true
176
+ }
177
+
178
+ }
179
+
180
+
163
181
  const _messaging = {
164
182
 
165
183
  "local-messaging": {
@@ -167,9 +185,9 @@ const _messaging = {
167
185
  local: true
168
186
  },
169
187
  "file-based-messaging": {
170
- outbox: {},
171
188
  impl: `${_runtime}/messaging/file-based.js`,
172
- file:'~/.cds-msg-box'
189
+ file:'~/.cds-msg-box',
190
+ outbox: true
173
191
  },
174
192
  "default-messaging": {
175
193
  "[development]": { kind: "local-messaging" },
@@ -186,19 +204,19 @@ const _messaging = {
186
204
  kind: "enterprise-messaging-amqp",
187
205
  },
188
206
  "enterprise-messaging-http": {
189
- outbox: {},
190
207
  deployForProvider: true,
191
208
  impl: `${_runtime}/messaging/enterprise-messaging.js`,
192
209
  vcap: { label: "enterprise-messaging" },
210
+ outbox: true
193
211
  },
194
212
  "enterprise-messaging-amqp": {
195
- outbox: {},
196
213
  impl: `${_runtime}/messaging/enterprise-messaging-shared.js`,
197
214
  vcap: { label: "enterprise-messaging" },
215
+ outbox: true
198
216
  },
199
217
  'message-queuing': {
200
- outbox: {},
201
- impl: `${_runtime}/messaging/message-queuing.js`
218
+ impl: `${_runtime}/messaging/message-queuing.js`,
219
+ outbox: true
202
220
  },
203
221
  "composite-messaging": {
204
222
  impl: `${_runtime}/messaging/composite.js`
@@ -212,15 +230,8 @@ const _messaging = {
212
230
  "redis-messaging": {
213
231
  impl: `${_runtime}/messaging/redis-messaging.js`,
214
232
  vcap: { label: "redis-cache" },
215
- outbox: {}
216
- },
217
-
218
- "persistent-outbox": {
219
- model: "@sap/cds/srv/outbox",
220
- maxAttempts: 20,
221
- chunkSize: 100,
222
- storeLastError: true
223
- },
233
+ outbox: true
234
+ }
224
235
 
225
236
  }
226
237
 
@@ -242,6 +253,7 @@ exports.kinds = {
242
253
  ..._authentication_strategies,
243
254
  ..._databases,
244
255
  ..._services,
256
+ ..._outbox,
245
257
  ..._messaging,
246
258
  ..._platform_services,
247
259
  }
@@ -43,6 +43,7 @@ const defaults = module.exports = {
43
43
  preview: !production,
44
44
  routes: !production,
45
45
  lean_draft: true,
46
+ wrap_multiple_errors: true, // switch default with cds 8
46
47
  draft_compat: undefined,
47
48
  '[better-sqlite]': { lean_draft: true },
48
49
  '[lean-draft]': { lean_draft: true },
@@ -0,0 +1,10 @@
1
+ const { readFile } = require('fs').promises
2
+ const { join } = require('path')
3
+
4
+ module.exports = new class {
5
+ async default4(name) {
6
+ let file = join(__dirname, name)
7
+ let json = await readFile(file, 'utf8')
8
+ return JSON.parse(json)
9
+ }
10
+ }