Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: unify physical elements check #408

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions db-service/lib/cqn2sql.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ class CQN2SQLRenderer {
return // REVISIT: mtx sends an insert statement without entries and no reference entity
}
const columns = elements
? ObjectKeys(elements).filter(c => c in elements && !elements[c].virtual && !elements[c].value && !elements[c].isAssociation)
? ObjectKeys(elements).filter(c => this.exists(elements[c]))
: ObjectKeys(INSERT.entries[0])

/** @type {string[]} */
Expand Down Expand Up @@ -583,9 +583,8 @@ class CQN2SQLRenderer {
const entity = this.name(q.target.name)
const alias = INSERT.into.as
const elements = q.elements || q.target?.elements || {}
const columns = (this.columns = (INSERT.columns || ObjectKeys(elements)).filter(
c => c in elements && !elements[c].virtual && !elements[c].isAssociation,
))
const columns = this.columns = (INSERT.columns || ObjectKeys(elements))
.filter(c => this.exists(elements[c]))
this.sql = `INSERT INTO ${entity}${alias ? ' as ' + this.quote(alias) : ''} (${columns}) ${this.SELECT(
cqn4sql(INSERT.as),
)}`
Expand Down Expand Up @@ -630,12 +629,7 @@ class CQN2SQLRenderer {
let updateColumns = q.UPSERT.entries ? Object.keys(q.UPSERT.entries[0]) : this.columns
updateColumns = updateColumns.filter(c => {
if (keys.includes(c)) return false //> keys go into ON CONFLICT clause
let e = elements[c]
if (!e) return true //> pass through to native SQL columns not in CDS model
if (e.virtual) return true //> skip virtual elements
if (e.value) return true //> skip calculated elements
// if (e.isAssociation) return true //> this breaks a a test in @sap/cds -> need to follow up how to correctly handle deep upserts
else return true
return this.exists(elements[c]) //> only update columns that exist in the database
}).map(c => `${this.quote(c)} = excluded.${this.quote(c)}`)

// temporal data
Expand All @@ -662,15 +656,15 @@ class CQN2SQLRenderer {
if (entity.as) sql += ` AS ${entity.as}`

let columns = []
if (data) _add(data, val => this.val({ val }))
if (_with) _add(_with, x => this.expr(x))
function _add(data, sql4) {
const _add = (data, sql4) => {
for (let c in data) {
if (!elements || (c in elements && !elements[c].virtual)) {
if (!elements || (this.exists(elements[c]))) {
columns.push({ name: c, sql: sql4(data[c]) })
}
}
}
if (data) _add(data, val => this.val({ val }))
if (_with) _add(_with, x => this.expr(x))

columns = columns.map(c => {
if (q.elements?.[c.name]?.['@cds.extension']) return {
Expand Down Expand Up @@ -956,6 +950,15 @@ class CQN2SQLRenderer {
return s
}

/**
* Check if element exists on the database
* @param {import('./infer/cqn').element} e
* @returns {Boolean}
*/
exists(e) {
return e && !e.virtual && !e.value && !e.isAssociation
}

/**
* Convers the columns array into an array of SQL expressions that extract the correct value from inserted JSON data
* @param {object[]} columns
Expand All @@ -972,7 +975,7 @@ class CQN2SQLRenderer {
: Object.keys(elements)
.filter(
e =>
(elements[e]?.[annotation] || (!isUpdate && elements[e]?.default && !elements[e].virtual && !elements[e].isAssociation)) &&
(elements[e]?.[annotation] || (!isUpdate && elements[e]?.default && this.exists(elements[e]))) &&
!columns.find(c => c.name === e),
)
.map(name => ({ name, sql: 'NULL' }))
Expand Down
8 changes: 4 additions & 4 deletions hana/lib/HANAService.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@
this.temporary = this.temporary || []
this.temporaryValues = this.temporaryValues || []

const { limit, one, orderBy, expand, columns, localized, count, from, parent } = q.SELECT

Check warning on line 268 in hana/lib/HANAService.js

View workflow job for this annotation

GitHub Actions / Node.js 18

'from' is assigned a value but never used

Check warning on line 268 in hana/lib/HANAService.js

View workflow job for this annotation

GitHub Actions / HANA Node.js 18

'from' is assigned a value but never used

const walkAlias = q => {
if (q.args) return q.as || walkAlias(q.args[0])
Expand Down Expand Up @@ -528,7 +528,7 @@
return // REVISIT: mtx sends an insert statement without entries and no reference entity
}
const columns = elements
? ObjectKeys(elements).filter(c => c in elements && !elements[c].virtual && !elements[c].value && !elements[c].isAssociation)
? ObjectKeys(elements).filter(c => this.exists(elements[c]))
: ObjectKeys(INSERT.entries[0])
this.columns = columns.filter(elements ? c => !elements[c]?.['@cds.extension'] : () => true)

Expand Down Expand Up @@ -618,8 +618,8 @@
let keys = q.target?.keys
const keyCompare =
keys &&
Object.keys(keys)
.filter(k => !keys[k].isAssociation)
ObjectKeys(keys)
.filter(k => this.exists(keys[k]))
.map(k => `NEW.${this.quote(k)}=OLD.${this.quote(k)}`)
.join('AND')

Expand Down Expand Up @@ -798,7 +798,7 @@
const keyZero = this.quote(
ObjectKeys(elements).find(e => {
const el = elements[e]
return el.key && !el.isAssociation
return el.key && this.exists(el)
}) || '',
)

Expand Down
Loading