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

@sap/cds-hana

Package Overview
Dependencies
Maintainers
3
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sap/cds-hana - npm Package Compare versions

Comparing version 1.7.1 to 1.11.1

34

CHANGELOG.md

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

## Version 1.11.1 - 2019-05-16
### Changed
- Updated version of @sap/cds-sql to 1.11.1
## Version 1.11.0 - 2019-05-15
### Changed
- Improved performance by reducing calls to process.nextTick()
## Version 1.10.0 - 2019-05-03
### Added
- Service related functions
## Version 1.9.0 - 2019-04-16
### Added
- `client.stream()` for streaming large binaries
### Changed
- Make hdb default driver
## Version 1.8.0 - 2019-03-29
### Changed
- Updated version of @sap/cds-sql to 1.8.0
## Version 1.7.1 - 2019-03-19

@@ -11,0 +45,0 @@

49

lib/cds.js

@@ -1,33 +0,36 @@

const _notInjected = () => {
throw new Error('This method requires `cds` to be injected')
}
const injection = {
inject (cds) {
if (!cds || typeof cds !== 'object') {
throw new Error('Injected value is not of type `cds`')
}
const _validateInjection = cds => {
if (!cds || typeof cds !== 'object') {
throw new Error('Injected value is not of type `cds`')
injection.cds = cds
require('@sap/cds-sql').inject(cds)
}
}
const injection = {
cds: {
parse: {
cql: _notInjected
const handler = {
get: (target, name) => {
switch (name) {
case 'inject':
case 'cds':
return target[name]
}
},
inject (cds) {
_validateInjection(cds)
injection.cds = cds
require('@sap/cds-sql').inject(cds)
},
parse: {
cql (arg) {
return injection.cds.parse.cql(arg)
if (!injection.cds) {
if (name === 'config') {
return { data: {} }
}
throw new Error('This method requires `cds` to be injected')
}
},
get config () {
return injection.cds.config || {}
if (name === 'config' && !target.cds.config) {
return { data: {} }
}
return target.cds[name]
}
}
module.exports = injection
module.exports = new Proxy(injection, handler)

@@ -10,2 +10,5 @@ const hanaClient = require('./hanaClient')

const {
postProcessing: { getPostProcessMapper, getPropertyMapper, getStructMapper }
} = cdsSql
const {
convertToBoolean,

@@ -49,2 +52,7 @@ convertInt64ToString,

// hana-client
if (this._dbc.constructor.name === 'Connection') {
this._hanaStream = require('@sap/hana-client/extension/Stream.js')
}
registerReconnect(this)

@@ -60,3 +68,3 @@ }

return new Promise((resolve, reject) => {
this._dbc.connect(err => {
this._traced(this._dbc.connect, err => {
if (err) {

@@ -66,6 +74,7 @@ return reject(convertErrorCodeToString(err))

this._isInUse = true
if (this._credentials.schema) {
this.execute(`SET SCHEMA ${this._credentials.schema}`)
.then(() => {
this._isInUse = true
resolve(this)

@@ -78,3 +87,2 @@ })

} else {
this._isInUse = true
return resolve(this)

@@ -93,5 +101,15 @@ }

this._isInUse = false
return Promise.resolve(this._dbc.end())
return cdsSql.thenable.resolve(this._dbc.end())
}
_getDynatraceDbInfo () {
return {
name: `${this._credentials.host}:${this._credentials.port}`, // TODO: Get real name from VCAP
vendor: 'HanaDB',
host: this._credentials.host,
port: Number(this._credentials.port)
}
}
/**

@@ -131,11 +149,11 @@ * Execute SQL statement.

if (this._toBeDestroyed) {
return Promise.reject(new cdsSql.errors.InconsistentClientError())
return cdsSql.thenable.reject(new cdsSql.errors.InconsistentClientError())
}
if (!Array.isArray(values)) {
return Promise.reject(new cdsSql.errors.IllegalFunctionArgumentError('values'))
return cdsSql.thenable.reject(new cdsSql.errors.IllegalFunctionArgumentError('values'))
}
if (typeof query === 'string') {
return this._executeSQL(query, values, new Map())
return this._executeSQL(query, values, false, new Map())
}

@@ -167,30 +185,65 @@

// in case an object is passed and sql builder throws an error
return Promise.reject(convertErrorCodeToString(err))
return cdsSql.thenable.reject(convertErrorCodeToString(err))
}
}
_execute (query, inValues = []) {
const query_ = this._addDefaultValues(query, false, true)
/**
* Stream large binary from HANA.
*
* The query can be provided as SELECT SQL string or as SELECT CQN object selecting exactly one large binary columns.
*
* @example <caption>Simple Select as SQL string<caption>
* .execute("SELECT BLOB FROM T")
* @example <caption>Select with filter as CQN object<caption>
* .execute(SELECT.from('T').columns('BLOB').where(['x', '=', 1])
*
* @param {string|object} query - SELECT SQL string or SELECT CQN object.
* @param {Array} [values] - Values to be set in the SQL statement if query is provided as string or as CQN object with placeholders.
* @returns {Promise} Promise, that resolves with stream if successful or rejects with error if not.
* Result object can be undefined if no rows obtained.
*/
async stream (query, values = []) {
if (!query.SELECT && (typeof query !== 'string' || !query.trim().startsWith('SELECT'))) {
return cdsSql.thenable.reject(new cdsSql.errors.IllegalFunctionArgumentError('query'))
}
values.streaming = true
const resultSet = await this.execute(query, values)
if (resultSet.length === 0) {
return
}
// resultset entry always has values
const stream = Object.values(resultSet[0])[0]
// non-blob or multiple rows selected
if (typeof stream.pipe !== 'function') {
return
}
return stream
}
_execute (cqn, inValues = []) {
const cqnWithDefaultValues = this._addDefaultValues(cqn, false, true)
const { sql, values = [] } = cdsSql.builder.sqlFactory(
query_,
{
typeConversion: this._typeConversionMap,
customBuilder: CustomBuilder,
user: this._user
},
cqnWithDefaultValues,
{ typeConversion: this._typeConversionMap, customBuilder: CustomBuilder, user: this._user },
this._csn
)
const { postProcessing: { getPostProcessMapper, getPropertyMapper, getStructMapper } } = cdsSql
const propertyMapper = getPropertyMapper(this._csn, cqn, true)
const outValues = inValues.length > 0 ? inValues : values
outValues.streaming = inValues.streaming
const propertyMapper = getPropertyMapper(this._csn, query, true)
const outValues = inValues.length > 0 ? inValues : values
return this._executeSQL(
sql,
outValues,
getPostProcessMapper(this._toService, this._csn, query),
cqn.SELECT && cqn.SELECT.one,
getPostProcessMapper(this._toService, this._csn, cqn),
propertyMapper,
getStructMapper(this._csn, query, propertyMapper)
getStructMapper(this._csn, cqn, propertyMapper),
this._hanaStream && (cqn.INSERT || cqn.UPDATE)
)

@@ -210,3 +263,3 @@ }

return cdsSql.expand.rawToExpanded(expandQueries, queries)
return cdsSql.expand.rawToExpanded(expandQueries, queries, cqn.SELECT.one)
}

@@ -216,9 +269,7 @@

if (Array.isArray(values) && values.length !== 0) {
return this.prepareStatement(sql).then(statement => {
return statement.execute(values)
})
return this.preparedExecute(sql, false, values)
}
return new Promise((resolve, reject) => {
this._dbc.exec(sql, (err, result) => {
this._traced(this._dbc.exec, sql, (err, result) => {
if (err) {

@@ -261,18 +312,21 @@ convertErrorCodeToString(err)

_executeSQL (sql, values, postMapper, propertyMapper, objStructMapper) {
_executeSQL (sql, values, isOne, postMapper, propertyMapper, objStructMapper, useHanaClientStatement) {
if (values.length !== 0) {
return this.prepareStatement(sql)
.then(statement => {
return statement.execute(values)
const executed = this.preparedExecute(sql, useHanaClientStatement, values)
if (this._postProcessNeeded(isOne, postMapper, propertyMapper, objStructMapper)) {
return executed.then(result => {
result = this._returnFirstResultIfOne(
isOne,
cdsSql.postProcessing.postProcess(result, postMapper, propertyMapper, objStructMapper)
)
return result
})
.then(result => {
return Promise.resolve(cdsSql.postProcessing.postProcess(result, postMapper, propertyMapper, objStructMapper))
})
.catch(err => {
return Promise.reject(err)
})
}
return executed
}
return new Promise((resolve, reject) => {
this._dbc.exec(sql, (err, result) => {
this._traced(this._dbc.exec, sql, (err, result) => {
if (err) {

@@ -284,3 +338,8 @@ convertErrorCodeToString(err)

resolve(cdsSql.postProcessing.postProcess(result, postMapper, propertyMapper, objStructMapper))
resolve(
this._returnFirstResultIfOne(
isOne,
cdsSql.postProcessing.postProcess(result, postMapper, propertyMapper, objStructMapper)
)
)
})

@@ -290,19 +349,88 @@ })

_postProcessNeeded (isOne, postMapper, propertyMapper, objStructMapper) {
if (isOne) {
return true
}
if (postMapper && postMapper.size) {
return true
}
if (propertyMapper && propertyMapper.size) {
return true
}
return objStructMapper && objStructMapper.size
}
_returnFirstResultIfOne (isOne, result) {
if (isOne) {
return result.length > 0 ? result[0] : null
}
return result
}
/**
* Prepare and execute SQL statement.
*
* @param {string} sql - SQL string to be prepared.
* @param {boolean} useHanaClientStatement - Use HanaClientStatement
* @param {Array} [values] - Values to be set in the SQL statement if query is provided as string or as CQN object with placeholders.
* @returns {Promise} Promise, that resolves with HdbStatement if successful and rejects if not.
*/
preparedExecute (sql, useHanaClientStatement, values) {
const that = this
return new Promise((resolve, reject) => {
this._traced(this._preparedExecuteCb, sql, useHanaClientStatement, values, that, (error, results) => {
if (error) {
reject(error)
} else {
resolve(results)
}
})
})
}
/**
* Wrapper to use callbacks, which are needed for tracing.
*/
_preparedExecuteCb (sql, useHanaClientStatement, values, client, cb) {
client
.prepareStatement(sql, useHanaClientStatement)
.then(statement => {
return statement.execute(values)
})
.then(results => cb(null, results))
.catch(error => cb(error))
}
/**
* Prepare SQL statement.
* Beware: For tracing use preparedExecute instead.
*
* @param {string} sql - SQL string to be prepared.
* @param {boolean} useHanaClientStatement - Use HanaClientStatement
* @returns {Promise} Promise, that resolves with HdbStatement if successful and rejects if not.
*/
prepareStatement (sql) {
prepareStatement (sql, useHanaClientStatement) {
return new Promise((resolve, reject) => {
this._dbc.prepare(sql, (err, statement) => {
const cb = (err, statement) => {
if (err) {
convertErrorCodeToString(err)
err.failedQuery = sql
return reject(err)
}
resolve(new HdbStatement(statement, sql))
})
resolve(new HdbStatement(statement, sql, this._hanaStream))
}
if (this._hanaStream && useHanaClientStatement) {
this._hanaStream.createStatement(this._dbc, sql, cb)
} else {
this._dbc.prepare(sql, cb)
}
})

@@ -367,2 +495,3 @@ }

this._transCount++
if (this._transCount === 1) {

@@ -372,3 +501,3 @@ this._dbc.setAutoCommit(false)

return Promise.resolve()
return cdsSql.thenable.resolve()
}

@@ -383,12 +512,16 @@

if (this._transCount === 0) {
return Promise.resolve()
return cdsSql.thenable.resolve()
}
this._transCount--
if (this._transCount === 0) {
return new Promise((resolve, reject) => {
this._dbc.commit(err => {
this._traced(this._dbc.commit, err => {
this._dbc.setAutoCommit(true)
if (err) {
return reject(convertErrorCodeToString(err))
}
resolve()

@@ -399,3 +532,3 @@ })

return Promise.resolve()
return cdsSql.thenable.resolve()
}

@@ -410,12 +543,16 @@

if (this._transCount === 0) {
return Promise.resolve()
return cdsSql.thenable.resolve()
}
this._transCount--
if (this._transCount === 0) {
return new Promise((resolve, reject) => {
this._dbc.rollback(err => {
this._traced(this._dbc.rollback, err => {
this._dbc.setAutoCommit(true)
if (err) {
return reject(convertErrorCodeToString(err))
}
resolve()

@@ -426,3 +563,3 @@ })

return Promise.resolve()
return cdsSql.thenable.resolve()
}

@@ -429,0 +566,0 @@

@@ -1,13 +0,16 @@

const _getClient = (name, err) => {
let error
const _getClient = name => {
try {
return require(name)
} catch (e) {
if (name === '@sap/hana-client') {
return _getClient('hdb', e)
} catch (err) {
if (name === 'hdb') {
error = err
return _getClient('@sap/hana-client')
}
throw e
throw error
}
}
module.exports = _getClient('@sap/hana-client')
module.exports = _getClient('hdb')
const _checkHanaClient = () => {
try {
require.resolve('@sap/hana-client')
require.resolve('hdb')
} catch (e) {
try {
require.resolve('@sap/hana-client')
} catch (e) {
return false
}
return true
} catch (e) {
return false
}
return false
}

@@ -9,0 +16,0 @@

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

const cds = require('../cds')
const SelectBuilder = require('@sap/cds-sql').builder.SelectBuilder

@@ -13,2 +14,13 @@

if (cds.config.data.sql_mapping === 'plain') {
CustomSelectBuilder.prototype._buildRefElement = function (col, res, noQuoting) {
res = new this.ReferenceBuilder(col, this._options, this._csn).build()
if (!noQuoting && !col.as && res.sql && !res.sql.includes(' as ')) {
res.sql += ` AS ${this._options.delimiter}${col.ref[col.ref.length - 1]}${this._options.delimiter}`
}
return res
}
}
module.exports = CustomSelectBuilder

@@ -12,2 +12,7 @@ const dependencies = {

},
get serviceFunctions () {
const { serviceFunctions } = require('@sap/cds-sql')
Object.defineProperty(dependencies, 'serviceFunctions', { value: serviceFunctions })
return serviceFunctions
},
inject: (...args) => {

@@ -14,0 +19,0 @@ return require('./cds').inject(...args)

@@ -9,6 +9,8 @@ const { convertErrorCodeToString } = require('../util')

* @param {string} sql - SQL string to be passed to SqlError
* @param {object} hanaStream - hanaStream object if using hana-client
*/
constructor (statement, sql) {
constructor (statement, sql, hanaStream) {
this._stmt = statement
this._sql = sql
this._hanaStream = hanaStream
}

@@ -38,3 +40,3 @@

return new Promise((resolve, reject) => {
this._stmt.exec(values, (err, result) => {
this._stmt[this._getFunctionName(values.streaming)](values, (err, result) => {
if (err) {

@@ -50,8 +52,116 @@ convertErrorCodeToString(err)

}
resolve(result)
if (values.streaming) {
if (this._hanaStream) {
return this._getReadObjectHanaClient(result, resolve, reject)
}
const rows = []
const objStream = result.createObjectStream()
objStream
.on('readable', this._getReadObjectHdb(objStream, rows))
.once('error', this._getErrorObjectHdb(reject))
.once('end', this._getEndObjectHdb(rows, resolve))
} else {
resolve(result)
}
})
})
}
_getReadObjectHdb (result, rows) {
return () => {
const row = result.read()
if (row) {
for (const key of Object.keys(row)) {
if (typeof row[key] === 'object' && typeof row[key].createReadStream === 'function') {
row[key] = row[key].createReadStream()
}
}
rows.push(row)
}
}
}
_getEndObjectHdb (rows, resolve) {
return () => {
return resolve(rows)
}
}
_getErrorObjectHdb (reject) {
return err => {
return reject(err)
}
}
_getColumnInfo (result) {
const columnInfo = []
for (let i = 0, length = result.getColumnCount(); i < length; i++) {
columnInfo.push({
name: result.getColumnInfo()[i].originalColumnName,
lob: result.getColumnInfo()[i].nativeTypeName === 'BLOB'
})
}
return columnInfo
}
_getResultSetRow (result, columnInfo) {
const res = {}
for (let i = 0, length = result.getColumnCount(); i < length; i++) {
if (columnInfo[i].lob) {
res[columnInfo[i].name] = this._hanaStream.createLobStream(result, i, { readSize: 1024000 })
} else {
res[columnInfo[i].name] = result.getValue(i)
}
}
return res
}
// The method createObjectStream does not work in hana-client as expected.
// It provides the complete LOBs and not the streams.
// The resultset should be constructed like bellow.
_getReadObjectHanaClient (result, resolve, reject) {
const resultSet = []
const columnInfo = this._getColumnInfo(result)
let next = true
while (next) {
next = result.next((err, ret) => {
if (err) {
return reject(err)
}
if (ret) {
resultSet.push(this._getResultSetRow(result, columnInfo))
}
if (!next) {
resolve(resultSet)
}
})
}
}
_getFunctionName (streaming) {
if (streaming) {
if (this._hanaStream) {
return 'executeQuery'
}
return 'execute'
}
return 'exec'
}
}
module.exports = HdbStatement
{
"name": "@sap/cds-hana",
"version": "1.7.1",
"version": "1.11.1",
"lockfileVersion": 1,

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

"@sap/cds-sql": {
"version": "1.7.0"
"version": "1.11.1"
}
}
}

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

{"bundleDependencies":false,"dependencies":{"@sap/cds-sql":"1.7.0"},"deprecated":false,"description":"Driver package for access to hana database, including setting up the client, configuring all the necessary options to initiate the connection and handling database specifics so that they can be processed on our end.","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-hana","version":"1.7.1","license":"SEE LICENSE IN developer-license-3.1.txt"}
{"bundleDependencies":false,"dependencies":{"@sap/cds-sql":"1.11.1"},"deprecated":false,"description":"Driver package for access to hana database, including setting up the client, configuring all the necessary options to initiate the connection and handling database specifics so that they can be processed on our end.","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-hana","version":"1.11.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