Работа с БД из кода

Sequel для выполнения запросов

Настало время для работы с SQL прямо из Ruby кода. Для того, чтобы это было возможно, необходимо установить библиотеку sequel

gem 'sequel', '~> 5.69'

Также СУБД бывают различные и каждая из СУБД предоставляет свой собственный API для различных языков программирования. В Ruby для работы с SQLite необходим дополнительный гем

Теперь мы можем получить доступ до Sequel в нашем коде.

Для того, чтобы начать посылать запросы, нам нужно установить соединение с базой данных:

require 'sequel'

DB = Sequel.connect('sqlite://shop.db') # указываем путь до файла БД относительно .rb файла
# Также можно использовать именованные параметры на основе Hash. В данном случае необходимо обязательно укзаать значение для adapter
# DB = Sequel.connect(adapter: :sqlite, user: 'user', password: 'password', host: 'host', port: port, database: 'database_name.db')

DDL операции

Sequel предоставляет нам удобный DSL (domain-specific language) для выполнения DDL операций. Например, так будет выглядеть операция для создания таблицы items:

# В качестве аргумента передает название таблицы в виде символа, а также блок кода
DB.create_table :items do
  primary_key :id # внутри которого с помощью методов описываем нашу таблицу
  column :manufacture, String, null: false
  column :model, String, null: false 
  column :color, String, null: false
  column :price, Integer null: false,
  column :date_added, Time, null: false
end

В данном примере мы вызывали метод .column в который передавали:

  1. название колонки

  2. класс Ruby, который имеет сопоставление с типами SQL

  3. параметры, передаваемые в виде хэша

DML операции

После того как таблица создана, рассмотрим пример запроса для получения товаров стоимостью выше 10 000 рублей отсортированные по цене в порядке убиывания

table = DB[:items]

result = table
  .where{price > 10_000} # создаем блок кода с передачей условия в него
  .order(Sequel.desc(:price)) # вызываем метод для сортировки

p result # Получаем массив значений в виде хэша

Мы можем также добавлять значения в нашу таблицу:

table.insert(
  manUfacture: "apple", 
  model: "Iphone 14", 
  color: "Red", 
  price: 120_000,
  date_added: Time.now
) 

Точно также как и удалять:

table.where{id == 1}.delete

Sequel как ORM

Чаще всего встречается использование ORM для работы с базой данных. ORM - Object Relational Mapping. По сути, это работа с таблицами как с Ruby объектами, где каждый атрибут объекта - атрибут таблицы. Давайте создадим такой класс для нашей таблицы items.

require 'sequel'

# Sequel обязывает нас называть наши классы как таблицы в единственном числе
# Он использует название класса для определния названия таблицы
# если нам нужно изменить это поведение, 
# то необходимо наследоваться с использованием названия в качестве аргумента (Sequel::Model(:items))
class Item < Sequel::Model
end

Item.where{price > 10_000}.order(Sequel.desc(:price)) 

Важно при этом создать объект соединения с помощью Sequel.connect(...), так как при создании модели будет использоваться неявно(без использования переменной) ранее созданное соеднинение. Сначала создаем соединение, потом инициализируем модели с помощью require.

Ассоциации

Кроме того, в моделях нам доступны ассоциации. Ассоциации позволяют одной модели ссылаться на другие в случае, если между ними есть связь в виде FK.

Рассмотрим основные связи:

  • many_to_one - ассоциация описывает отношение "многие к одному" между двумя таблицами в базе данных. Это означает, что одна запись в "родительской" таблице может быть связана с множеством записей в "дочерней" таблице, но каждая запись "дочерней" таблицы имеет связь только с одной записью из "родительской" таблицы.

Пример использования ассоциации many_to_one для двух таблиц: students и classrooms. Здесь один класс (classroom) может иметь много студентов (students), но каждый студент может быть только в одном классе.

Структура двух таблиц:

students

idnameclassroom_id

1

Alice

1

2

Bob

1

classrooms

idname

1

Math Class

Объявление моделей с ассоциацией в Sequel:

class Student < Sequel::Model
  many_to_one :classroom
end

class Classroom < Sequel::Model
  one_to_many :students
end

Теперь вы можете получить класс (classroom) каждого студента с помощью ассоциации many_to_one:

student = Student.where(id: 1).first
classroom = student.classroom
puts classroom.name # Выводит: "Math Class"

В данном случае, ассоциация many_to_one позволила установить связь между таблицами таким образом, что для каждого объекта Student можно легко получить соответствующий объект Classroom, без необходимости писать дополнительные SQL-запросы.

  • one_to_many - ассоциация описывает отношение "многие ко многим" между двумя таблицами в базе данных. Это означает, что одна запись в первой таблице может быть связана с несколькими записями во второй таблице, и наоборот, одна запись во второй таблице может быть связана с несколькими записями в первой таблице.

Для реализации такого отношения обычно используется третья таблица, называемая "связующей" (join) таблицей, которая содержит внешние ключи (foreign keys) для обеих таблиц и связывает их записи.

Пример использования ассоциации many_to_many для таблиц students, courses, и связующей таблицы enrollments. Здесь один студент может быть записан на несколько курсов, и каждый курс может иметь несколько студентов.

Структура таблиц:

students

idname

1

Alice

courses

idname

1

Math

2

History

enrollments

student_idcourse_id

1

1

1

2

Объявление моделей с ассоциацией в Sequel:

class Student < Sequel::Model
  many_to_many :courses, join_table: :enrollments
end

class Course < Sequel::Model
  many_to_many :students, join_table: :enrollments
end

Теперь вы можете получить все курсы, на которые записан студент, или все студенты, которые записаны на курс, с помощью ассоциации many_to_many:

student = Student.where(id: 1).first
courses = student.courses
courses.each { |course| puts course.name } # Выводит: "Math", "History"

course = Course.where(id: 1).first
students = course.students
students.each { |student| puts student.name } # Выводит: "Alice"

Таким образом, ассоциация many_to_many позволяет установить связь многие ко многим между двумя таблицами с использованием связующей таблицы, и предоставляет удобный способ получения и работы с этими связями на уровне объектов Ruby и моделей Sequel.

Обратите внимание на следующие правила и рекомендации по составлению названий таблиц, классов и ассоциаций в контексте таблиц базы данных и объектно-реляционного отображения, такого как Sequel:

  1. Таблицы:

    • Обычно названия таблиц должны быть во множественном числе и в нижнем регистре (например, students, bo`oks).

    • Используйте подчеркивания для разделения слов в названиях таблиц (например, book_authors, order_items).

    • Старайтесь делать названия короткими и ясными, чтобы они отражали назначение таблицы.

  2. Классы и модели:

    • Имена классов и моделей должны быть в единственном числе и в формате CamelCase (например, Student, Book).

    • Каждое слово в имени класса должно начинаться с заглавной буквы и не содержать подчеркиваний (например, BookAuthor, OrderItem).

  3. Ассоциации:

    • Названия ассоциаций one_to_many и many_to_many должны быть во множественном числе и в нижнем регистре, чтобы они соответствовали названиям таблиц (например, students, books).

    • Названия ассоциации many_to_one должно быть в единственном числе и в нижнем регистре, чтобы оно соответствовали названию класса и модели в нижнем регистре (например, student, book).

В случае если названия классов или ассоциаций отличаются от названий таблиц или не выполняют какое-либо из выше перечисленных правил, то необходимо будет вручную проставлять нзавания классов/таблиц. В противном случае работать это не будет.

Задание university

Задание todo_api

Напишите используя Sinatra и Sequel приложение для работы со списком дел, которое:

  • Добавляет новое дело в базу данных

  • Изменяет дело по его идентификатору

  • Удаляет дело по его идентификатору

  • Показывает список дел постранично

Рекомендации:

  • Требований как должна выглядеть модель дела здесь нет, поэтому можете включить свою фантазию и придумать

  • Для того, чтобы модель Sequel могла бы быть преобразована в JSON, вам необходимо включить JSON сериализацию

Last updated