@sap/cds 8.5.0 → 8.6.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 (81) hide show
  1. package/CHANGELOG.md +54 -3
  2. package/_i18n/i18n.properties +4 -7
  3. package/eslint.config.mjs +1 -1
  4. package/lib/compile/etc/properties.js +2 -2
  5. package/lib/compile/for/java.js +15 -3
  6. package/lib/compile/for/lean_drafts.js +44 -34
  7. package/lib/compile/for/nodejs.js +19 -10
  8. package/lib/compile/minify.js +2 -4
  9. package/lib/compile/parse.js +106 -72
  10. package/lib/compile/to/edm.js +19 -9
  11. package/lib/compile/to/hana.js +25 -21
  12. package/lib/compile/to/sql.js +15 -8
  13. package/lib/core/linked-csn.js +10 -4
  14. package/lib/dbs/cds-deploy.js +2 -2
  15. package/lib/env/cds-env.js +76 -66
  16. package/lib/env/defaults.js +1 -0
  17. package/lib/i18n/bundles.js +2 -1
  18. package/lib/i18n/localize.js +2 -2
  19. package/lib/index.js +24 -18
  20. package/lib/ql/CREATE.js +11 -6
  21. package/lib/ql/DELETE.js +12 -9
  22. package/lib/ql/DROP.js +15 -8
  23. package/lib/ql/INSERT.js +19 -14
  24. package/lib/ql/SELECT.js +95 -168
  25. package/lib/ql/UPDATE.js +23 -14
  26. package/lib/ql/UPSERT.js +15 -2
  27. package/lib/ql/Whereable.js +44 -118
  28. package/lib/ql/cds-ql.js +222 -28
  29. package/lib/ql/{Query.js → cds.ql-Query.js} +52 -41
  30. package/lib/ql/cds.ql-predicates.js +133 -0
  31. package/lib/ql/cds.ql-projections.js +111 -0
  32. package/lib/ql/cqn.d.ts +146 -0
  33. package/lib/srv/cds-connect.js +3 -3
  34. package/lib/srv/cds-serve.js +2 -2
  35. package/lib/srv/cds.Service.js +132 -0
  36. package/lib/srv/{srv-api.js → cds.ServiceClient.js} +16 -71
  37. package/lib/srv/cds.ServiceProvider.js +20 -0
  38. package/lib/srv/factory.js +20 -8
  39. package/lib/srv/protocols/hcql.js +2 -3
  40. package/lib/srv/protocols/index.js +3 -3
  41. package/lib/srv/srv-dispatch.js +7 -6
  42. package/lib/srv/srv-handlers.js +103 -113
  43. package/lib/srv/srv-methods.js +14 -14
  44. package/lib/srv/srv-tx.js +5 -3
  45. package/lib/utils/cds-utils.js +2 -2
  46. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +3 -3
  47. package/libx/_runtime/cds.js +2 -1
  48. package/libx/_runtime/common/aspects/service.js +25 -0
  49. package/libx/_runtime/common/generic/auth/index.js +5 -0
  50. package/libx/_runtime/common/generic/auth/restrict.js +36 -14
  51. package/libx/_runtime/common/generic/auth/service.js +24 -0
  52. package/libx/_runtime/common/generic/auth/utils.js +14 -6
  53. package/libx/_runtime/common/generic/etag.js +1 -1
  54. package/libx/_runtime/common/utils/cqn.js +1 -2
  55. package/libx/_runtime/common/utils/cqn2cqn4sql.js +1 -1
  56. package/libx/_runtime/common/utils/generateOnCond.js +7 -3
  57. package/libx/_runtime/common/utils/postProcess.js +4 -1
  58. package/libx/_runtime/common/utils/restrictions.js +1 -0
  59. package/libx/_runtime/fiori/lean-draft.js +53 -42
  60. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -1
  61. package/libx/_runtime/remote/Service.js +2 -0
  62. package/libx/_runtime/remote/utils/client.js +12 -0
  63. package/libx/odata/ODataAdapter.js +2 -1
  64. package/libx/odata/index.js +5 -3
  65. package/libx/odata/middleware/batch.js +4 -0
  66. package/libx/odata/middleware/create.js +2 -2
  67. package/libx/odata/middleware/delete.js +2 -2
  68. package/libx/odata/middleware/operation.js +2 -2
  69. package/libx/odata/middleware/read.js +14 -12
  70. package/libx/odata/middleware/service-document.js +16 -8
  71. package/libx/odata/middleware/update.js +2 -2
  72. package/libx/odata/parse/afterburner.js +64 -30
  73. package/libx/odata/parse/grammar.peggy +95 -0
  74. package/libx/odata/parse/parser.js +1 -1
  75. package/libx/odata/utils/index.js +6 -1
  76. package/libx/odata/utils/metadata.js +69 -75
  77. package/libx/odata/utils/postProcess.js +24 -3
  78. package/package.json +1 -1
  79. package/server.js +1 -1
  80. package/lib/ql/parse.js +0 -36
  81. /package/lib/ql/{infer.js → cds.ql-infer.js} +0 -0
@@ -7,13 +7,20 @@ const TRACE = cds.debug('trace')
7
7
 
8
8
  function cds_compile_to_sql (csn,_o) {
9
9
  TRACE?.time('cdsc.compile 2sql'.padEnd(22))
10
- csn = cds.minify(csn)
11
- const o = cdsc._options.for.sql(_o) //> used twice below...
12
- const all = cdsc.to.sql(csn,o) .map (each => each.replace(/^-- .+\n/,'')) //> strip comments
13
- const sql = unfold_ddl(all, csn, o)
14
- TRACE?.timeEnd('cdsc.compile 2sql'.padEnd(22))
15
- if (o.as === 'str') return `\n${sql.join('\n\n')}\n`
16
- return sql
10
+ try {
11
+ let result, next = ()=> result ??= function (){
12
+ csn = cds.minify(csn)
13
+ const o = cdsc._options.for.sql(_o) //> used twice below...
14
+ const all = cdsc.to.sql(csn,o) .map (each => each.replace(/^-- .+\n/,'')) //> strip comments
15
+ const sql = unfold_ddl(all, csn, o)
16
+ TRACE?.timeEnd('cdsc.compile 2sql'.padEnd(22))
17
+ if (o.as === 'str') return `\n${sql.join('\n\n')}\n`
18
+ return sql
19
+ }()
20
+ cds.emit ('compile.to.dbx', csn, _o, next)
21
+ return result ??= next() //> in case no handler called next
22
+ }
23
+ finally { TRACE?.timeEnd('cds.compile 2sql'.padEnd(22)) }
17
24
  }
18
25
 
19
26
  function cds_compile_to_hdbtable (csn,o) {
@@ -23,7 +30,7 @@ function cds_compile_to_hdbtable (csn,o) {
23
30
 
24
31
  function cds_compile_to_hana(csn, o, beforeCsn) {
25
32
  return require('./hana')(cds.minify(csn), o, beforeCsn)
26
- }
33
+ }
27
34
 
28
35
  function cds_compile_to_deltaSql (csn, o, beforeCsn) {
29
36
  const options = cdsc._options.for.sql(o)
@@ -13,9 +13,10 @@ const _kinds = {
13
13
 
14
14
  class LinkedCSN {
15
15
 
16
- constructor(x) {
16
+ constructor (x,...etc) {
17
17
 
18
- if (typeof x === 'string') x = require('../index').compile(x) //> for convenience in repl
18
+ if (x.raw) x = require('../index').compile(String.raw(x,...etc)) //> for convenience in repl
19
+ else if (typeof x === 'string') x = require('../index').compile(x) //> for convenience in repl
19
20
  const defs = x.definitions = _iterable (x.definitions||{})
20
21
  for (let d in defs) _link (defs[d],d)
21
22
  return Object.setPrototypeOf (x, new.target.prototype)
@@ -124,7 +125,7 @@ class LinkedCSN {
124
125
  const _iterable = defs => defs && Object.setPrototypeOf (defs, LinkedDefinitions.prototype)
125
126
  const _unresolved = (x, unknown = types.any) => ({ name:x, __proto__:unknown, _unresolved:true })
126
127
  const _builtin = x => types[x] || x.startsWith?.('cds.hana.') && types.any
127
- const _infer = require('../ql/infer')
128
+ const _infer = require('../ql/cds.ql-infer')
128
129
  const _set = (o,p,v,e=false) => Object.defineProperty (o,p,{ value:v, enumerable:e, configurable:1, writable:1 })
129
130
  const _own = (o,p) => { const pd = Reflect.getOwnPropertyDescriptor(o,p); return pd && pd.value }
130
131
  const _is = x => {
@@ -140,4 +141,9 @@ any.prototype.set('is_linked', true)
140
141
 
141
142
 
142
143
  /** @returns {LinkedCSN} */
143
- module.exports = Object.assign (x => x.is_linked ? x : new LinkedCSN (x), { LinkedCSN, LinkedDefinitions, types, classes })
144
+ const cds_linked = x => !x || x.is_linked ? x : new LinkedCSN (x)
145
+
146
+ module.exports = Object.assign (cds_linked, {
147
+ LinkedCSN, LinkedDefinitions,
148
+ types, classes
149
+ })
@@ -7,7 +7,7 @@ const TRACE = cds.debug('trace')
7
7
  /** Fluent API: cds.deploy(model).to(db) */
8
8
  const deploy = module.exports = function cds_deploy (model, options, csvs) {
9
9
 
10
- return { async to (/** @type {import('../../lib/srv/srv-api')} */ db, o = options||{}) {
10
+ return { async to (/** @type {import('../srv/cds.ServiceClient')} */ db, o = options||{}) {
11
11
  /* eslint-disable no-console */
12
12
 
13
13
  // prepare logging
@@ -37,7 +37,7 @@ const deploy = module.exports = function cds_deploy (model, options, csvs) {
37
37
  const _run = fn => o.dry ? fn(db) : db.run(fn)
38
38
  await _run (async tx => {
39
39
  let any = await deploy.schema (tx, model, o)
40
- if (any || csvs) await deploy.data (tx, model, o, csvs, file => LOG?.(GREY, ' > init from', local(file), RESET))
40
+ if ((any || csvs) && !o.dry) await deploy.data (tx, model, o, csvs, file => LOG?.(GREY, ' > init from', local(file), RESET))
41
41
  })
42
42
  LOG?.('/> successfully deployed to', descr, '\n')
43
43
  } catch (e) {
@@ -1,7 +1,7 @@
1
1
  const { isdir, isfile, fs, path } = require('../utils/cds-utils')
2
2
  const DEFAULTS = require('./defaults'), defaults = require.resolve ('./defaults')
3
3
  const compat = require('./compat')
4
- const serviceBindings = require('./serviceBindings');
4
+ const DEBUG = /\b(y|all|env)\b/.test(process.env.DEBUG) ? console.debug : undefined
5
5
 
6
6
 
7
7
  /**
@@ -48,20 +48,25 @@ class Config {
48
48
  if (_context === 'cds' && _defaults) compat (this)
49
49
  if (!_home) return
50
50
 
51
- // Fill-in process.env from .env files...
52
- this._add_to_process_env (_home, 'default-env.json')
53
- if (this._profiles.has('development')) this._add_to_process_env (_home, '.env')
54
-
55
- // Read config sources in defined order
56
- const sources = this.sources(_home, _context)
57
- for (let { path:dir, file, mapper = x=>x } of sources) {
58
- let src = path.join(dir,file)
59
- let json = _readJson(src,{paths:[_home]}); if (!json) continue
60
- if (json.dependencies?.['@sap/cds-mtx']) {
61
- console.error('@sap/cds-mtx is not supported by @sap/cds >= 7. Please upgrade to @sap/cds-mtxs following the migration guide on https://cap.cloud.sap/docs/guides/multitenancy/old-mtx-migration.')
62
- process.exit(1)
51
+ // Read config sources in reverse order of precedence -> last one wins
52
+ if (_context !== 'cds') {
53
+ this.#import (_home,'package.json', { get: p => p[_context] })
54
+ } else {
55
+ for (let {impl} of Object.values(this.plugins)) {
56
+ const _plugin = path.dirname(impl)
57
+ this.#import (_plugin,'.cdsrc.yaml', { load: _readYaml })
58
+ this.#import (_plugin,'.cdsrc.json')
59
+ this.#import (_plugin,'.cdsrc.js')
60
+ this.#import (_plugin,'package.json', { get: p => p.cds })
63
61
  }
64
- this.add (mapper(json), src)
62
+ const user_ = process.env.CDS_USER_HOME || require('os').homedir()
63
+ this.#import (user_,'.cdsrc.json')
64
+ this.#import (user_,'.cdsrc.js')
65
+ this.#import (_home,'.cdsrc.yaml', { load: _readYaml })
66
+ this.#import (_home,'.cdsrc.json')
67
+ this.#import (_home,'.cdsrc.js')
68
+ this.#import (_home,'package.json', { get: _ext_package_json })
69
+ this.#import (_home,'.cdsrc-private.json')
65
70
  }
66
71
 
67
72
  // Apply important (!) profiles from config sources
@@ -69,7 +74,7 @@ class Config {
69
74
  delete this._profiles._important
70
75
 
71
76
  // Add process env before linking to allow things like CDS_requires_db=sql
72
- this._add_process_env(_context, _home)
77
+ this._add_process_env()
73
78
 
74
79
  // Link cds.requires services to cds.requires.kinds
75
80
  this._link_required_services()
@@ -93,31 +98,21 @@ class Config {
93
98
  }
94
99
  }
95
100
 
96
- /**
97
- * Get configuration sources
98
- * @param {string} home Project home
99
- * @param {string} context configuration context literal
100
- */
101
- sources (home, context = 'cds') {
102
- if (!home) throw new Error('Missing parameter "home".')
103
- if (context !== 'cds') return [
104
- { path: home, file: 'package.json', mapper: x => x[context] },
105
- ]
106
- const user_home = process.env.CDS_USER_HOME || require('os').homedir()
107
- return [
108
- ...Object.keys(this.plugins).map (root => ({
109
- path: root, file: 'package.json', mapper: x => x.cds
110
- })),
111
- { path: user_home, file: '.cdsrc.json', mapper: x => x.cds||x },
112
- { path: home, file: '.cdsrc.json', mapper: x => x.cds||x },
113
- { path: home, file: 'package.json', mapper: _package_json },
114
- { path: home, file: '.cdsrc-private.json', mapper: x => x.cds||x },
115
- ]
116
- function _package_json (pkg) { // fill cds.extends from .extends
117
- let cds = pkg.cds
118
- if (pkg.extends) (cds??={}).extends = pkg.extends
119
- return cds
120
- }
101
+
102
+ #import (dir, file, etc) {
103
+ let conf = this.load (dir, file, etc)
104
+ if (conf) this.add (conf)
105
+ }
106
+
107
+
108
+ load (dir, file, { load=_readJson, get = x => x.cds||x } = {}) {
109
+ file = path.join (dir, file)
110
+ DEBUG?.('[cds.env] - checking', {file})
111
+ let cont = load(file); if (!cont) return
112
+ let conf = get(cont); if (!conf) return
113
+ DEBUG?.('[cds.env] - importing', file)
114
+ this._sources.push (file)
115
+ return conf
121
116
  }
122
117
 
123
118
 
@@ -194,25 +189,25 @@ class Config {
194
189
  // The following are internal APIs which can always change!
195
190
  //
196
191
 
197
- _add_to_process_env (cwd, filename) {
198
- const file = path.resolve (cwd,filename)
199
- try {
200
- const all = require('../compile/etc/properties').read(file); if (!all) return
201
- for (const key in all) {
202
- if (key in process.env) continue // do not change existing env vars
203
- const val = all[key]
204
- process.env[key] = typeof val === 'string' ? val : JSON.stringify(val)
205
- }
206
- this._sources.push (file)
207
- } catch (e) {
208
- if (e instanceof SyntaxError) console.error(`Error parsing '${file}': ${e.message}`)
209
- else if (e.code !== 'MODULE_NOT_FOUND') console.error(e.message)
192
+ _add_to_env (filename, env = process.env) {
193
+ const _env = this.load (this._home, filename, { load: _readEnv })
194
+ for (const key in _env) {
195
+ if (key in env) continue // do not change existing env vars
196
+ const val = _env[key]
197
+ env[key] = typeof val === 'string' ? val : JSON.stringify(val)
210
198
  }
211
199
  }
212
200
 
213
-
214
- _add_process_env (prefix, basePath) {
201
+ _add_process_env() {
202
+ const prefix = this._context, cwd = this._home
215
203
  const {env} = process
204
+ if (this._profiles.has('development')) {
205
+ this._add_to_env ('default-env.json', env)
206
+ for (let each of this._profiles)
207
+ each === 'development' || this._add_to_env (`.${each}.env`, env)
208
+ this._add_to_env ('.env', env)
209
+ }
210
+
216
211
  const PREF = prefix.toUpperCase(), my = { CONFIG: PREF+'_CONFIG', ENV: PREF+'_ENV' }
217
212
  let config
218
213
 
@@ -224,7 +219,7 @@ class Config {
224
219
  // CDS_CONFIG=/path/to/config.json *OR* CDS_CONFIG=/path/to/config/dir
225
220
  if (typeof val === "string") {
226
221
  // Load from JSON file or directory; No profile support!
227
- if (basePath && !path.isAbsolute(val)) val = path.join(basePath, val)
222
+ if (cwd && !path.isAbsolute(val)) val = path.join(cwd, val)
228
223
  const json = _readJson(val) || _readFromDir(val)
229
224
  if (json) this.add (json, val, false)
230
225
  }
@@ -246,7 +241,7 @@ class Config {
246
241
  o[next] = _value4(env[p])
247
242
  }
248
243
 
249
- this.add(config, 'process.env')
244
+ if (Object.keys(config).length) this.add (config, 'process.env')
250
245
  }
251
246
 
252
247
  _link_required_services () {
@@ -312,7 +307,7 @@ class Config {
312
307
  }
313
308
 
314
309
  if (!bindings && SERVICE_BINDING_ROOT) {
315
- bindings = serviceBindings(SERVICE_BINDING_ROOT)
310
+ bindings = require('./serviceBindings')(SERVICE_BINDING_ROOT)
316
311
  bindingsSource = SERVICE_BINDING_ROOT
317
312
  }
318
313
 
@@ -435,7 +430,7 @@ class Config {
435
430
  */
436
431
  function _add_static_profiles (_home, profiles) {
437
432
  for (let src of ['package.json', '.cdsrc.json']) try {
438
- const conf = require(path.join(_home,src))
433
+ const conf = require(path.join(_home,src))
439
434
  const cds = src === 'package.json' ? conf.cds : conf.cds||conf
440
435
  if (cds?.profiles) return profiles.push(...cds.profiles)
441
436
  if (cds?.profile) return profiles.push(cds.profile)
@@ -495,17 +490,26 @@ function _value4 (val) {
495
490
  return val
496
491
  }
497
492
 
498
- function _readJson (file, _options) {
499
- try {
500
- const src = fs.readFileSync (require.resolve(file,_options))
501
- return JSON.parse (src)
502
- } catch (e) {
503
- if (e instanceof SyntaxError) console.error(`Error parsing '${file}': ${e.message}`)
504
- else if (e.code !== 'MODULE_NOT_FOUND') console.error(e.message)
493
+ function _readJson (file) {
494
+ if (isfile(file)) {
495
+ if (file.endsWith('.js')) return require (file)
496
+ try { return JSON.parse (fs.readFileSync(file,'utf-8')) } catch (e) { console.error(e) }
505
497
  }
506
498
  }
507
499
 
500
+ function _readYaml (file) {
501
+ if (isfile(file)) {
502
+ const YAML = _readYaml.parser ??= require('../compile/etc/yaml')
503
+ return YAML.parse (fs.readFileSync(file,'utf-8'))
504
+ }
505
+ }
508
506
 
507
+ function _readEnv (file) {
508
+ if (isfile(file)) {
509
+ const ENV = _readEnv.parser = require('../compile/etc/properties')
510
+ return ENV.parse (fs.readFileSync(file,'utf-8'))
511
+ }
512
+ }
509
513
 
510
514
  function _readFromDir (p) {
511
515
  if (isdir(p)) {
@@ -516,6 +520,12 @@ function _readFromDir (p) {
516
520
  return _value4(fs.readFileSync(p, "utf-8"))
517
521
  }
518
522
 
523
+ // REVISIT: We need to get rid of such hard-coded stuff
524
+ function _ext_package_json (pkg) { // fill cds.extends from .extends
525
+ let cds = pkg.cds
526
+ if (pkg.extends) (cds??={}).extends = pkg.extends
527
+ return cds
528
+ }
519
529
 
520
530
 
521
531
  /** @type Config & typeof DEFAULTS */
@@ -152,6 +152,7 @@ const defaults = module.exports = {
152
152
  /** @deprecated */ for_sqlite: ['de', 'fr'],
153
153
  /** @deprecated */ for_sql: ['de', 'fr'],
154
154
  /** @deprecated */ fallback_bundle: '',
155
+ /** @deprecated */ fatjson: true, // REVISIT: remove in cds9
155
156
  },
156
157
 
157
158
  odata: {
@@ -73,7 +73,8 @@ class I18nBundle {
73
73
  if (lang in $) return $[locale] = $[lang] // already cached -> leave method
74
74
  else all = this.files.content4 (lang, lang) // load content for language only
75
75
  }
76
- const texts = Object.create ((_defaults ?? this.defaults) || Object.prototype)
76
+ const defaults = (_defaults ?? this.defaults) || Object.prototype
77
+ const texts = i18n.fatjson ? Object.assign ({},defaults) : Object.create (defaults)
77
78
  return $[locale] = $[suffix] = Object.assign (texts, ...all)
78
79
  }
79
80
 
@@ -56,8 +56,8 @@ class Localize {
56
56
 
57
57
  module.exports = exports = localize
58
58
 
59
- function localize (input) {
60
- if (arguments.length > 1) return exports.legacy (...arguments)
59
+ function localize (input,...etc) {
60
+ if (etc.length) return exports.legacy (input,...etc)
61
61
  return new Localize (input)
62
62
  }
63
63
 
package/lib/index.js CHANGED
@@ -4,15 +4,18 @@ if (process.env.CDS_STRICT_NODE_VERSION !== 'false') require ('./utils/check-ver
4
4
  const { EventEmitter } = require('node:events')
5
5
  const cds = module.exports = global.cds = new class cds extends EventEmitter {
6
6
 
7
- /** @typedef {import('./srv/srv-api.js')} Service */
8
- /** @type {import('./core/linked-csn.js')} */ model = undefined
7
+ /** @typedef {import('./srv/cds.ServiceProvider')} Service */
8
+ /** @type {import('./core/linked-csn')} */ model = undefined
9
9
  /** @type Service */ db = undefined
10
10
  /** CLI args */ cli = { command:'', options:{}, argv:[] }
11
11
  /** Working dir */ root = process.cwd()
12
12
 
13
- async emit (eve, ...args) {
14
- if (eve === 'served') for (let each of this.listeners(eve)) await each.call(this,...args)
15
- else return super.emit (eve, ...args)
13
+ emit (eve, ...args) {
14
+ if (eve === 'served') return this.listeners(eve) .reduce (
15
+ (p,each) => p.then(()=> each.call(this,...args)),
16
+ Promise.resolve()
17
+ )
18
+ else return super.emit (eve, ...args)
16
19
  }
17
20
 
18
21
  // Configuration & Information
@@ -69,7 +72,7 @@ const cds = module.exports = global.cds = new class cds extends EventEmitter {
69
72
  shutdown() { this.app?.server && process.exit() } // is overridden in bin/serve.js
70
73
 
71
74
  // Core Services API
72
- get Service() { return super.Service = require('./srv/srv-api') }
75
+ get Service() { return super.Service = require('./srv/cds.ServiceProvider') }
73
76
  get EventContext() { return super.EventContext = require('./req/context') }
74
77
  get Request() { return super.Request = require('./req/request') }
75
78
  get Event() { return super.Event = require('./req/event') }
@@ -82,7 +85,7 @@ const cds = module.exports = global.cds = new class cds extends EventEmitter {
82
85
  get DatabaseService() { return super.DatabaseService = require('../libx/_runtime/db/Service.js') }
83
86
  get RemoteService() { return super.RemoteService = require('../libx/_runtime/remote/Service.js') }
84
87
 
85
- /** Contexts and Transactions @type {import('./req/context.js')} */
88
+ /** Contexts and Transactions @type {import('./req/context')} */
86
89
  get context() { return this._context.getStore() }
87
90
  set context(x) { this._context.enterWith(x) }
88
91
  get spawn() { return super.spawn = this._context.spawn }
@@ -98,7 +101,7 @@ const cds = module.exports = global.cds = new class cds extends EventEmitter {
98
101
  clone(x) { return structuredClone(x) }
99
102
 
100
103
  // Querying and Databases
101
- get infer(){ return super.infer = require('./ql/infer') }
104
+ get infer(){ return super.infer = require('./ql/cds.ql-infer.js') }
102
105
  get txs() { return super.txs = new this.Service('cds.tx') }
103
106
  get ql() { return super.ql = require('./ql/cds-ql') }
104
107
  tx (..._) { return (this.db || this.txs).tx(..._) }
@@ -122,17 +125,20 @@ const cds = module.exports = global.cds = new class cds extends EventEmitter {
122
125
 
123
126
  // Add global convenience shortcuts for cds.ql and cds.parse commands
124
127
  cds.extend (global) .with ( class globals {
125
- get SELECT() { return cds.ql.SELECT }
126
- get INSERT() { return cds.ql.INSERT }
127
- get UPSERT() { return cds.ql.UPSERT }
128
- get UPDATE() { return cds.ql.UPDATE }
129
- get DELETE() { return cds.ql.DELETE }
130
- get CREATE() { return cds.ql.CREATE }
131
- get DROP() { return cds.ql.DROP }
132
- get CDL() { return cds.parse.CDL }
133
- get CQL() { return cds.parse.CQL }
134
- get CXL() { return cds.parse.CXL }
128
+ get SELECT() { return Q('SELECT') }
129
+ get INSERT() { return Q('INSERT') }
130
+ get UPSERT() { return Q('UPSERT') }
131
+ get UPDATE() { return Q('UPDATE') }
132
+ get DELETE() { return Q('DELETE') }
133
+ /** @deprecated */ get CREATE() { return D('CREATE', '{CREATE} = cds.ql', cds.ql.CREATE) }
134
+ /** @deprecated */ get DROP() { return D('DROP', '{DROP} = cds.ql', cds.ql.DROP) }
135
+ /** @deprecated */ get CDL() { return D('CDL', 'cds.parse.cdl', cds.parse.cdl) }
136
+ /** @deprecated */ get CQL() { return D('CQL', 'cds.parse.cql', cds.parse.cql) }
137
+ /** @deprecated */ get CXL() { return D('CXL', 'cds.parse.expr', cds.parse.expr) }
135
138
  } .prototype )
139
+ function Q (p) { return G (p, cds.ql[p]) }
140
+ function D (old,use,fn) { return G (old, cds.utils.deprecated (fn,{kind:'Global constant',old,use})) }
141
+ function G (p,v) { Object.defineProperty (global, p, { value:v, enumerable:1,configurable:1}); return v }
136
142
 
137
143
  // Allow for `import cds from '@sap/cds'` without `esModuleInterop` in tsconfig.json
138
144
  Object.defineProperties (module.exports, { default: {value:cds}, __esModule: {value:true} })
package/lib/ql/CREATE.js CHANGED
@@ -1,10 +1,12 @@
1
- module.exports = class Query extends require('./Query') {
1
+ const Query = require('./cds.ql-Query')
2
+ class CREATE extends Query {
2
3
 
3
- get kind() { return 'CREATE' }
4
- static _api() {
5
- return Object.assign((..._) => (new this).entity(..._), {
6
- entity: (..._) => (new this).entity(..._),
7
- })
4
+ /** @type import('./cqn').CREATE['CREATE'] */
5
+ CREATE = {}
6
+
7
+ static call = (..._) => (new this).entity(..._)
8
+ static API = { class:this,
9
+ entity: (..._) => (new this).entity(..._)
8
10
  }
9
11
 
10
12
  entity (e, elements) {
@@ -23,3 +25,6 @@ module.exports = class Query extends require('./Query') {
23
25
 
24
26
  get _target_ref(){ return this.CREATE.entity }
25
27
  }
28
+
29
+ /** @type CREATE.API & (...entries:[]) => CREATE */
30
+ module.exports = CREATE.init()
package/lib/ql/DELETE.js CHANGED
@@ -1,17 +1,17 @@
1
1
  const Whereable = require('./Whereable')
2
+ class DELETE extends Whereable {
2
3
 
3
- module.exports = class Query extends Whereable {
4
+ /** @type import('./cqn').DELETE['DELETE'] */
5
+ DELETE = {}
4
6
 
5
- get kind() { return 'DELETE' }
6
- static _api() {
7
- return Object.assign ((..._) => (new this).from(..._), {
8
- from: (..._) => (new this).from(..._),
9
- })
7
+ static call = (..._) => (new this).from(..._)
8
+ static API = { class:this,
9
+ from: (..._) => (new this).from(..._)
10
10
  }
11
11
 
12
- from(entity, key) {
13
- this.DELETE.from = this._target4 (...arguments) // supporting tts
14
- if (key !== undefined) this.byKey(key)
12
+ from (entity, ...etc) {
13
+ this.DELETE.from = this._target4 (entity, ...etc) // supporting tts
14
+ if (!entity.raw && etc.length) this.byKey(etc[0])
15
15
  return this
16
16
  }
17
17
 
@@ -21,3 +21,6 @@ module.exports = class Query extends Whereable {
21
21
 
22
22
  get _target_ref(){ return this.DELETE.from }
23
23
  }
24
+
25
+ /** @type DELETE.API & (...entries:[]) => DELETE */
26
+ module.exports = DELETE.init()
package/lib/ql/DROP.js CHANGED
@@ -1,12 +1,16 @@
1
- module.exports = class Query extends require('./Query') {
2
- get kind() { return 'DROP' }
3
- static _api() {
4
- return Object.assign ((e) => (new this).entity(e), {
5
- entity: (e) => (new this).entity(e),
6
- table: (e) => (new this).table(e),
7
- view: (e) => (new this).view(e),
8
- })
1
+ const Query = require('./cds.ql-Query')
2
+ class DROP extends Query {
3
+
4
+ /** @type import('./cqn').DROP['DROP'] */
5
+ DROP = {}
6
+
7
+ static call = (..._) => (new this).entity(..._)
8
+ static API = { class:this,
9
+ entity: (..._) => (new this).entity(..._),
10
+ table: (..._) => (new this).table(..._),
11
+ view: (..._) => (new this).view(..._),
9
12
  }
13
+
10
14
  entity(e) {
11
15
  this.DROP.entity = this._target4 (e)
12
16
  return this
@@ -24,3 +28,6 @@ module.exports = class Query extends require('./Query') {
24
28
 
25
29
  get _target_ref(){ return this.DROP.entity }
26
30
  }
31
+
32
+ /** @type DROP.API & (...entries:[]) => DROP */
33
+ module.exports = DROP.init()
package/lib/ql/INSERT.js CHANGED
@@ -1,14 +1,16 @@
1
- module.exports = class Query extends require('./Query') {
1
+ const Query = require('./cds.ql-Query')
2
+ class INSERT extends Query {
2
3
 
3
- get kind() { return 'INSERT' }
4
- static _api() {
5
- return Object.assign ((..._) => (new this).entries(..._), {
6
- into: (..._) => (new this).into(..._),
7
- })
4
+ /** @type import('./cqn').INSERT['INSERT'] */
5
+ INSERT = {}
6
+
7
+ static call = (..._) => (new this).entries(..._)
8
+ static API = { class:this,
9
+ into: (..._) => (new this).into(..._)
8
10
  }
9
11
 
10
12
  into (entity, ...data) {
11
- this._.into = this._target4 (...arguments) // supporting tts
13
+ this._.into = this._target4 (entity, ...data) // supporting tts
12
14
  if (data.length) this.entries(...data)
13
15
  return this
14
16
  }
@@ -44,18 +46,21 @@ module.exports = class Query extends require('./Query') {
44
46
  return this
45
47
  }
46
48
 
47
- /** @deprecated */ as (query) {
48
- INSERT_as_SELECT ??= require('../utils').deprecated(()=>{},{old:'INSERT.as(SELECT)', use:'INSERT.entries(SELECT)'})
49
- INSERT_as_SELECT()
50
- return this.from(query)
51
- }
49
+ /** @deprecated */ as(q) { return this.from(q) }
52
50
 
53
51
  valueOf() {
54
52
  return super.valueOf('INSERT INTO')
55
53
  }
56
54
 
57
- get _target_ref(){ return this._.into }
55
+ get _target_ref(){ return ( this.INSERT || this.UPSERT ).into }
58
56
  }
59
57
 
60
58
  const is_array = Array.isArray
61
- let INSERT_as_SELECT
59
+
60
+ INSERT.prototype.as = require('../utils').deprecated (INSERT.prototype.as, {
61
+ old:'INSERT.as(SELECT)',
62
+ use:'INSERT.entries(SELECT)'
63
+ })
64
+
65
+ /** @type INSERT.API & (...entries:[]) => INSERT */
66
+ module.exports = INSERT.init()