@cap-js/db-service
Advanced tools
Comparing version 1.5.0 to 1.5.1
@@ -7,2 +7,15 @@ # Changelog | ||
## [1.5.1](https://github.com/cap-js/cds-dbs/compare/db-service-v1.5.0...db-service-v1.5.1) (2023-12-20) | ||
### Fixed | ||
* **cqn2sql:** supporting calculated elements ([#387](https://github.com/cap-js/cds-dbs/issues/387)) ([2153fb9](https://github.com/cap-js/cds-dbs/commit/2153fb9a3910cd4afa3a91918e6cf682646492b7)) | ||
* do not rely on db constraints for deep delete ([#390](https://github.com/cap-js/cds-dbs/issues/390)) ([9623af6](https://github.com/cap-js/cds-dbs/commit/9623af64db97cfe15ef07b659635850fc908f77c)) | ||
### Performance Improvements | ||
* HANA list placeholder ([#380](https://github.com/cap-js/cds-dbs/issues/380)) ([3eadfea](https://github.com/cap-js/cds-dbs/commit/3eadfea7b94f485030cc8bd0bd298ce088586422)) | ||
## [1.5.0](https://github.com/cap-js/cds-dbs/compare/db-service-v1.4.0...db-service-v1.5.0) (2023-12-06) | ||
@@ -9,0 +22,0 @@ |
@@ -30,3 +30,3 @@ const cds = require('@sap/cds/lib') | ||
static _add_mixins (aspect, mixins) { | ||
static _add_mixins(aspect, mixins) { | ||
const fqn = this.name + aspect | ||
@@ -56,3 +56,3 @@ const types = cds.builtin.types | ||
} | ||
this._init = () => {} // makes this a noop for subsequent calls | ||
this._init = () => { } // makes this a noop for subsequent calls | ||
} | ||
@@ -213,3 +213,3 @@ | ||
if (expand) { | ||
if ('elements' in q) sql = this.SELECT_expand (q,sql) | ||
if ('elements' in q) sql = this.SELECT_expand(q, sql) | ||
else cds.error`Query was not inferred and includes expand. For which the metadata is missing.` | ||
@@ -255,3 +255,3 @@ } | ||
if(cols.length < 50) obj = `json_object(${cols.slice(0, 50)})` | ||
if (cols.length < 50) obj = `json_object(${cols.slice(0, 50)})` | ||
else { | ||
@@ -349,5 +349,5 @@ const chunks = [] | ||
? c => | ||
this.expr(c) + | ||
(c.element?.[this.class._localized] ? ' COLLATE NOCASE' : '') + | ||
(c.sort === 'desc' || c.sort === -1 ? ' DESC' : ' ASC') | ||
this.expr(c) + | ||
(c.element?.[this.class._localized] ? ' COLLATE NOCASE' : '') + | ||
(c.sort === 'desc' || c.sort === -1 ? ' DESC' : ' ASC') | ||
: c => this.expr(c) + (c.sort === 'desc' || c.sort === -1 ? ' DESC' : ' ASC'), | ||
@@ -380,8 +380,8 @@ ) | ||
: INSERT.rows | ||
? this.INSERT_rows(q) | ||
: INSERT.values | ||
? this.INSERT_values(q) | ||
: INSERT.as | ||
? this.INSERT_select(q) | ||
: cds.error`Missing .entries, .rows, or .values in ${q}` | ||
? this.INSERT_rows(q) | ||
: INSERT.values | ||
? this.INSERT_values(q) | ||
: INSERT.as | ||
? this.INSERT_select(q) | ||
: cds.error`Missing .entries, .rows, or .values in ${q}` | ||
} | ||
@@ -403,3 +403,3 @@ | ||
const columns = elements | ||
? ObjectKeys(elements).filter(c => c in elements && !elements[c].virtual && !elements[c].isAssociation) | ||
? ObjectKeys(elements).filter(c => c in elements && !elements[c].virtual && !elements[c].value && !elements[c].isAssociation) | ||
: ObjectKeys(INSERT.entries[0]) | ||
@@ -437,5 +437,4 @@ | ||
this.entries = [[...this.values, JSON.stringify(INSERT.entries)]] | ||
return (this.sql = `INSERT INTO ${this.quote(entity)}${alias ? ' as ' + this.quote(alias) : ''} (${ | ||
this.columns | ||
}) SELECT ${extraction} FROM json_each(?)`) | ||
return (this.sql = `INSERT INTO ${this.quote(entity)}${alias ? ' as ' + this.quote(alias) : ''} (${this.columns | ||
}) SELECT ${extraction} FROM json_each(?)`) | ||
} | ||
@@ -454,10 +453,10 @@ | ||
const columns = INSERT.columns | ||
|| cds.error`Cannot insert rows without columns or elements` | ||
|| cds.error`Cannot insert rows without columns or elements` | ||
const inputConverter = this.class._convertInput | ||
const extraction = columns.map((c,i) => { | ||
const extraction = columns.map((c, i) => { | ||
const extract = `value->>'$[${i}]'` | ||
const element = elements?.[c] | ||
const converter = element?.[inputConverter] | ||
return converter?.(extract,element) || extract | ||
return converter?.(extract, element) || extract | ||
}) | ||
@@ -467,5 +466,4 @@ | ||
this.entries = [[JSON.stringify(INSERT.rows)]] | ||
return (this.sql = `INSERT INTO ${this.quote(entity)}${alias ? ' as ' + this.quote(alias) : ''} (${ | ||
this.columns | ||
}) SELECT ${extraction} FROM json_each(?)`) | ||
return (this.sql = `INSERT INTO ${this.quote(entity)}${alias ? ' as ' + this.quote(alias) : ''} (${this.columns | ||
}) SELECT ${extraction} FROM json_each(?)`) | ||
} | ||
@@ -565,5 +563,5 @@ | ||
let columns = [] | ||
if (data) _add (data, val => this.val({val})) | ||
if (_with) _add (_with, x => this.expr(x)) | ||
function _add (data, sql4) { | ||
if (data) _add(data, val => this.val({ val })) | ||
if (_with) _add(_with, x => this.expr(x)) | ||
function _add(data, sql4) { | ||
for (let c in data) { | ||
@@ -616,4 +614,4 @@ if (!elements || (c in elements && !elements[c].virtual)) { | ||
: STREAM.into | ||
? this.STREAM_into(q) | ||
: cds.error`Missing .form or .into in ${q}` | ||
? this.STREAM_into(q) | ||
: cds.error`Missing .form or .into in ${q}` | ||
} | ||
@@ -683,3 +681,3 @@ | ||
if (typeof x === 'string') throw cds.error`Unsupported expr: ${x}` | ||
if ('param' in x) return wrap(this.param(x)) | ||
if (x.param) return wrap(this.param(x)) | ||
if ('ref' in x) return wrap(this.ref(x)) | ||
@@ -720,11 +718,11 @@ if ('val' in x) return wrap(this.val(x)) | ||
// Translate = to IS NULL for rhs operand being NULL literal | ||
if (x === '=') return xpr[i+1]?.val === null ? 'is' : '=' | ||
if (x === '=') return xpr[i + 1]?.val === null ? 'is' : '=' | ||
// Translate == to IS NOT NULL for rhs operand being NULL literal, otherwise ... | ||
// Translate == to IS NOT DISTINCT FROM, unless both operands cannot be NULL | ||
if (x === '==') return xpr[i+1]?.val === null ? 'is' : _not_null(i-1) && _not_null(i+1) ? '=' : this.is_not_distinct_from_ | ||
if (x === '==') return xpr[i + 1]?.val === null ? 'is' : _not_null(i - 1) && _not_null(i + 1) ? '=' : this.is_not_distinct_from_ | ||
// Translate != to IS NULL for rhs operand being NULL literal, otherwise... | ||
// Translate != to IS DISTINCT FROM, unless both operands cannot be NULL | ||
if (x === '!=') return xpr[i+1]?.val === null ? 'is not' : _not_null(i-1) && _not_null(i+1) ? '<>' : this.is_distinct_from_ | ||
if (x === '!=') return xpr[i + 1]?.val === null ? 'is not' : _not_null(i - 1) && _not_null(i + 1) ? '<>' : this.is_distinct_from_ | ||
@@ -766,5 +764,5 @@ else return x | ||
switch (ref[0]) { | ||
case '$now': return this.func({ func: 'session_context', args: [{ val: '$now' }]}) | ||
case '$now': return this.func({ func: 'session_context', args: [{ val: '$now', param: false }] }) | ||
case '$user': | ||
case '$user.id': return this.func({ func: 'session_context', args: [{ val: '$user.id' }]}) | ||
case '$user.id': return this.func({ func: 'session_context', args: [{ val: '$user.id', param: false }] }) | ||
default: return ref.map(r => this.quote(r)).join('.') | ||
@@ -779,3 +777,3 @@ } | ||
*/ | ||
val({ val }) { | ||
val({ val, param }) { | ||
switch (typeof val) { | ||
@@ -789,3 +787,3 @@ case 'function': throw new Error('Function values not supported.') | ||
if (val instanceof Date) return `'${val.toISOString()}'` | ||
if (val instanceof Readable) ; // go on with default below | ||
if (val instanceof Readable); // go on with default below | ||
else if (Buffer.isBuffer(val)) val = val.toString('base64') | ||
@@ -796,3 +794,3 @@ else if (is_regexp(val)) val = val.source | ||
} | ||
if (!this.values) return this.string(val) | ||
if (!this.values || param === false) return this.string(val) | ||
else this.values.push(val) | ||
@@ -881,8 +879,8 @@ return '?' | ||
: Object.keys(elements) | ||
.filter( | ||
e => | ||
(elements[e]?.[annotation] || (!isUpdate && elements[e]?.default && !elements[e].virtual && !elements[e].isAssociation)) && | ||
!columns.find(c => c.name === e), | ||
) | ||
.map(name => ({ name, sql: 'NULL' })) | ||
.filter( | ||
e => | ||
(elements[e]?.[annotation] || (!isUpdate && elements[e]?.default && !elements[e].virtual && !elements[e].isAssociation)) && | ||
!columns.find(c => c.name === e), | ||
) | ||
.map(name => ({ name, sql: 'NULL' })) | ||
@@ -897,3 +895,3 @@ return [...columns, ...requiredColumns].map(({ name, sql }) => { | ||
let val = _managed[element[annotation]?.['=']] | ||
if (val) sql = `coalesce(${sql}, ${this.func({ func: 'session_context', args: [{ val }] })})` | ||
if (val) sql = `coalesce(${sql}, ${this.func({ func: 'session_context', args: [{ val, param: false }] })})` | ||
else if (!isUpdate && element.default) { | ||
@@ -903,5 +901,4 @@ const d = element.default | ||
// REVISIT: d.ref is not used afterwards | ||
sql = `(CASE WHEN json_type(value,'$."${name}"') IS NULL THEN ${ | ||
this.defaultValue(d.val) // REVISIT: this.defaultValue is a strange function | ||
} ELSE ${sql} END)` | ||
sql = `(CASE WHEN json_type(value,'$."${name}"') IS NULL THEN ${this.defaultValue(d.val) // REVISIT: this.defaultValue is a strange function | ||
} ELSE ${sql} END)` | ||
} | ||
@@ -908,0 +905,0 @@ } |
@@ -156,3 +156,4 @@ const cds = require('@sap/cds/lib'), | ||
get onDELETE() { | ||
return super.onDELETE = cds.env.features.assert_integrity === 'db' ? this.onSIMPLE : deep_delete | ||
// REVISIT: It's not yet 100 % clear under which circumstances we can rely on db constraints | ||
return super.onDELETE = /* cds.env.features.assert_integrity === 'db' ? this.onSIMPLE : */ deep_delete | ||
async function deep_delete(/** @type {Request} */ req) { | ||
@@ -159,0 +160,0 @@ let { compositions } = req.target |
{ | ||
"name": "@cap-js/db-service", | ||
"version": "1.5.0", | ||
"version": "1.5.1", | ||
"description": "CDS base database service", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/cap-js/cds-dbs/tree/main/db-service#cds-base-database-service", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
259449
5678