msnodesqlv8
Version:
Microsoft Driver for Node.js SQL Server compatible with all versions of Node.
263 lines (231 loc) • 6.7 kB
JavaScript
'use strict'
const { ServerDialect } = require('./dialect')
class ProcedureParamMeta {
constructor (raw) {
this.proc_name = raw.proc_name
this.type_desc = raw.type_desc
this.object_id = raw.object_id
this.has_default_value = raw.has_default_value
this.default_value = raw.default_value
this.is_output = raw.is_output
this.precision = raw.precision
this.scale = raw.scale
this.name = raw.name
this.type_id = raw.type_id
this.max_length = raw.max_length
this.order = raw.order
this.collation = raw.collation
this.is_user_defined = raw.is_user_defined
}
}
/*
{
proc_name: "test_sp",
type_desc: "SQL_STORED_PROCEDURE",
object_id: 1446165539,
has_default_value: false,
default_value: null,
is_output: false,
name: "@param",
type_id: "varchar",
max_length: 50,
order: 1,
collation: "SQL_Latin1_General_CP1_CI_AS",
is_user_defined: null,
}
*/
class ProcedureParamFactory {
makeParam (procName, paramName, paramType, paramLength, isOutput) {
return {
proc_name: procName,
type_desc: 'SQL_STORED_PROCEDURE',
object_id: -1,
has_default_value: false,
default_value: null,
is_output: isOutput,
name: paramName,
type_id: paramType,
max_length: paramLength,
order: 1,
collation: '',
is_user_defined: null
}
}
returnParam () {
return {
is_output: true,
name: '@returns',
type_id: 'int',
max_length: 4,
order: 0,
is_user_defined: false,
has_default_value: false,
default_value: null,
collation: null
}
}
}
class ProcedureMeta {
constructor (name, paramVector) {
this.name = name
this.dialect = ServerDialect.SqlServer
this.paramVector = paramVector.map(p => new ProcedureParamMeta(p))
const summary = this.constructMeta(name, this.paramVector)
this.select = summary.select
this.signature = summary.signature
this.summary = summary
this.params = summary.params
this.outputParams = summary.outputParams
this.inputParams = summary.inputParams
this.paramByName = summary.paramByName
}
reconstruct () {
this.constructMeta(this.name, this.paramVector)
}
constructMeta (name, paramVector) {
paramVector = paramVector.filter(p => p.object_id !== null)
const outputParams = paramVector.filter(p => p.is_output)
const inputParams = paramVector.filter(p => !p.is_output)
const signature = this.buildSignature(paramVector, name)
const select = this.asSelect(paramVector, name)
const summary = this.summarise(name, paramVector)
const paramByName = paramVector.reduce((agg, latest) => {
if (latest.name) {
agg[latest.name.slice(1)] = latest
}
return agg
}, {})
return {
select,
signature,
summary,
params: paramVector,
outputParams,
inputParams,
paramByName
}
}
isSybase () {
return this.dialect === ServerDialect.Sybase
}
isSqlServer () {
return this.dialect === ServerDialect.SqlServer
}
buildSignature (pv, name) {
const pars = pv.reduce((aggr, latest, i) => {
if (i > 0) {
aggr.push(`${latest.name} = ?`)
}
return aggr
}, []).join(', ')
return `{ ? = call ${name}(${pars}) }`
}
asSelect (pv, procedure) {
if (this.isSqlServer()) {
return this.asSelectSqlServer(pv, procedure)
} else {
return this.asSelectSybase(pv, procedure)
}
}
asSelectSqlServer (pv, procName) {
const params = []
const parameters = []
pv.forEach(param => {
if (param.name !== '@returns') {
parameters.push(param)
}
})
parameters.forEach(param => {
if (param.is_output) {
const s = `${param.name} ${param.type_id}`
params.push(s)
}
})
const cmdParam = ['@___return___ int'].concat(params).join(', ')
let cmd = `declare ${cmdParam};`
cmd += `exec = ${procName} `
const spp = parameters.map(param => {
return (param.is_output)
? `${param.name}=${param.name} output`
: param.name + '=?'
})
const params2 = this.asOutput(parameters)
const sppJoined = spp.join(', ')
cmd += sppJoined + ';'
const selectCmd = `select ${['@___return___ as \'___return___\''].concat(params2).join(', ')}`
cmd += selectCmd + ';'
return cmd
}
asSelectSybase (pv, procName) {
const params = []
const parameters = []
pv.forEach(param => {
if (param.name !== '@returns') {
parameters.push(param)
}
})
parameters.forEach(param => {
if (param.is_output) {
const size = param.type_id === 'varchar' ? `(${param.max_length})` : ''
const s = `${param.name} ${param.type_id}${size}`
params.push(s)
}
})
let cmdParam = ['@___return___ int'].concat(params).join(', ')
let cmd = `declare ${cmdParam} `
cmd += `exec = ${procName} `
const spp = []
parameters.forEach(param => {
if (param.is_output) {
// output parameter
cmdParam = `${param.name} output`
spp.push(cmdParam)
} else {
// input parameter
cmdParam = param.name + '=?'
spp.push(cmdParam)
}
})
const params2 = this.asOutput(parameters)
const sppJoined = spp.join(', ')
cmd += sppJoined + ' '
const selectCmd = `select ${['@___return___ as \'___return___\''].concat(params2).join(', ')}`
cmd += selectCmd + ' '
return cmd
}
asOutput (parameters) {
const params2 = []
parameters.forEach(param => {
if (param.is_output) {
let paramName = param.name
if (paramName[0] === '@') {
paramName = paramName.substring(1)
}
const cmdParam = `${param.name} as ${paramName}`
params2.push(cmdParam)
}
})
return params2
}
summarise (name, pv) {
if (!pv || pv.length === 0) return 'proc does not exist.'
let s = `${this.descp(pv[0])} ${name}( `
for (let i = 1; i < pv.length; i += 1) {
s += this.descp(pv[i])
if (i < pv.length - 1) {
s += ', '
}
}
s += ' ) '
return s
}
descp (p) {
let s = ''
s += `${p.name} [ ${p.type_id}${p.is_output
? ' out '
: ' in '} ] `
return s
}
}
exports.ProcedureMeta = ProcedureMeta
exports.ProcedureParamFactory = ProcedureParamFactory