@sap/cds-sql
Advanced tools
Comparing version 1.11.1 to 1.13.0
@@ -9,14 +9,24 @@ # Changelog | ||
## Version 1.12.0 - tbd | ||
## Version 1.13.0 - 2019-06-24 | ||
### Added | ||
- Struct Mapper checks subselect for matching columns | ||
## Version 1.12.0 - 2019-05-24 | ||
### Changed | ||
- Deep insert/update for to-many associations is not allowed | ||
### Fixed | ||
- Property mapper now works for fully-specified columns in SELECT statements | ||
## Version 1.11.1 - 2019-05-16 | ||
### Fixed | ||
- Cases with multiple brackets during `onCond` generation | ||
### Removed | ||
## Version 1.11.0 - 2019-05-15 | ||
@@ -305,2 +315,2 @@ | ||
- ambiguous column name when having multiple expands on same entity | ||
- ambiguous column name when having multiple expands on same entity |
@@ -180,3 +180,3 @@ const cds = require('../cds') | ||
const then = (resolve, reject) => { | ||
return promise.then(resolve).catch(reject) | ||
return promise.then(resolve, reject).catch(reject) | ||
} | ||
@@ -183,0 +183,0 @@ |
@@ -23,5 +23,3 @@ const _backLinkCustom = (name, target, element, entityKeys) => { | ||
const _backlinkForCustomOn = (element, entityKeys) => { | ||
const name = element.on[2].ref.join('.') | ||
const target = element.on[0].ref.join('.') | ||
const { name, target } = _onElements(element) | ||
return _backLinkCustom(name, target, element, entityKeys) | ||
@@ -31,5 +29,3 @@ } | ||
const _backlinkForCustomOnCond = (element, entityKeys) => { | ||
const name = element.onCond.args[1]['='] | ||
const target = element.onCond.args[0]['='] | ||
const { name, target } = _onCondElements(element) | ||
return _backLinkCustom(name, target, element, entityKeys) | ||
@@ -53,2 +49,24 @@ } | ||
const _onElements = element => { | ||
const name = element.on[2].ref.join('.') | ||
const target = element.on[0].ref.join('.') | ||
return { name, target } | ||
} | ||
const _onCondElements = element => { | ||
const name = element.onCond.args[1]['='] | ||
const target = element.onCond.args[0]['='] | ||
return { name, target } | ||
} | ||
const getOnCondElements = element => { | ||
if (element.on) { | ||
return _onElements(element) | ||
} else if (element.onCond && element.onCond.op === '=') { | ||
return _onCondElements(element) | ||
} | ||
} | ||
const _backLinkNameFromOnCond = element => { | ||
@@ -117,3 +135,4 @@ const onCondElement1 = _cleanupOnCondElement(element, element.onCond.args[0]['=']) | ||
getBackLinks, | ||
isSelfManaged | ||
isSelfManaged, | ||
getOnCondElements | ||
} |
@@ -1,2 +0,2 @@ | ||
const { getBackLinks, isSelfManaged } = require('./backlinks') | ||
const { getBackLinks, isSelfManaged, getOnCondElements } = require('./backlinks') | ||
const { ensureNoDraftsSuffix, ensureDraftsSuffix } = require('../utils/draftUtils') | ||
@@ -88,5 +88,24 @@ | ||
const _checkIfBackLink = (element, definitions) => { | ||
const target = definitions[element.target] | ||
const parent = element.parent | ||
for (const elementName in target.elements) { | ||
const targetElement = target.elements[elementName] | ||
if ( | ||
targetElement.target === parent.name && | ||
(targetElement.type === 'cds.Composition' || targetElement.type === 'cds.Association') | ||
) { | ||
const { name, target } = getOnCondElements(targetElement) | ||
if (name === `${elementName}.${element.name}` || target === `${elementName}.${element.name}`) { | ||
return true | ||
} | ||
} | ||
} | ||
} | ||
const _addBackLinksToCompositionTree = (element, definitions, compositionTree) => { | ||
if (_isUnManaged(element)) { | ||
compositionTree.customBackLinks.push(...getBackLinks(element, Object.keys(definitions[element.target].keys))) | ||
if (_checkIfBackLink(element, definitions)) { | ||
compositionTree.customBackLinks.push(...getBackLinks(element, Object.keys(definitions[element.target].keys))) | ||
} | ||
} else { | ||
@@ -543,2 +562,12 @@ compositionTree.backLinks.push(...getBackLinks(element, Object.keys(definitions[element.target].keys))) | ||
const _checkForToManyAssociation = (toManyElements, dataEntry, event) => { | ||
for (const toManyElement of toManyElements) { | ||
if (toManyElement.type === 'cds.Association' && dataEntry[toManyElement.name] !== undefined) { | ||
const error = new Error(`Deep ${event} with to-many Associations is not allowed`) | ||
error.statusCode = 400 | ||
throw error | ||
} | ||
} | ||
} | ||
const createDeepInsertCQNs = (definitions, cqn) => { | ||
@@ -556,3 +585,6 @@ const into = cqn.INSERT.into.name || cqn.INSERT.into | ||
const toOneElements = _toOneElements(entity) | ||
const toManyElements = _toManyElements(entity) | ||
for (const dataEntry of dataEntries) { | ||
_checkForToManyAssociation(toManyElements, dataEntry, 'insert') | ||
const toOneKeys = _toOneKeys(dataEntry, dataEntries, toOneElements, compositionTree) | ||
@@ -965,2 +997,6 @@ flattenedCqn.INSERT.entries.push(_cleanDeepData(entity, Object.assign({}, dataEntry, toOneKeys))) | ||
const compositionTree = getCompositionTree(definitions, entityName, false, !draft) | ||
const toManyElements = _toManyElements(entity) | ||
_checkForToManyAssociation(toManyElements, entry, 'update') | ||
const subCQNs = _addSubDeepUpdateCQN({ definitions, compositionTree, data: [entry], selectData, cqns: [], draft }) | ||
@@ -967,0 +1003,0 @@ subCQNs.forEach((subCQNs, index) => { |
@@ -32,3 +32,3 @@ const { isComplex, isAssociation, resolveAssociation } = require('../utils/associations') | ||
let entityName = from.ref[0] | ||
let entityName = from.ref[0].id ? from.ref[0].id : from.ref[0] | ||
@@ -180,9 +180,9 @@ if (csn.definitions && csn.definitions[entityName]) { | ||
if (element.ref) { | ||
const joinedName = element.ref.join('.') | ||
const name = element.as ? element.as : joinedName | ||
const identifier = element.ref[element.ref.length - 1] | ||
const name = element.as ? element.as : identifier | ||
if (element.cast) { | ||
mapper.set(name, _getCastFunction(element.cast)) | ||
} else if (elements.has(joinedName)) { | ||
mapper.set(name, elements.get(joinedName)) | ||
} else if (elements.has(identifier)) { | ||
mapper.set(name, elements.get(identifier)) | ||
} else if (elements.has(name)) { | ||
@@ -392,17 +392,37 @@ mapper.set(name, elements.get(name)) | ||
const _findMatchingSubSelectColumns = (cqn, element) => { | ||
return ( | ||
cqn.SELECT.from.SELECT && | ||
cqn.SELECT.from.SELECT.columns && | ||
cqn.SELECT.from.SELECT.columns.find( | ||
col => col.ref && col.ref[col.ref.length - 1] === element.ref[element.ref.length - 1] | ||
) | ||
) | ||
} | ||
const _isComposedRef = element => element.ref && element.ref.length > 1 | ||
const propertyMapperHasProp = (mapper, prop) => mapper && mapper.has(prop) | ||
const _selectWithSpecificColumns = cqn => | ||
cqn.SELECT && | ||
Array.isArray(cqn.SELECT.columns) && | ||
cqn.SELECT.columns.length !== 0 && | ||
!cqn.SELECT.columns.includes('*') | ||
const getStructMapper = (csn, cqn, propertyMapper) => { | ||
const map = new Map() | ||
if ( | ||
csn && | ||
cqn.SELECT && | ||
Array.isArray(cqn.SELECT.columns) && | ||
cqn.SELECT.columns.length !== 0 && | ||
!cqn.SELECT.columns.includes('*') | ||
) { | ||
for (const element of cqn.SELECT.columns) { | ||
if (element.ref && element.ref.length > 1 && _isAssocOrComp(csn, cqn.SELECT.from, element.ref[0])) { | ||
if (csn && _selectWithSpecificColumns(cqn)) { | ||
for (let element of cqn.SELECT.columns) { | ||
// for apply we need to look if there is a matching column in the subselect | ||
const colOfSubSelect = _findMatchingSubSelectColumns(cqn, element) | ||
if (colOfSubSelect) { | ||
element = colOfSubSelect | ||
} | ||
if (_isComposedRef(element) && _isAssocOrComp(csn, cqn.SELECT.from, element.ref[0])) { | ||
let property = element.ref[element.ref.length - 1] | ||
if (propertyMapper && propertyMapper.has(property)) { | ||
if (propertyMapperHasProp(propertyMapper, property)) { | ||
property = propertyMapper.get(property) | ||
@@ -432,4 +452,8 @@ } | ||
if (from.ref) { | ||
_addToMap(map, `${from.ref.join('.')}.${element}`) | ||
if (from.ref[0] && from.ref[0].id) { | ||
_addToMap(map, `${from.ref[0].id}.${element}`) | ||
} else { | ||
if (from.ref) { | ||
_addToMap(map, `${from.ref.join('.')}.${element}`) | ||
} | ||
} | ||
@@ -436,0 +460,0 @@ |
@@ -99,5 +99,8 @@ const getColumns = require('../utils/columns') | ||
const givenColumns = readToOneCQN.columns | ||
readToOneCQN.columns = [] | ||
this._expandedToFlat({ | ||
entity: entity, | ||
givenColumns: SELECT.columns, | ||
givenColumns: givenColumns, | ||
readToOneCQN: readToOneCQN, | ||
@@ -181,6 +184,6 @@ tableAlias: tableAlias, | ||
_getReadToOneCQN (SELECT, tableAlias) { | ||
const cqn = Object.assign({}, SELECT, { columns: [], from: Object.assign({}, SELECT.from) }) | ||
const cqn = Object.assign({}, SELECT, { from: Object.assign({}, SELECT.from) }) | ||
if (cqn.from.hasOwnProperty('join')) { | ||
this._adaptJoin(tableAlias, cqn.from) | ||
this._adaptJoin(tableAlias, cqn) | ||
} else { | ||
@@ -197,15 +200,18 @@ if (cqn.from.SET) { | ||
_adaptJoin (tableAlias, from) { | ||
from.args = from.args.slice(0) | ||
_adaptTableNameInColumn (column, originalIdentifier, tableAlias) { | ||
return column.ref && column.ref[0] === originalIdentifier | ||
? Object.assign({}, column, { ref: [tableAlias, column.ref[1]] }) | ||
: column | ||
} | ||
const index = from.args[0].ref ? 0 : from.args.length - 1 | ||
const target = Object.assign({}, from.args[index], { as: tableAlias }) | ||
const originalIdentifier = from.args[index].as || from.args[index].ref[0] | ||
_adaptJoin (tableAlias, cqn) { | ||
cqn.from.args = cqn.from.args.slice(0) | ||
from.args[index] = target | ||
from.on = from.on.map(column => { | ||
return column.ref && column.ref[0] === originalIdentifier | ||
? Object.assign({}, column, { ref: [tableAlias, column.ref[1]] }) | ||
: column | ||
}) | ||
const index = cqn.from.args[0].ref ? 0 : cqn.from.args.length - 1 | ||
const target = Object.assign({}, cqn.from.args[index], { as: tableAlias }) | ||
const originalIdentifier = cqn.from.args[index].as || cqn.from.args[index].ref[0] | ||
cqn.from.args[index] = target | ||
cqn.from.on = cqn.from.on.map(column => this._adaptTableNameInColumn(column, originalIdentifier, tableAlias)) | ||
cqn.columns = cqn.columns.map(column => this._adaptTableNameInColumn(column, originalIdentifier, tableAlias)) | ||
} | ||
@@ -212,0 +218,0 @@ |
const BaseBuilder = require('./BaseBuilder') | ||
const { FeatureNotSupportedError } = require('../errors') | ||
@@ -70,2 +71,5 @@ /** | ||
_parseReference (refArray) { | ||
if (refArray[0].id) { | ||
throw new FeatureNotSupportedError() | ||
} | ||
this._outputObj.sql.push(refArray.map(el => this._quoteElement(el)).join('.')) | ||
@@ -72,0 +76,0 @@ } |
{ | ||
"name": "@sap/cds-sql", | ||
"version": "1.11.1", | ||
"version": "1.13.0", | ||
"lockfileVersion": 1 | ||
} |
@@ -1,1 +0,1 @@ | ||
{"bundleDependencies":false,"dependencies":{},"deprecated":false,"description":"This package offers a factory method to build a SQL string from a CQN object and a BaseClient which performs default post processing to be used by the inheriting clients.","engines":{"node":">= 8.9.0"},"husky":{"hooks":{"pre-commit":"lint-staged"}},"lint-staged":{"{lib,test}/**/*.js":["prettier-standard","standard --fix","git add"]},"main":"lib/index.js","name":"@sap/cds-sql","version":"1.11.1","license":"SEE LICENSE IN developer-license-3.1.txt"} | ||
{"bundleDependencies":false,"dependencies":{},"deprecated":false,"description":"This package offers a factory method to build a SQL string from a CQN object and a BaseClient which performs default post processing to be used by the inheriting clients.","engines":{"node":">= 8.9.0"},"husky":{"hooks":{"pre-commit":"lint-staged"}},"lint-staged":{"{lib,test}/**/*.js":["prettier-standard","standard --fix","git add"]},"main":"lib/index.js","name":"@sap/cds-sql","scripts":{"format":"prettier-standard 'lib/**/*.js' 'test/**/*.js' && standard --fix"},"version":"1.13.0","license":"SEE LICENSE IN developer-license-3.1.txt"} |
Sorry, the diff of this file is not supported yet
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
211438
5309