Определение инстерфейса модуля работы с БД

This commit is contained in:
Mikhail Chechnev 2018-11-07 21:32:28 +03:00
parent 6e34f4d3c2
commit 70efa0250d
5 changed files with 167 additions and 93 deletions

View File

@ -15,6 +15,10 @@ exports.MODULES_PATH_EX = "@modules"; //Дополнительные польз
exports.ERR_MODULES_NO_MODULE_SPECIFIED = "ERR_MODULES_NO_MODULE_SPECIFIED"; //Не указан подключаемый модуль
exports.ERR_MODULES_BAD_INTERFACE = "ERR_MODULES_BAD_INTERFACE"; //Ошибочный интерфейс подключаемого модуля
//Типовые коды ошибок работы с объектами
exports.ERR_OBJECT_BAD_INTERFACE = "ERR_OBJECT_BAD_INTERFACE"; //Ошибочный интерфейс объекта
//Типовые коды ошибок работы с БД
exports.ERR_DB_CONNECT = "ERR_DB_CONNECT"; //Ошибка подключения к БД
exports.ERR_DB_DISCONNECT = "ERR_DB_DISCONNECT"; //Ошибка отключения от БД
exports.ERR_DB_EXECUTE = "ERR_DB_EXECUTE"; //Ошибка исполнения функции в БД

View File

@ -9,7 +9,7 @@
const _ = require("lodash"); //Работа с массивами и объектами
const glConst = require("@core/constants.js"); //Глобальные константы
const { checkModuleInterface, makeModuleFullPath } = require("@core/utils.js"); //Вспомогательные функции
const { checkModuleInterface, makeModuleFullPath, checkObject } = require("@core/utils.js"); //Вспомогательные функции
const { ServerError } = require("@core/server_errors.js"); //Типовая ошибка
//------------
@ -19,26 +19,55 @@ const { ServerError } = require("@core/server_errors.js"); //Типовая ош
class DBConnector {
//Конструктор
constructor(dbConnect) {
//Проверяем наличие модуля для работы с БД в настройках подключения
if (dbConnect.module) {
//Подключим модуль
this.connector = require(makeModuleFullPath(dbConnect.module));
//Проверим его интерфейс
if (!checkModuleInterface(this.connector, { functions: ["connect", "disconnect", "execute"] })) {
//Проверяем структуру переданного объекта для подключения
let checkResult = checkObject(dbConnect, {
fields: [
{ name: "user", required: true },
{ name: "password", required: true },
{ name: "connectString", required: true },
{ name: "module", required: false }
]
});
//Если структура объекта в норме
if (!checkResult) {
//Проверяем наличие модуля для работы с БД в настройках подключения
if (dbConnect.module) {
//Подключим модуль
this.connector = require(makeModuleFullPath(dbConnect.module));
//Проверим его интерфейс
if (
!checkModuleInterface(this.connector, {
functions: [
"connect",
"disconnect",
"getServices",
"log",
"getQueueOutgoing",
"putQueueIncoming",
"setQueueValue"
]
})
) {
throw new ServerError(
glConst.ERR_MODULES_BAD_INTERFACE,
"Модуль " + dbConnect.module + " реализует неверный интерфейс!"
);
}
//Всё успешно - сохраним настройки подключения
this.connectSettings = {};
_.extend(this.connectSettings, dbConnect);
//Инициализируем остальные свойства
this.connection = {};
} else {
throw new ServerError(
glConst.ERR_MODULES_BAD_INTERFACE,
"Модуль " + dbConnect.module + " реализует неверный интерфейс!"
glConst.ERR_MODULES_NO_MODULE_SPECIFIED,
"Не указано имя подключаемого модуля-коннектора!"
);
}
//Всё успешно - сохраним настройки подключения
this.connectSettings = {};
_.extend(this.connectSettings, dbConnect);
//Инициализируем остальные свойства
this.connection = {};
} else {
throw new ServerError(
glConst.ERR_MODULES_NO_MODULE_SPECIFIED,
"Не указано имя подключаемого модуля-коннектора!"
glConst.ERR_OBJECT_BAD_INTERFACE,
"Объект имеет недопустимый интерфейс: " + checkResult
);
}
}
@ -62,7 +91,14 @@ class DBConnector {
}
}
//Исполнить запрос
async execute() {}
async getServices() {
try {
let res = await this.connector.getServices(this.connection);
return res;
} catch (e) {
throw new ServerError(glConst.ERR_DB_EXECUTE, e.message);
}
}
}
//-----------------

View File

@ -59,6 +59,48 @@ const checkModuleInterface = (module, interface) => {
return res;
};
//Проверка корректности полей объекта
const checkObject = (obj, interface) => {
//Объявим результат
let res = "";
//Если есть что проверять
if (obj && interface) {
//Eсли есть список полей для проверки
if (interface.fields) {
if (Array.isArray(interface.fields)) {
let noFields = [];
let noValues = [];
//Обходим проверяемые поля
interface.fields.forEach(fld => {
//Проверим наличие поля в объекте
if (!(fld.name in obj)) {
//Поля нет
noFields.push(fld.name);
} else {
//Поле есть, проверим наличие значения
if (fld.required && !obj[fld.name])
//Обязательное поле не содержит значения
noValues.push(fld.name);
}
});
//Сформируем итоговое сообщение
if (noFields.length > 0) res = "Объект не содержит полей: " + noFields.join(", ");
if (noValues.length > 0)
res +=
(res == "" ? "" : "; ") + "Обязательные поля объекта не имеют значений: " + noValues.join(", ");
} else {
res = "Список проверяемых полей объекта не является массивом";
}
} else {
res = "Не указан список проверяемых полей объекта";
}
} else {
res = "Не указан проверяемый объект и/или его интерфейс";
}
//Вернем результат
return res;
};
//Формирование полного пути к подключаемому модулю
const makeModuleFullPath = moduleName => {
if (moduleName) {
@ -75,4 +117,5 @@ const makeModuleFullPath = moduleName => {
exports.isFunction = isFunction;
exports.haveFunctions = haveFunctions;
exports.checkModuleInterface = checkModuleInterface;
exports.checkObject = checkObject;
exports.makeModuleFullPath = makeModuleFullPath;

View File

@ -2,6 +2,11 @@
Сервис интеграции ПП Парус 8 с WEB API
Точка входа в сервер приложений
*/
//----------------------
// Подключение библиотек
//----------------------
require("module-alias/register");
const cfg = require("./config.js");
const { Logger } = require("@core/logger.js");
@ -10,19 +15,39 @@ const { ServerError } = require("@core/server_errors.js");
const parus = require("@modules/parus_db.js");
const utls = require("@core/utils.js");
//------------
// Тело модуля
//------------
let a = new db.DBConnector(cfg.dbConnect);
a.connect()
.then(res => {
console.log(res);
setTimeout(() => {
a.disconnect()
.then(res => {
console.log("DISCONNECTED");
})
.catch(e => {
console.log(e.code + ": " + e.message);
});
}, 2000);
console.log("CONNECTED");
a.getServices()
.then(res => {
console.log(res);
setTimeout(() => {
a.disconnect()
.then(res => {
console.log("DISCONNECTED");
})
.catch(e => {
console.log(e.code + ": " + e.message);
});
}, 10000);
})
.catch(e => {
console.log(e.code + ": " + e.message);
setTimeout(() => {
a.disconnect()
.then(res => {
console.log("DISCONNECTED");
})
.catch(e => {
console.log(e.code + ": " + e.message);
});
}, 10000);
});
})
.catch(e => {
console.log(e.code + ": " + e.message);

View File

@ -45,81 +45,47 @@ const disconnect = connection => {
}
});
} else {
reject(new Error("No connection specified"));
reject(new Error("Не указано подключение"));
}
});
};
//Исполнение запроса
const execute = prms => {
console.log("EXECUTE");
//Получение списка сервисов
const getServices = connection => {
return new Promise((resolve, reject) => {
if (connection) {
connection.execute("select * from EXSSERVICE", [], { outFormat: oracledb.OBJECT }, (err, result) => {
if (err) {
reject(err);
}
resolve(result.rows);
});
} else {
reject(new Error("Не указано подключение"));
}
});
};
//Запись в протокол работы
const log = prms => {};
//Считывание очередной порции исходящих сообщений из очереди
const getQueueOutgoing = prms => {};
//Помещение очередного входящего сообщения в очередь
const putQueueIncoming = prms => {};
//Установка значения в сообщении очереди
const setQueueValue = prms => {};
//-----------------
// Интерфейс модуля
//-----------------
exports.connect = connect;
exports.disconnect = disconnect;
exports.execute = execute;
/*
oracledb.getConnection(
{
user: cfg.dbConnect.user,
password: cfg.dbConnect.password,
connectString: cfg.dbConnect.connectString
},
function(err, connection) {
if (err) {
console.error(err.message);
return;
}
connection.execute(
// The statement to execute
"SELECT rn, agnabbr FROM agnlist WHERE rn = :id",
// The "bind value" 180 for the bind variable ":id"
[1431890],
// execute() options argument. Since the query only returns one
// row, we can optimize memory usage by reducing the default
// maxRows value. For the complete list of other options see
// the documentation.
{
maxRows: 1
//, outFormat: oracledb.OBJECT // query result format
//, extendedMetaData: true // get extra metadata
//, fetchArraySize: 100 // internal buffer allocation size for tuning
},
// The callback function handles the SQL execution results
function(err, result) {
if (err) {
console.error(err.message);
setTimeout(() => {
doRelease(connection);
}, 2000);
return;
}
console.log(result.metaData); // [ { name: 'DEPARTMENT_ID' }, { name: 'DEPARTMENT_NAME' } ]
console.log(result.rows); // [ [ 180, 'Construction' ] ]
setTimeout(() => {
doRelease(connection);
}, 2000);
}
);
}
);
// Note: connections should always be released when not needed
function doRelease(connection) {
connection.close(function(err) {
if (err) {
console.log("Connection closed with erros: " + err.message);
} else {
console.log("Connection closed - no erros");
}
});
}
*/
exports.getServices = getServices;
exports.log = log;
exports.getQueueOutgoing = getQueueOutgoing;
exports.putQueueIncoming = putQueueIncoming;
exports.setQueueValue = setQueueValue;