https://github.com/yakovenkodenis/node-oracledb-tutorial
Пример подключения и использования Oracle Database 11g XE в node.js
https://github.com/yakovenkodenis/node-oracledb-tutorial
database-adapter node node-oracledb nodejs oracle-11g oracle-db tutorial
Last synced: 4 months ago
JSON representation
Пример подключения и использования Oracle Database 11g XE в node.js
- Host: GitHub
- URL: https://github.com/yakovenkodenis/node-oracledb-tutorial
- Owner: yakovenkodenis
- License: mit
- Created: 2016-12-24T15:11:28.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2017-01-03T19:02:51.000Z (about 9 years ago)
- Last Synced: 2025-06-30T17:48:01.044Z (7 months ago)
- Topics: database-adapter, node, node-oracledb, nodejs, oracle-11g, oracle-db, tutorial
- Size: 62.5 KB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Инструкция по работе с Oracle Database XE в среде node.js
------------------
## Требования к программному обеспечению
1. node.js v7+
2. npm v3+
3. Oracle Database 11g XE
Данный гайд ориентирован на работу в среде Unix (в частности, ОС Ubuntu).
### Устанавливаем node и npm
```bash
sudo apt-get update
sudo apt-get install nodejs
sudo apt-get install npm
```
### Проверка корректности установки node и npm
Команды, приведённые ниже, должны вывести версии установленных пакетов.
```
node -v
npm -v
```
### Инициализация проекта
Здесь `$PROJECT_ROOT` - адрес корневой директории для проекта.
```bash
cd $PROJECT_ROOT
npm init --yes
```
Ниже приведёт пример инициализации проекта в домашней директории ОС Unix:
```bash
cd ~
mkdir my_project && cd $_
npm init --yes
touch index.js
```
Для простоты будем считать, что весь javascript-код, приведённый ниже, находится в файле `index.js`.
Для запуска приложения будет использоваться следующая команда:
```
node --harmony index.js
```
### Устанавливаем драйвер базы данных (версия 1.11.0)
```bash
npm install --save oracledb@1.11.0
```
-----------------
## Подключение к Oracle DB
### Функция подключения к базе данных и выполнения запроса (Promise-based):
```javascript
const oracledb = require('oracledb');
const executePLSQL = (statement, params=[]) =>
new Promise((resolve, reject) => {
oracledb.getConnection(
{
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
connectString: process.env.DB_CONNECTION_STRING
}
).then(connection => {
return connection.execute(
statement, params
).then(result => {
resolve(result);
return connection.release();
}).catch(err => {
reject(err);
return connection.release();
})
}).catch(err => reject(err));
});
```
Использование промисов позволит в дальнейшем использовать синтаксис `async/await` для выполнения запросов. Однако, [официальный драйвер](https://github.com/oracle/node-oracledb) предоставляет не только Promise-based интерфейс, но и callback-based.
Описанная выше функция принимает параметры `statement` и `params`. Параметр `statement` - PL/SQL-запрос, а `params` - параметры, которые необходимо передать в запрос (об этом ниже).
Метод `getConnection` на объекте `oracledb` принимает в качестве параметра объект с конфигурациями подключения (имя пользователя, пароль и адрес для подключения к базе данных). Сами параметры лучше хранить в переменных среды (например, использовать пакет [dotenv](https://github.com/motdotla/dotenv)) и потом получать доступ к ним через `process.env.$PARAM_NAME`, как показано в коде выше.
Пример параметра `connectString` для Oracle DB XE, установленной локально со всеми параметрами по умолчанию: `localhost/XE`.
Вызов `oracledb.getConnection` вернёт промис, в который будет передан объект `connection`. Объект `connection` позволяет выполнять запросы непосредственно к базе данных (метод `connection.execute`). После выполнения необходимых операций с базой данных, соединение `connection` нужно освобождать, используя метод `connection.release()`.
### Примеры выполнения запросов
Допустим, мы хотим выполнить вызов хранимой процедуры, которая в базе данных была объявлена следующим образом:
```sql
procedure buy_book(user_id users.id%type, book_id books.id%type, books_count books.available_count%type) is
currently_available_books books.available_count%type;
not_enough_books_in_store exception;
negative_or_zero_count exception;
begin
select available_count into currently_available_books from books where id = book_id;
if currently_available_books - books_count < 0 then
raise not_enough_books_in_store;
elsif books_count <= 0 then
raise negative_or_zero_count;
end if;
insert into sales values (sales_seq.nextval, sysdate, user_id, book_id, books_count);
exception
when not_enough_books_in_store then
raise_application_error(-20001, 'Not enough books in store');
when negative_or_zero_count then
raise_application_error(-20002, 'You cannot buy 0 or less books');
end buy_book;
```
Для этого напишем простую функцию, которая будет принимать параметры, необходимые для вызова процедуры (`user_id`, `book_id`, `books_count`), а возвращать будет массив, состоящий из двух элементов: первый элемент - строка с запросом, второй элемент - массив параметров. Тут мы используем массив, потому что далее будет удобно пользоватья spread-оператором при вызове `executePLSQL`.
```javascript
const buyBook = (userId, bookId, booksCount) => [
'begin buy_book(:user_id, :book_id, :books_count); end;',
[userId, bookId, booksCount]
];
```
Имена параметров в строке запроса не имеют значения, важен только их порядок, который должен совпадать с порядком значений в массиве параметров.
Использовать нашу функцию можно будет следующим образом:
Внутри фукцнии, объявленной как `async`:
```javascript
const f = async() => {
const plsqlResult = await executePLSQL(...buyBook(1, 1, 15));
console.log(plsqlResult);
}
```
Используя `.then` на объекте промиса, возвращаемого функцией `executePLSQL`:
```javascript
executePLSQL(...buyBook(1, 1, 15))
.then(data => console.log(data))
.catch(err => console.log(err));
```
Ниже представлен пример выполнения хранимой в бд функции, которая возвращает значение.
Пример кода функции в бд:
```sql
function get_books_csv_by_publisher(publisher_id in publishers.id%type) return varchar2 as
result varchar2(2000);
book_name books.name%type;
cursor books_cur is select books.name from books where books.publisher_id = publisher_id;
begin
result := '';
open books_cur;
loop
fetch books_cur into book_name;
exit when books_cur%notfound;
result := result || book_name || ',';
end loop;
close books_cur;
return result;
end get_books_csv_by_publisher;
```
В случае, когда нам нужно получить значение, возвращаемое хранимой в бд функцией, `connection.execute` вторым параметром будет принимать объект специального вида, а не массив, как раньше. Объект должен будет содержать поля, обозначающие тип возвращаемого значения, его размер и направление (н-р, BIND_OUT).
Для этого напишем вспомогательную функцию, которая будет принимать массив наших параметров для запроса и тип возвращаемого значения, а возвращать будет объект нужного вида. `zipObject` - функция из пакета [lodash](https://github.com/lodash/lodash).
```javascript
const zipObject = require('lodash/zipObject');
const zipParams = (params, type) =>
Object.assign({}, zipObject([...Array(params.length).keys()], params), {
result: { dir: oracledb.BIND_OUT, type, maxSize: 2000 }
});
```
Теперь напишем вспомогательную функцию `getBooksCSVbyPublisher` по типу ранее описанной `buyBook`:
```javascript
const getBooksCSVbyPublisher = (id) => [
`begin :result := get_books_csv_by_publisher(:0); end;`,
zipParams([id], oracledb.STRING)
];
```
Примеры использования представлены ниже.
Внутри `async` функции:
```javascript
const f = async() => {
try {
const dbResponse = await executePLSQL(...getBooksCSVbyPublisher(1));
const jsonResponse = JSON.stringify(dbResponse.outBinds.result.slice(0, -1));
console.log(jsonResponse);
} catch (e) {
console.log(e);
}
}
```
Второй вариант:
```javascript
executePLSQL(...getBooksCSVbyPublisher(1))
.then(dbResponse => {
const jsonResponse = JSON.stringify(dbResponse.outBinds.result.slice(0, -1));
console.log(jsonResponse);
})
.catch(err => console.log(err));
```
-------------------------
Выше были описаны базовые примеры использования драйвера [node-oracledb](https://github.com/oracle/node-oracledb). Для более продвинутых вариантов использования стоит обращаться к [официальной документации](https://github.com/oracle/node-oracledb/blob/master/doc/api.md).