diff --git a/examples/example.mssql.config.js b/examples/example.mssql.config.js index f8e56c3..f120b00 100644 --- a/examples/example.mssql.config.js +++ b/examples/example.mssql.config.js @@ -3,7 +3,7 @@ module.exports = { server: 'localhost', user: 'sa', password: '***', - database: 'mfactor', + database: 'some-test-example-mssql', pool: { max: 10, min: 0, @@ -15,8 +15,7 @@ module.exports = { } }, link: { - SP: { - schemas: ['a', 'b'] // schemas allowed - } + gluePrefix: '.', + schema: ['a', 'b'] // schemas allowed } }; \ No newline at end of file diff --git a/examples/mssql/example.sql b/examples/mssql/example.sql new file mode 100644 index 0000000..d03af38 --- /dev/null +++ b/examples/mssql/example.sql @@ -0,0 +1,32 @@ +CREATE TYPE LessonType AS TABLE (LessonId INT, LessonName VARCHAR(100)) + +CREATE TABLE Lesson ( + Id INT PRIMARY KEY, + LName VARCHAR(50) +) +------------------------- +CREATE PROCEDURE Usp_InsertLesson + @ParLessonType LessonType READONLY, + @ParLessonType2 LessonType READONLY +AS + INSERT INTO Lesson + SELECT * FROM @ParLessonType; + +CREATE PROCEDURE Usp_InsertLesson2 + @ParLessonType LessonType READONLY, + @ParLessonType2 LessonType READONLY +AS + INSERT INTO Lesson + SELECT * FROM @ParLessonType +------------------------- +DECLARE @VarLessonType AS LessonType + +INSERT INTO @VarLessonType VALUES ( 1, 'Math') +INSERT INTO @VarLessonType VALUES ( 2, 'Science') +INSERT INTO @VarLessonType VALUES ( 3, 'Geometry') + + +EXECUTE Usp_InsertLesson @VarLessonType +------------------------- +------------------------- +------------------------- \ No newline at end of file diff --git a/examples/mssql/index.js b/examples/mssql/index.js index f34083b..cc76a03 100644 --- a/examples/mssql/index.js +++ b/examples/mssql/index.js @@ -2,5 +2,9 @@ const methods = await require('../../lib/mssql')( require('../mssql.config.js') ); - methods['abc']({arg1: 123}); + try { + await methods['dbo.Usp_InsertLesson']({ParLessonType: [{LessonId: 100, LessonName: 'example lesson'}]}); + } catch (e) { + console.error(e); + } })(); \ No newline at end of file diff --git a/lib/mssql/index.js b/lib/mssql/index.js index 66dfa7c..e4cd207 100644 --- a/lib/mssql/index.js +++ b/lib/mssql/index.js @@ -77,35 +77,34 @@ const Link = async(config) => { module.exports = async(config) => { - let tableTypes = {}; - let methods = {}; + const {gluePrefix = '.'} = config; const link = await Link(config.connect); const predefinedQuery = async(key) => { if (!key) { throw SqlSe.create('noSuchSqlHelperFile'); } + const q = (await predefinedSql[key]).toString('utf8'); return link.query( - (await predefinedSql[key]).toString('utf8') + q ); } const groupTTs = (list) => { - return list.reduce((a, { + return list.reduce((type, { name, userTypeId, column, ...c }) => { - const el = a[userTypeId] || { - columns: [], - name, - userTypeId - }; - el.columns.push({...c, name: column}); + const columns = type[userTypeId]?.columns || []; return { - ...a, - [userTypeId]: el + ...type, + [userTypeId]: { + columns: columns.concat([{...c, name: column}]), + name, + userTypeId + } }; }, {}); } @@ -172,7 +171,7 @@ module.exports = async(config) => { }, {}); } - const parameter = ({ + const buildParam = ({ params: {precision, type, scale, tableType, ...paramsRest}, values }) => { @@ -208,34 +207,29 @@ module.exports = async(config) => { } } - const registerMethod = ({ - name, - args: { - name: procedure, - params: procedureParams - } = {} - }) => { - methods[name] = async( - callParams - ) => { - const paramsNameList = Object - .keys(callParams); + const executable = ({ + name: procedure, + params: definedParams + } = {}) => { + return async(params) => { + const paramsKey = Object.keys(params); + try { const request = link.request(); request.multiple = true; - callParams && paramsNameList - .reduce((a, key) => { - if (procedureParams[key] && (callParams[key] !== undefined)) { - const valueType = parameter({ - params: procedureParams[key], - values: callParams[key] + params && paramsKey + .reduce((request, key) => { + if (definedParams[key] && (params[key] !== undefined)) { + const valueType = buildParam({ + params: definedParams[key], + values: params[key] }); - valueType && a.input( + valueType && request.input( ...[key].concat(valueType) ); } - return a; + return request; }, request); return await request.execute(procedure); } catch (e) { @@ -244,20 +238,17 @@ module.exports = async(config) => { e, { procedure, - callParams: paramsNameList.join(';') + callParams: paramsKey.join(';') } ); } }; } - const storedProcedures = async() => { - const schemas = [] - .concat(config.link.SP.schemas); + const build = async(tableTypes) => { + const linkOnly = [].concat(config.link.schema); - const qr = await predefinedQuery( - 'internalMethod' - ); + const qr = await predefinedQuery('internalMethod'); const procList = qr.recordset.reduce((procedures, { name, @@ -272,19 +263,15 @@ module.exports = async(config) => { isNullable, isOutput }) => { - if (isOutput) { - return procedures; - } - if (schemas.indexOf(schema) < 0) { + if (isOutput || linkOnly.indexOf(schema) < 0) { return procedures; } - const pn = [schema, name].join('.'); - const callName = [`[${schema}]`, `[${name}]`].join('.'); - const pProps = procedures[pn] || {}; - const newParam = {}; + const pn = [schema, name].join(gluePrefix); + const callName = [`[${schema}]`, `[${name}]`].join(gluePrefix); + const params = {...(procedures[pn]?.params || {})}; if (column) { const paramClean = column.slice(1); - newParam[paramClean] = { + params[paramClean] = { name: paramClean, type, isOutput, @@ -301,37 +288,30 @@ module.exports = async(config) => { ...procedures, [pn]: { name: callName, - params: ( - pProps.params && - {...pProps.params, ...newParam} - ) || newParam + params } }; }, {}); - Object.keys(procList) - .map((name) => registerMethod({ - name: ['$procedure$', name].join('.'), - args: procList[name] - })); + return Object.keys(procList) + .reduce((procs, name) => ({ + ...procs, + [name]: executable(procList[name]) + }), {}); } - const extractTTs = async() => { + const tableTypes = async() => { const qr = await predefinedQuery( 'tableTypes' ); - tableTypes = createTTs( + return createTTs( groupTTs(qr.recordset) ); }; - const linkStoredProcedures = async() => { - await extractTTs(); - await storedProcedures(); - } - - await linkStoredProcedures(); + const tt = await tableTypes(); + const methods = await build(tt); return methods; }; diff --git a/package.json b/package.json index 080939e..6bfd627 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,11 @@ }, "dependencies": { "error": "^10.4.0", - "mssql": "8.1.2" + "mssql": "10.0.1" }, "devDependencies": { "tap": "*", - "semantic-release": "^19.0.3" + "semantic-release": "^22.0.12" }, "scripts": { "unit-test": "./node_modules/tap/bin/run.js --no-cov ./tests/unit/"