Особенности совместной работы ruby и oracle
TRANSCRIPT
Особенности совместной работы Ruby и Oracle
Никита Шильников, Латера
Биллинг?
2
Oracle?
3
Условия
• Нет доступа к таблицам
• Все выборки делаются из
представлений БД
• Изменение данных происходит
через вызов хранимых процедур
4
Преимущества
• Отдельный слой API
• Безопасность. SQL-инъекции? Не слышал
• Близость к данным
• Скорость
• Повторное использование кода
5
Где это нужно?
Приложение Ok?
Интернет-магазин ✗
Социальная сеть ✗
Процессинг банка ✓
Биллинг ✓
6
• 160 таблиц
• 340 представлений
• 2000 хранимых процедур и
функций
• 250 моделей
• 120 контроллеров
7
Схема
8
Схема
9
Представления
10
PL/SQL
declarel_hello varchar2(500);
beginl_hello := 'Hello World!';dbms_output.put_line(l_hello);
end;
Переменные
Код
Анонимный блок
11
Хранимые процедуры
create procedure print_message(p_msg in varchar2)
asbegindbms_output.put_line(p_msg);
end;
Заголовок
Тело
12
Пакеты
create package hello_pkg asfunction salute(p_name in varchar2)return varchar2;
end hello_pkg;
create package body hello_pkg asfunction salute(p_name in varchar2)return varchar2asbeginreturn 'Hello, ' || p_name;
end;end hello_pkg;
Заголовок
Тело
13
PL/SQL
create procedure send_messages(p_group_id in users.group_id%type,p_msg in varchar2)
asbeginfor l_user in (select user_idfrom userswhere group_id = p_group_id)
loopsend_message(
p_user_id => l_user.user_id,p_msg => p_msg);
end loop;end;
SQL
PL
14
Динамический код
create procedure truncate_table(p_table_name in all_tables.table_name%type)
asbeginexecute immediate -- Выполняем любой код'truncate table ' || p_table_name;
end;
15
Вызов процедур
connection = ActiveRecord::Base.connection.raw_connectioncursor = connection.parse(<<-PLSQL) # Разборbeginmighty_package.destroy_the_earth;
end;PLSQLcursor.exec # Вызовcursor.close # Закрытие курсора
16
ruby-plsql
plsql.star_wars_pkg.start_episode(p_episode_no: 1,p_show_subtitles: ‘N’)
Kernel#plsql
Пакет star_wars_pkg
Вызов процедуры star_wars_pkg.start_episode
Аргументы процедуры
beginstar_wars_pkg.start_episode(p_episode_no => :p_episode_no, p_show_subtitles => :p_show_subtitles);
end;
17
ActiveRecord + ruby-plsql
class User < ActiveRecord::Baseset_create_method doplsql.users_pkg.add_user(p_name: name, p_band: band)
endendUser.create(name: 'Robert Plant', band: 'Led Zeppelin')
beginusers_pkg.add_user(p_name => :p_name, p_band => :p_band);
end;
18
AR + ruby-plsql + rails-plsql
class User < ActiveRecord::Baseprocedure_method :change_name, plsql.users_pkg['rename']
endUser.first.change_name(p_name: 'Nils Bohr')
beginusers_pkg.rename(p_user_id => :p_user_id,p_name => :p_name);
end;
Берется из атрибутов объекта
19
Последний штрих
module CustomSaveMethodsextend ActiveSupport::Concernincluded doset_create_method { put.values.first}set_update_method { put; reload_attributes }set_delete_method { del }
endend
20
Было
class Dragon < BaseModelheader doself.table_name = 'drgn_view'
endend
class Dragon < ActiveRecord::Baseself.table_name = 'drgn_view'self.primary_key = dragon_iddef create
_run_create_callbacks docursor = connection.parse(<<-PLSQL)
begindrgn_pkg.put_drgn(p_dragon_id => :p_dragon_id,p_name => :p_name,p_type => :p_type,p_birth_date => :p_birth_date,p_location => :p_location);
end;PLSQLcursor.bind(':p_gragon', nil, Number)cursor.bind(':p_name', name)cursor.bind(':p_type', type)cursor.bind(':p_birth_date',
birth_date, Date)cursor.bind(':p_location', location)cursor.execcursor.close...
Стало
21
22
Организация кода
23
Организация кода
ActiveRecord::Base
BaseModel
Accounts::Base Documents::Base
Accounts::Current Documents::Contract
24
Организация кода
25
Обработка исключений
UNIQUE_CONSTRAINT_VIOLATED = 1
beginplsql.users.insert(user_id: 1)plsql.users.insert(user_id: 1)
rescue OCIError => eif e.code == UNIQUE_CONSTRAINT_VIOLATEDputs 'Got it!’
elseraise
endend
26
Обработка исключений
class OCINamedError < OCIErrorclass_attribute :oci_error_code, instance_writer: false
def self.===(error)OCIError === error && error.code.in?([*oci_error_code])
endend
27
Обработка исключений
class UniqueConstraintViolated < OCINamedErrorself.oci_error_code = 1
end
beginplsql.users.insert(user_id: 1)plsql.users.insert(user_id: 1)
rescue UniqueConstraintViolated => eputs 'Got it!'
end
28
Обработка исключений
29
• 6 лет
• RoR 1 -> 2.3 -> 3.2
• MRI 1.8.7 -> 1.9.3
Заключение
30
Заключение
31
Никита Шильников, Латера
• github.com/flash-gordon
• latera.ru
32