Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@sap/cds-sql

Package Overview
Dependencies
Maintainers
3
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sap/cds-sql - npm Package Compare versions

Comparing version 1.16.0 to 1.17.1

15

CHANGELOG.md

@@ -9,2 +9,17 @@ # Changelog

## Version 1.17.1 - 2019-09-18
### Changed
- Improved error messages
- Improves SQL Builder for `.where` clauses
## Version 1.17.0 - 2019-09-09
### Fixed
- Expand-to-one in draft context
- Expand with multiple orderby elements using window function
- `UUID` generation for `INSERT` statements
## Version 1.16.0 - 2019-08-21

@@ -11,0 +26,0 @@

5

lib/client/BaseClient.js
const cds = require('../cds')
const { typeConversionMap } = require('../utils/dataTypes')
const { InconsistentClientError } = require('../errors')
const { ensureNoDraftsSuffix } = require('../utils/draftUtils')

@@ -139,3 +138,3 @@

* @param {Array} [values] - values for prepared stmt in case of SQL query string.
* @returns {Promise} - resolves with result or rejects with error.
* @returns {Promise} - resolves with result or rejects with error if client is in inconsistent state.
*/

@@ -145,3 +144,3 @@ run (query, values) {

if (this._toBeDestroyed) {
return Promise.reject(new InconsistentClientError())
return Promise.reject(new Error('Client is in an inconsistent state'))
}

@@ -148,0 +147,0 @@

4

lib/composition/compositionTree.js

@@ -175,6 +175,8 @@ const generateUUID = require('uuid/v4')

* @param {boolean} checkRoot Check is provided entity is a root
* @returns {Object} tree of all compositions
* @throws Error if no valid root entity provided
*/
const getCompositionTree = (definitions, rootEntityName, checkRoot = true, includeAssociations = false) => {
if (checkRoot && !isRootEntity(definitions, rootEntityName)) {
throw new Error('Entity is not root entity')
throw new Error(`Entity "${rootEntityName}" is not root entity`)
}

@@ -181,0 +183,0 @@ const compositionTree = {}

@@ -9,3 +9,3 @@ const { isComplex, isAssociation, resolveAssociation } = require('../utils/associations')

* @returns {function}
* @throws Error
* @throws Error if no valid parameter fn provided
* @private

@@ -18,3 +18,3 @@ */

throw Error(`Method '${fn}' does not exist`)
throw new Error(`Method "${fn}" does not exist.`)
}

@@ -21,0 +21,0 @@

@@ -7,9 +7,9 @@ const getColumns = require('../utils/columns')

// Symbols are used to add extra information in response structure
const GET_KEY_VALUE = Symbol.for('getKeyValue')
const TO_MANY = Symbol.for('toMany')
const GET_KEY_VALUE = Symbol.for('sap.cds.getKeyValue')
const TO_MANY = Symbol.for('sap.cds.toMany')
const SKIP_MAPPING = Symbol.for('skipMapping')
const IDENTIFIER = Symbol.for('identifier')
const IS_ACTIVE = Symbol.for('isActive')
const IS_UNION_DRAFT = Symbol.for('isUnionDraft')
const SKIP_MAPPING = Symbol.for('sap.cds.skipMapping')
const IDENTIFIER = Symbol.for('sap.cds.identifier')
const IS_ACTIVE = Symbol.for('sap.cds.isActive')
const IS_UNION_DRAFT = Symbol.for('sap.cds.isUnionDraft')
const DRAFT_COLUMNS = ['IsActiveEntity', 'HasActiveEntity', 'HasDraftEntity', 'DraftAdministrativeData_DraftUUID']

@@ -21,3 +21,3 @@

this._SELECT = Object.assign({}, cqn.SELECT)
this._csn = cqn[Symbol.for('cds.ql.model')] || csn
this._csn = cqn[Symbol.for('sap.cds.model')] || csn
this.queries = []

@@ -36,3 +36,3 @@ this.mappings = {}

// Add table aliases to all refs in where part obtained from annotations
this._adaptWhereAnnotations(this._SELECT.where)
this._adaptAliasForWhere(this._SELECT.where)

@@ -250,2 +250,7 @@ // Update elements at WHERE, so there are no issues with ambiguity

cqn.where = cqn.where.map(element => {
if (element.list) {
return Object.assign(element, {
list: element.list.map(element => this._checkOrderByWhereElementRecursive(cqn, element, tableAlias))
})
}
return this._checkOrderByWhereElementRecursive(cqn, element, tableAlias)

@@ -264,8 +269,16 @@ })

_adaptWhereAnnotations (where) {
_addAliasAndDeleteSymbol (whereElement) {
this._addAlias(whereElement)
delete whereElement.ref[Symbol.for('sap.cds.FROM_ANNOTATION')]
}
_addAlias (whereElement) {
whereElement.ref && whereElement.ref.unshift(Object.values(this._aliases)[0])
}
_adaptAliasForWhere (where) {
if (where) {
for (const w of where) {
if (w.ref && w.ref[Symbol.for('FROM_ANNOTATION')] === true) {
w.ref.unshift(Object.values(this._aliases)[0])
delete w.ref[Symbol.for('FROM_ANNOTATION')]
for (const whereElement of where) {
if (whereElement.ref && whereElement.ref[Symbol.for('sap.cds.FROM_ANNOTATION')] === true) {
this._addAliasAndDeleteSymbol(whereElement)
}

@@ -454,2 +467,7 @@ }

// if union always only expand with active, otherwise evaluate flag
// if flag shows false, we check entity for associations to non draft
const activeTableRequired =
readToOneCQN[IS_UNION_DRAFT] || readToOneCQN[IS_ACTIVE] || !this._isDraftEnabled(this._csn.definitions[target])
// TODO: If draft union and composition target add union as to be joined

@@ -459,3 +477,3 @@ readToOneCQN.from = {

readToOneCQN.from.SET ? this._unionToSubQuery(readToOneCQN) : readToOneCQN.from,
{ ref: [this._refFromRefByExpand(column.ref[0], entity.elements)], as: tableAlias }
{ ref: [this._refFromRefByExpand(column.ref[0], entity.elements, activeTableRequired)], as: tableAlias }
],

@@ -475,5 +493,12 @@ join:

entity: this._getEntityForTable(target),
givenColumns: column.expand.filter(
columnObj => !(columnObj.ref && columnObj.ref.length && columnObj.ref[0] === 'IsActiveEntity')
),
givenColumns: column.expand.map(col => {
if (activeTableRequired && col.ref && col.ref.length && col.ref[0] === 'IsActiveEntity') {
return {
val: true,
as: 'IsActiveEntity',
cast: { type: 'cds.Boolean' }
}
}
return col
}),
readToOneCQN: readToOneCQN,

@@ -485,4 +510,7 @@ tableAlias: tableAlias,

_refFromRefByExpand (column, elements) {
return column === 'DraftAdministrativeData' ? 'DRAFT.DraftAdministrativeData' : elements[column].target
_refFromRefByExpand (column, elements, isActiveRequired = true) {
if (column === 'DraftAdministrativeData') {
return 'DRAFT.DraftAdministrativeData'
}
return `${elements[column].target}${isActiveRequired ? '' : '_drafts'}`
}

@@ -1048,6 +1076,17 @@

_getOrderByForWindowFn (orderBy) {
return orderBy.reduce((arr, value, i) => {
arr.push(value)
if (i < orderBy.length - 1) {
arr.push(',')
}
return arr
}, [])
}
_getWindowXpr (columns, orderBy) {
const xpr = [{ func: 'ROW_NUMBER', args: [] }, 'OVER', '(', 'PARTITION BY', ...columns]
if (orderBy.length !== 0) {
xpr.push('ORDER BY', ...orderBy)
xpr.push('ORDER BY', ...this._getOrderByForWindowFn(orderBy))
}

@@ -1054,0 +1093,0 @@ xpr.push(')')

@@ -1,4 +0,4 @@

const EXPAND = Symbol.for('expand')
const GET_KEY_VALUE = Symbol.for('getKeyValue')
const TO_MANY = Symbol.for('toMany')
const EXPAND = Symbol.for('sap.cds.expand')
const GET_KEY_VALUE = Symbol.for('sap.cds.getKeyValue')
const TO_MANY = Symbol.for('sap.cds.toMany')

@@ -5,0 +5,0 @@ class RawToExpanded {

@@ -14,7 +14,2 @@ const cds = require('./cds')

},
get errors () {
const errors = require('./errors')
Object.defineProperty(dependencies, 'errors', { value: errors })
return errors
},
get builder () {

@@ -21,0 +16,0 @@ const sqlBuilder = require('./sql-builder/')

const cds = require('../cds')
const { InvalidQuotingStyleError } = require('../errors')

@@ -49,4 +48,6 @@ const _slugify = name => name.replace(/::/g, '__').replace(/\./g, '_')

_validateQuotingStyle () {
if (typeof this._quotingStyle !== 'string' || !quotingStyles.hasOwnProperty(this._quotingStyle)) {
throw new InvalidQuotingStyleError(this._quotingStyle)
let type = typeof this._quotingStyle
if (type !== 'string' || !quotingStyles.hasOwnProperty(this._quotingStyle)) {
type = type !== 'string' ? `Type ${type}` : `"${this._quotingStyle}"`
throw new Error(`Quoting style: ${type} is not supported. Allowed strings: "quoted", "plain".`)
}

@@ -53,0 +54,0 @@ }

const BaseBuilder = require('./BaseBuilder')
const { InvalidCqnObjectError } = require('../errors')

@@ -59,3 +58,3 @@ /**

*
* @throws InvalidCqnObjectError
* @throws Error if the input object is invalid
* @returns {{sql: string, values: Array}} Object with two properties.

@@ -84,4 +83,5 @@ * SQL string for prepared statement and array of values to replace the placeholders.

// Some keywords need to be process as a block, while others can be treated one at a time
if (this._reseverdKeyWords(objects, i)) {
i = i + 3
const reserved = this._reseverdKeyWords(objects, i)
if (reserved) {
i = i + reserved
} else {

@@ -106,10 +106,28 @@ this._expressionElementToSQL(objects[i])

if (objects[i + 2] && objects[i + 2].val === null) {
return this._addNullOrNotNull(objects[i], objects[i + 1])
this._addNullOrNotNull(objects[i], objects[i + 1])
return 3
}
if (/^(not )?in+/i.test(objects[i + 1])) {
return this._addInOrNotIn(objects[i], objects[i + 1].toUpperCase(), objects[i + 2])
if (objects[i + 2] !== '(') {
this._addInOrNotIn(objects[i], objects[i + 1].toUpperCase(), objects[i + 2])
return 3
}
// map other notation to current notation
const arr = []
let skip = 3
for (let j = i + 3; j < objects.length; j++) {
skip++
if (objects[j] === ')') {
break
} else if (objects[j].val) {
arr.push(objects[j].val)
}
}
this._addInOrNotIn(objects[i], objects[i + 1].toUpperCase(), { val: arr })
return skip
}
return false
return 0
}

@@ -141,3 +159,3 @@

_addInOrNotIn (reference, operator, values) {
if (values.val instanceof Array) {
if (Array.isArray(values.val)) {
this._addArrayForInQuery(reference, operator, values.val)

@@ -223,3 +241,3 @@ return true

throw new InvalidCqnObjectError()
throw new Error(`Cannot build SQL. Invalid CQN object provided: ${JSON.stringify(element)}`)
}

@@ -226,0 +244,0 @@

const BaseBuilder = require('./BaseBuilder')
const SelectBuilder = require('./SelectBuilder')
const getAnnotatedColumns = require('../utils/annotations')
const generateUUID = require('uuid/v4')

@@ -54,2 +55,5 @@ /**

// side effect: sets this.uuidKeys if found any
this._findUuidKeys(entityName)
this._columnIndexesToDelete = []

@@ -129,2 +133,17 @@ const annotatedColumns = getAnnotatedColumns(entityName, this._csn)

_findUuidKeys (entityName) {
const uuidKeys = []
if (this._csn && this._csn.definitions[entityName]) {
for (const key of Object.values(this._csn.definitions[this._obj.INSERT.into].keys)) {
if (key.type === 'cds.UUID') {
uuidKeys.push(key.name)
}
}
}
if (uuidKeys.length > 0) {
this.uuidKeys = uuidKeys
}
}
_columns (annotatedColumns) {

@@ -138,4 +157,14 @@ this._outputObj.sql.push('(')

this._outputObj.sql.push(this._obj.INSERT.columns.map(col => this._quoteElement(col)).join(', '))
const insertColumns = [...this._obj.INSERT.columns.map(col => this._quoteElement(col))]
if (this.uuidKeys) {
for (const key of this.uuidKeys) {
if (!this._obj.INSERT.columns.includes(key)) {
insertColumns.unshift(this._quoteElement(key))
}
}
}
this._outputObj.sql.push(insertColumns.join(', '))
if (annotatedColumns) {

@@ -177,2 +206,13 @@ // add insert annotated columns

if (this.uuidKeys && this._obj.INSERT.columns) {
for (const key of this.uuidKeys) {
if (!this._obj.INSERT.columns.includes(key)) {
placeholderNum += 1
this._obj.INSERT.values
? this._outputObj.values.unshift(generateUUID())
: this._outputObj.values.forEach(arr => arr.unshift(generateUUID()))
}
}
}
this._outputObj.sql.push(

@@ -183,2 +223,12 @@ ...this._createPlaceholderString(placeholderNum, annotatedInsertColumnValues.valuesAndSQLs)

_addUuidToColumns (columns, flattenColumnMap) {
if (this.uuidKeys) {
for (const key of this.uuidKeys) {
if (!flattenColumnMap.get(key)) {
columns.push(...this.uuidKeys.map(key => this._quoteElement(key)))
}
}
}
}
/**

@@ -207,2 +257,3 @@ * This method creates insert statement in case of multiple entries.

this._addUuidToColumns(columns, flattenColumnMap)
columns.push(...flattenColumnMap.keys())

@@ -216,4 +267,8 @@

for (const key of flattenColumnMap.get(column)) {
val = val[key]
if (!flattenColumnMap.get(column) && this.uuidKeys.includes(column)) {
val = generateUUID()
} else {
for (const key of flattenColumnMap.get(column)) {
val = val[key]
}
}

@@ -248,3 +303,3 @@

entry[key] !== null &&
!(entry[key] instanceof Buffer) &&
!Buffer.isBuffer(entry[key]) &&
typeof entry[key].pipe !== 'function'

@@ -251,0 +306,0 @@ ) {

const BaseBuilder = require('./BaseBuilder')
const { FeatureNotSupportedError } = require('../errors')

@@ -33,3 +32,2 @@ /**

*
* @throws InvalidCqnObjectError
* @returns {{sql: string, values: Array}} Object with two properties.

@@ -73,3 +71,3 @@ * SQL string for prepared statement and an empty array of values.

if (refArray[0].id) {
throw new FeatureNotSupportedError()
throw new Error(`${refArray[0].id}: Views with parameters supported only on HANA`)
}

@@ -76,0 +74,0 @@ this._outputObj.sql.push(refArray.map(el => this._quoteElement(el)).join('.'))

@@ -1,2 +0,1 @@

const { IllegalFunctionArgumentError } = require('../errors')
const DeleteBuilder = require('./DeleteBuilder')

@@ -49,8 +48,8 @@ const InsertBuilder = require('./InsertBuilder')

* @param {Object} [csn] CSN
* @throws IllegalFunctionArgumentError
* @returns {string} The SQL string
* * @throws Error if no valid CQN object provided
*/
const build = (cqn, options, csn) => {
if (!cqn) {
throw new IllegalFunctionArgumentError('cqn')
throw new Error('Cannot build SQL. No CQN object provided.')
}

@@ -91,5 +90,5 @@

throw new IllegalFunctionArgumentError('cqn')
throw new Error(`Cannot build SQL. Invalid CQN object provided: ${JSON.stringify(cqn)}`)
}
module.exports = build
{
"name": "@sap/cds-sql",
"version": "1.16.0",
"version": "1.17.1",
"lockfileVersion": 1,

@@ -5,0 +5,0 @@ "requires": true,

@@ -1,1 +0,1 @@

{"bundleDependencies":false,"dependencies":{"uuid":"3.3.2"},"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.16.0","license":"SEE LICENSE IN developer-license-3.1.txt"}
{"bundleDependencies":false,"dependencies":{"uuid":"3.3.2"},"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.17.1","license":"SEE LICENSE IN developer-license-3.1.txt"}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc