-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
306 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
const cds = require('@sap/cds/lib') | ||
|
||
const OP = {} | ||
|
||
module.exports = function (q) { | ||
const kind = q.kind || Object.keys(q)[0] | ||
const ret = OP[kind].call(this, q) | ||
return ret | ||
} | ||
|
||
OP.INSERT = function (q, path = [], targets = {}) { | ||
const name = n => n.replace(/\./g, '_') | ||
|
||
const kind = q.kind || Object.keys(q)[0] | ||
const INSERT = q[kind] || q.INSERT || q.UPSERT | ||
const { target } = q | ||
// Only INSERT.entries get deep logic | ||
// if (INSERT.rows) return '' | ||
const { compositions } = target | ||
|
||
let into = INSERT.into | ||
if (typeof into === 'string') into = { ref: [into] } | ||
|
||
if (path.find(c => c.name === q.target.name)) return '' | ||
const isRoot = path.length === 0 | ||
path.push(q.target) | ||
targets[q.target.name] = targets[q.target.name] || { count: 0 } | ||
targets[q.target.name].count += 1 | ||
|
||
const label = `l${path.length}` | ||
const extract = this.cqn2sql(q) | ||
Check warning on line 31 in hana/lib/deep2flat.js GitHub Actions / Node.js 18
|
||
.extract | ||
.replace('SRC.JSON', ':input') | ||
.trim() | ||
let sql = '' | ||
/* | ||
let sql = !isRoot | ||
? '' | ||
: ` | ||
DO (IN input NCLOB => ?) | ||
BEGIN | ||
DECLARE v_${label}_index INT = 0; | ||
DECLARE v_${label}_last_index INT = -1; | ||
v_${name(q.target.name)} = ${extract}; | ||
`*/ | ||
|
||
const needDeep = {} | ||
for (const c in compositions) { | ||
const t = compositions[c].target | ||
if (targets[t] === undefined) { | ||
needDeep[t] = true | ||
targets[t] = { count: 0 } | ||
} | ||
} | ||
|
||
// Compute all compositions | ||
for (const c in compositions) { | ||
const element = compositions[c] | ||
const target = cds.model.definitions[element.target] // REVISIT: element._target is the actual reference | ||
|
||
const ins = cds.ql.INSERT([]).into({ ref: [...into.ref, c] }) | ||
const next = needDeep[target.name] ? OP.INSERT.call(this, ins, path, targets).replace(/\n/g, '\n ') : '' | ||
Check warning on line 63 in hana/lib/deep2flat.js GitHub Actions / Node.js 18
|
||
/* TODO: for UPDATE / UPSERT | ||
const del = cds.ql.DELETE.from({ | ||
ref: [...into.ref, { | ||
id: c, | ||
where: ['not', { list: ObjectKeys(target.keys).map(k => ({ ref: [k] })) }, 'in', { list: [] }] | ||
}] | ||
}) | ||
*/ | ||
const cqn2sql = this.cqn2sql(ins) | ||
let extract = cqn2sql.extract.trim() | ||
targets[target.name].extract = extract | ||
targets[target.name].columns = cqn2sql.columns | ||
|
||
const parentMapping = [] | ||
for (const foreignKey of element._foreignKeys) { | ||
const cname = foreignKey.childElement.name | ||
const pname = foreignKey.parentElement.name | ||
const org = new RegExp(`,${cname} ([^ ]*) PATH '\\$\\.${cname}'`).exec(extract) | ||
extract = extract.replace(org[0], '') // TODO: properly quote column name | ||
parentMapping.push(`${cname} ${org[1]} PATH '$.${pname}'`) | ||
} | ||
|
||
sql = `${sql} | ||
WHILE record_count(:v_${name(target.name)}) > 0 DO | ||
INSERT INTO ${name(target.name)} (${cqn2sql.columns}) SELECT ${cqn2sql.columns} FROM :v_${name(target.name)}; | ||
v_${name(target.name)} = | ||
WITH SRC AS (SELECT _JSON_ as JSON FROM :v_${name(q.target.name)}) | ||
${extract.replace(`'$' COLUMNS(`, `'$$' COLUMNS(${parentMapping}, ${c} NVARCHAR(2147483647) FORMAT JSON PATH '$$.${c}', NESTED PATH '$$.${c}[*]' COLUMNS(`).replace(') ERROR ON ERROR)', ')) ERROR ON ERROR)')} | ||
WHERE LENGTH(${c}) > 2; | ||
END WHILE; | ||
` | ||
} | ||
|
||
// Remove current target from path | ||
path.pop() | ||
|
||
if (isRoot) { | ||
const tableValues = Object.keys(targets) | ||
.map(t => `v_${name(t)} = ${targets[t].extract.replace('SRC.JSON', q.target.name === t ? ':input' : "'[]'")};`) | ||
const finalInserts = [] || Object.keys(targets) | ||
.map(t => `INSERT INTO ${name(t)} (${targets[t].columns}) SELECT ${targets[t].columns} FROM :v_${name(t)};`) | ||
|
||
sql = `DO (IN input NCLOB => ?) | ||
BEGIN | ||
DECLARE v_changes INT = 0; | ||
DECLARE v_${label}_index INT = 0; | ||
DECLARE v_${label}_last_index INT = -1; | ||
${tableValues.join('\n')} | ||
SELECT COUNT(*) INTO v_changes FROM :v_${name(q.target.name)}; | ||
${sql} | ||
--SELECT * FROM :v_${name(q.target.name)}; | ||
${finalInserts.join('\n')} | ||
SELECT v_changes as "changes" FROM DUMMY; | ||
END;` | ||
} else { | ||
sql = `${sql}` | ||
} | ||
|
||
return sql | ||
} | ||
|
||
OP.UPDATE = (/*{ UPDATE, target, elements }*/) => { | ||
return [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
DO (IN input NCLOB => ?) | ||
BEGIN | ||
DECLARE v_changes INT = 0; | ||
DECLARE v_l1_index INT = 0; | ||
DECLARE v_l1_last_index INT = -1; | ||
|
||
-- Parse the incoming root data | ||
v_sap_capire_bookshop_Genres = SELECT name AS name,descr AS descr,ID AS ID,parent_ID AS parent_ID,_JSON_ AS _JSON_ FROM JSON_TABLE(:input, '$' COLUMNS(name NVARCHAR(1020) PATH '$.name',descr NVARCHAR(4000) PATH '$.descr',ID INT PATH '$.ID',parent_ID INT PATH '$.parent_ID',_JSON_ NVARCHAR(2147483647) FORMAT JSON PATH '$') ERROR ON ERROR); | ||
|
||
-- Take root level update count to return "changes" result | ||
v_changes = record_count(:v_sap_capire_bookshop_Genres); | ||
|
||
-- This is bookshop.Genres and the composition is recursive so it need to keep going until no new genres are left | ||
WHILE record_count(:v_sap_capire_bookshop_Genres) > 0 DO | ||
-- Insert the current contents of "v_sap_capire_bookshop_Genres" as it will be overwritten in this loop | ||
INSERT INTO sap_capire_bookshop_Genres (name,descr,ID,parent_ID) SELECT name,descr,ID,parent_ID FROM :v_sap_capire_bookshop_Genres; | ||
-- Select all the children with their parent ID propogated (mostly the same as the root data JSON_TABLE, but with parent_ID prefixed) | ||
v_sap_capire_bookshop_Genres = | ||
WITH SRC AS (SELECT _JSON_ FROM :v_sap_capire_bookshop_Genres) | ||
SELECT name AS name,descr AS descr,ID AS ID,parent_ID as parent_ID,_JSON_ AS _JSON_ FROM JSON_TABLE(SRC._JSON_, '$' COLUMNS(parent_ID INT PATH '$.ID', children NVARCHAR(2147483647) FORMAT JSON PATH '$.children', NESTED PATH '$.children[*]' COLUMNS(name NVARCHAR(1020) PATH '$.name',descr NVARCHAR(4000) PATH '$.descr',ID INT PATH '$.ID',_JSON_ NVARCHAR(2147483647) FORMAT JSON PATH '$')) ERROR ON ERROR) | ||
WHERE LENGTH(children) > 2; -- Prevent parents to show up that have no children as "JSON_TABLE" does (SELECT * FROM PARENT LEFT JOIN PARENT.CHILDREN) So the parent also shows up when it does not have children | ||
END WHILE; | ||
|
||
-- Removed texts as it is not being used currently | ||
|
||
-- Debugging output queries to see intermediate results: | ||
-- SELECT * FROM :v_sap_capire_bookshop_Genres; | ||
-- INSERT INTO sap_capire_bookshop_Genres (name,descr,ID,parent_ID) SELECT name,descr,ID,parent_ID FROM :v_sap_capire_bookshop_Genres; | ||
-- INSERT INTO sap_capire_bookshop_Genres_texts (locale,name,descr,ID) SELECT locale,name,descr,ID FROM :v_sap_capire_bookshop_Genres_texts; | ||
-- SELECT * FROM sap_capire_bookshop_Genres; | ||
|
||
SELECT v_changes as "changes" FROM DUMMY; | ||
END; |
Oops, something went wrong.