Рефакторинг: приведение полей объектов и параметров процедур к общему стилю + песочница npm test

This commit is contained in:
Mikhail Chechnev 2018-11-16 20:55:48 +03:00
parent ea74ff4ed1
commit 326565d3b4
6 changed files with 214 additions and 148 deletions

View File

@ -10,23 +10,23 @@
//Параметры подключения к БД
let dbConnect = {
//Пользователь БД
user: "parus",
sUser: "parus",
//Пароль пользователя БД
password: "parus",
sPassword: "parus",
//Строка подключения к БД
connectString: "DEMOP_CITKSERV_WAN",
sConnectString: "DEMOP_CITKSERV_WAN",
//Наименование модуля (для сессии БД)
sessionModuleName: "PARUS$ExchangeServer",
sSessionModuleName: "PARUS$ExchangeServer",
//Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД)
connectorModule: "parus_oracle_db.js"
sConnectorModule: "parus_oracle_db.js"
};
//Параметры обработки очереди исходящих сообщений
let outgoing = {
//Размер блока одновременно обрабатываемых исходящих сообщений
portionSize: 1,
nPortionSize: 1,
//Скорость проверки наличия исходящих сообщений (мс)
checkTimeout: 500
nCheckTimeout: 500
};
//-----------------

View File

@ -17,9 +17,9 @@ const { ServerError } = require("@core/server_errors.js"); //Типовая ош
//----------
//Состояния записей журнала работы сервиса
const MSG_TYPE_INF = 0; //Информация
const MSG_TYPE_WRN = 1; //Предупреждение
const MSG_TYPE_ERR = 2; //Ошибка
const NLOG_STATE_INF = 0; //Информация
const NLOG_STATE_WRN = 1; //Предупреждение
const NLOG_STATE_ERR = 2; //Ошибка
//------------
// Тело модуля
@ -27,23 +27,23 @@ const MSG_TYPE_ERR = 2; //Ошибка
class DBConnector {
//Конструктор
constructor(dbConnect) {
constructor(prms) {
//Проверяем структуру переданного объекта для подключения
let checkResult = checkObject(dbConnect, {
let checkResult = checkObject(prms, {
fields: [
{ name: "user", required: true },
{ name: "password", required: true },
{ name: "connectString", required: true },
{ name: "sessionModuleName", required: true },
{ name: "connectorModule", required: false }
{ name: "sUser", required: true },
{ name: "sPassword", required: true },
{ name: "sConnectString", required: true },
{ name: "sSessionModuleName", required: true },
{ name: "sConnectorModule", required: false }
]
});
//Если структура объекта в норме
if (!checkResult) {
//Проверяем наличие модуля для работы с БД в настройках подключения
if (dbConnect.connectorModule) {
if (prms.sConnectorModule) {
//Подключим модуль
this.connector = require(makeModuleFullPath(dbConnect.connectorModule));
this.connector = require(makeModuleFullPath(prms.sConnectorModule));
//Проверим его интерфейс
if (
!checkModuleInterface(this.connector, {
@ -61,12 +61,12 @@ class DBConnector {
) {
throw new ServerError(
glConst.ERR_MODULES_BAD_INTERFACE,
"Модуль " + dbConnect.module + " реализует неверный интерфейс!"
"Модуль " + prms.sConnectorModule + " реализует неверный интерфейс!"
);
}
//Всё успешно - сохраним настройки подключения
this.connectSettings = {};
_.extend(this.connectSettings, dbConnect);
_.extend(this.connectSettings, prms);
//Инициализируем остальные свойства
this.connection = {};
} else {
@ -85,12 +85,12 @@ class DBConnector {
//Подключиться к БД
async connect() {
try {
this.connection = await this.connector.connect(
this.connectSettings.user,
this.connectSettings.password,
this.connectSettings.connectString,
this.connectSettings.sessionModuleName
);
this.connection = await this.connector.connect({
sUser: this.connectSettings.sUser,
sPassword: this.connectSettings.sPassword,
sConnectString: this.connectSettings.sConnectString,
sSessionModuleName: this.connectSettings.sSessionModuleName
});
return this.connection;
} catch (e) {
throw new ServerError(glConst.ERR_DB_CONNECT, e.message);
@ -99,7 +99,7 @@ class DBConnector {
//Отключиться от БД
async disconnect() {
try {
await this.connector.disconnect(this.connection);
await this.connector.disconnect({ connection: this.connection });
this.connection = {};
return;
} catch (e) {
@ -109,9 +109,12 @@ class DBConnector {
//Получить список сервисов
async getServices() {
try {
let srvs = await this.connector.getServices(this.connection);
let srvs = await this.connector.getServices({ connection: this.connection });
let srvsFuncs = srvs.map(async srv => {
const response = await this.connector.getServiceFunctions(this.connection, srv.NRN);
const response = await this.connector.getServiceFunctions({
connection: this.connection,
ddd: srv.NRN
});
let tmp = {};
_.extend(tmp, srv, { FN: [] });
response.map(f => {
@ -126,21 +129,61 @@ class DBConnector {
}
}
//Запись в журнал работы
async putLog(msgType, msg, queueID) {
try {
let res = await this.connector.log(this.connection, msgType, msg, queueID);
return res;
} catch (e) {
throw new ServerError(glConst.ERR_DB_EXECUTE, e.message);
async putLog(prms) {
//Проверяем структуру переданного объекта для подключения
let checkResult = checkObject(prms, {
fields: [
{ name: "nLogState", required: true },
{ name: "sMsg", required: false },
{ name: "nServiceId", required: false },
{ name: "nServiceFnId", required: false },
{ name: "nQueueId", required: false }
]
});
//Если структура объекта в норме
if (!checkResult) {
try {
let res = await this.connector.log({
connection: this.connection,
nLogState: prms.nLogState,
sMsg: prms.sMsg,
nServiceId: prms.nServiceId,
nServiceFnId: prms.nServiceFnId,
nQueueId: prms.nQueueId
});
return res;
} catch (e) {
throw new ServerError(glConst.ERR_DB_EXECUTE, e.message);
}
} else {
throw new ServerError(
glConst.ERR_OBJECT_BAD_INTERFACE,
"qqqОбъект имеет недопустимый интерфейс: " + checkResult
);
}
}
//Считать очередную порцию исходящих сообщений
async getOutgoing(portionSize) {
try {
let res = await this.connector.getQueueOutgoing(this.connection, portionSize);
return res;
} catch (e) {
throw new ServerError(glConst.ERR_DB_EXECUTE, e.message);
async getOutgoing(prms) {
//Проверяем структуру переданного объекта для подключения
let checkResult = checkObject(prms, {
fields: [{ name: "nPortionSize", required: true }]
});
//Если структура объекта в норме
if (!checkResult) {
try {
let res = await this.connector.getQueueOutgoing({
connection: this.connection,
nPortionSize: prms.nPortionSize
});
return res;
} catch (e) {
throw new ServerError(glConst.ERR_DB_EXECUTE, e.message);
}
} else {
throw new ServerError(
glConst.ERR_OBJECT_BAD_INTERFACE,
"Объект имеет недопустимый интерфейс: " + checkResult
);
}
}
}
@ -149,7 +192,7 @@ class DBConnector {
// Интерфейс модуля
//-----------------
exports.MSG_TYPE_INF = MSG_TYPE_INF;
exports.MSG_TYPE_WRN = MSG_TYPE_WRN;
exports.MSG_TYPE_ERR = MSG_TYPE_ERR;
exports.NLOG_STATE_INF = NLOG_STATE_INF;
exports.NLOG_STATE_WRN = NLOG_STATE_WRN;
exports.NLOG_STATE_ERR = NLOG_STATE_ERR;
exports.DBConnector = DBConnector;

View File

@ -73,13 +73,16 @@ const checkObject = (obj, interface) => {
let noValues = [];
//Обходим проверяемые поля
interface.fields.forEach(fld => {
//Проверим наличие поля в объекте
if (!(fld.name in obj)) {
//Проверим наличие поля в объекте (только для обязательных)
if (fld.required && !(fld.name in obj)) {
//Поля нет
noFields.push(fld.name);
} else {
//Поле есть, проверим наличие значения
if (fld.required && !obj[fld.name])
if (
fld.required &&
(obj[fld.name] === "undefined" || obj[fld.name] === null || obj[fld.name] === "")
)
//Обязательное поле не содержит значения
noValues.push(fld.name);
}

View File

@ -38,39 +38,45 @@ const SLOG_STATE_ERR = "ERR"; //Ошибка (строковый код)
//------------
//Подключение к БД
const connect = async (user, password, connectString, moduleName) => {
const connect = async prms => {
try {
const conn = await oracledb.getConnection({
user,
password,
connectString
});
conn.module = moduleName;
return conn;
if (prms && prms.sUser && prms.sPassword && prms.sConnectString) {
const conn = await oracledb.getConnection({
user: prms.sUser,
password: prms.sPassword,
connectString: prms.sConnectString
});
if (prms.sSessionModuleName) conn.module = prms.sSessionModuleName;
return conn;
} else {
throw new Error(
"Не указаны параметры подключения (отсутствует одно из полей: sUser, sPassword, sConnectString)"
);
}
} catch (e) {
throw new Error(e.message);
}
};
//Отключение от БД
const disconnect = async connection => {
if (connection) {
const disconnect = async prms => {
if (prms && prms.connection) {
try {
const conn = await connection.close();
const conn = await prms.connection.close();
return;
} catch (e) {
throw new Error(e.message);
}
} else {
throw new Error("Не указано подключение");
throw new Error("Не указано подключение (отсутствует поле: connection)");
}
};
//Получение списка сервисов
const getServices = async connection => {
const getServices = prms => {
return new Promise((resolve, reject) => {
if (connection) {
connection.execute(
if (prms && prms.connection) {
prms.connection.execute(
"BEGIN PKG_EXS.SERVICE_GET(RCSERVICES => :RCSERVICES); END;",
{ RCSERVICES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } },
{ outFormat: oracledb.OBJECT },
@ -94,115 +100,129 @@ const getServices = async connection => {
}
);
} else {
reject(new Error("Не указано подключение"));
reject(new Error("Не указано подключение (отсутствует поле: connection)"));
}
});
};
//Получение списка функций сервиса
const getServiceFunctions = (connection, serviceID) => {
const getServiceFunctions = prms => {
return new Promise((resolve, reject) => {
if (connection) {
connection.execute(
"BEGIN PKG_EXS.SERVICEFN_GET(NSERVICE => :NSERVICE, RCSERVICEFNS => :RCSERVICEFNS); END;",
{ NSERVICE: serviceID, RCSERVICEFNS: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } },
{ outFormat: oracledb.OBJECT },
(err, result) => {
if (err) {
reject(new Error(err.message));
} else {
let cursor = result.outBinds.RCSERVICEFNS;
let queryStream = cursor.toQueryStream();
let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
if (prms && prms.connection) {
if (prms.nServiceId) {
prms.connection.execute(
"BEGIN PKG_EXS.SERVICEFN_GET(NSERVICE => :NSERVICE, RCSERVICEFNS => :RCSERVICEFNS); END;",
{ NSERVICE: prms.nServiceId, RCSERVICEFNS: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } },
{ outFormat: oracledb.OBJECT },
(err, result) => {
if (err) {
reject(new Error(err.message));
});
queryStream.on("close", () => {
resolve(rows);
});
} else {
let cursor = result.outBinds.RCSERVICEFNS;
let queryStream = cursor.toQueryStream();
let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
reject(new Error(err.message));
});
queryStream.on("close", () => {
resolve(rows);
});
}
}
}
);
);
} else {
reject(new Error("Не указан идентификатор сервиса"));
}
} else {
reject(new Error("Не указано подключение"));
reject(new Error("Не указано подключение (отсутствует поле: connection)"));
}
});
};
//Запись в протокол работы
const log = (connection, logState, msg, queueID) => {
const log = prms => {
return new Promise((resolve, reject) => {
if (connection) {
connection.execute(
"BEGIN PKG_EXS.LOG_PUT(NLOG_STATE => :NLOG_STATE, SMSG => :SMSG, NEXSQUEUE => :NEXSQUEUE, RCLOG => :RCLOG); END;",
{
NLOG_STATE: logState,
SMSG: msg,
NEXSQUEUE: queueID,
RCLOG: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OBJECT, autoCommit: true },
(err, result) => {
if (err) {
reject(new Error(err.message));
} else {
let cursor = result.outBinds.RCLOG;
let queryStream = cursor.toQueryStream();
let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
if (prms && prms.connection) {
if (!(prms.nLogState === "undefined")) {
prms.connection.execute(
"BEGIN PKG_EXS.LOG_PUT(NLOG_STATE => :NLOG_STATE, SMSG => :SMSG, NEXSSERVICE => :NEXSSERVICE, NEXSSERVICEFN => :NEXSSERVICEFN, NEXSQUEUE => :NEXSQUEUE, RCLOG => :RCLOG); END;",
{
NLOG_STATE: prms.nLogState,
SMSG: prms.sMsg,
NEXSSERVICE: prms.nServiceId,
NEXSSERVICEFN: prms.nServiceFnId,
NEXSQUEUE: prms.nQueueId,
RCLOG: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OBJECT, autoCommit: true },
(err, result) => {
if (err) {
reject(new Error(err.message));
});
queryStream.on("close", () => {
resolve(rows[0]);
});
} else {
let cursor = result.outBinds.RCLOG;
let queryStream = cursor.toQueryStream();
let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
reject(new Error(err.message));
});
queryStream.on("close", () => {
resolve(rows[0]);
});
}
}
}
);
);
} else {
reject(new Error("Не указан тип сообщения журнала (отсутствует поле: nLogState)"));
}
} else {
reject(new Error("Не указано подключение"));
reject(new Error("Не указано подключение (отсутствует поле: connection)"));
}
});
};
//Считывание очередной порции исходящих сообщений из очереди
const getQueueOutgoing = (connection, portionSize) => {
const getQueueOutgoing = prms => {
return new Promise((resolve, reject) => {
if (connection) {
connection.execute(
"BEGIN PKG_EXS.QUEUE_NEXT_GET(NPORTION => :NPORTION, NSRV_TYPE => :NSRV_TYPE, RCQUEUES => :RCQUEUES); END;",
{
NPORTION: portionSize,
NSRV_TYPE: NSRV_TYPE_SEND,
RCQUEUES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OBJECT, autoCommit: true, fetchInfo: { BMSG: { type: oracledb.BUFFER } } },
(err, result) => {
if (err) {
reject(new Error(err.message));
} else {
let cursor = result.outBinds.RCQUEUES;
let queryStream = cursor.toQueryStream();
let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
if (prms && prms.connection) {
if (prms.nPortionSize) {
prms.connection.execute(
"BEGIN PKG_EXS.QUEUE_NEXT_GET(NPORTION_SIZE => :NPORTION_SIZE, NSRV_TYPE => :NSRV_TYPE, RCQUEUES => :RCQUEUES); END;",
{
NPORTION_SIZE: prms.nPortionSize,
NSRV_TYPE: NSRV_TYPE_SEND,
RCQUEUES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OBJECT, autoCommit: true, fetchInfo: { bMsg: { type: oracledb.BUFFER } } },
(err, result) => {
if (err) {
reject(new Error(err.message));
});
queryStream.on("close", () => {
resolve(rows);
});
} else {
let cursor = result.outBinds.RCQUEUES;
let queryStream = cursor.toQueryStream();
let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
reject(new Error(err.message));
});
queryStream.on("close", () => {
resolve(rows);
});
}
}
}
);
);
} else {
reject(new Error("Не указан размер извлекаемой порции сообщений (отсутствует поле: nPortionSize)"));
}
} else {
reject(new Error("Не указано подключение"));
reject(new Error("Не указано подключение (отсутствует поле: connection)"));
}
});
};

View File

@ -5,7 +5,7 @@
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
"test": "node test.js"
},
"repository": {
"type": "git",

View File

@ -23,7 +23,7 @@ try {
a.connect()
.then(res => {
console.log("CONNECTED");
a.getOutgoing(cfg.outgoing.portionSize)
a.getOutgoing({ nPortionSize: cfg.outgoing.nPortionSize })
.then(res => {
if (res.length > 0) {
res.map(r => {
@ -32,7 +32,7 @@ try {
} else {
console.log("NO MESSAGES IN QUEUE!!!");
}
a.putLog(db.MSG_TYPE_INF, "Сервер приложений подключен")
a.putLog({ nLogState: db.NLOG_STATE_INF, sMsg: "Сервер приложений подключен" })
.then(res => {
console.log(res);
setTimeout(() => {