starproxima_library 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +69 -0
- data/diagrams/add_uthor_seq.png +0 -0
- data/diagrams/add_uthor_seq.puml +42 -0
- data/diagrams/author.png +0 -0
- data/diagrams/author.puml +118 -0
- data/diagrams/core.png +0 -0
- data/diagrams/core.puml +103 -0
- data/diagrams/delete_author.png +0 -0
- data/diagrams/delete_author.puml +25 -0
- data/diagrams/edit_author.png +0 -0
- data/diagrams/edit_author.puml +48 -0
- data/diagrams/er.png +0 -0
- data/diagrams/er.puml +30 -0
- data/diagrams/publisher.png +0 -0
- data/diagrams/publisher.puml +118 -0
- data/diagrams/requirements.docx +0 -0
- data/diagrams/start.png +0 -0
- data/diagrams/start.puml +74 -0
- data/lib/author/author_db_data_source.rb +90 -0
- data/lib/author/controllers/author_controller.rb +57 -0
- data/lib/author/controllers/author_input_form_controller_create.rb +44 -0
- data/lib/author/controllers/author_input_form_controller_edit.rb +53 -0
- data/lib/author/controllers/author_list_controller.rb +107 -0
- data/lib/author/ui/author_input_form.rb +69 -0
- data/lib/author/ui/author_list_view.rb +170 -0
- data/lib/controllers/tab_students_controller.rb +43 -0
- data/lib/data_sources/book_db_data_source.rb +43 -0
- data/lib/data_sources/db_client.rb +34 -0
- data/lib/db_config/config.yaml +5 -0
- data/lib/db_config/library_config.yaml +5 -0
- data/lib/db_config/migrations/create_db.sql +3 -0
- data/lib/db_config/migrations/create_tables.sql +27 -0
- data/lib/db_config/mock_data/mock_data.sql +49 -0
- data/lib/logger.rb +27 -0
- data/lib/main.rb +6 -0
- data/lib/models/author.rb +32 -0
- data/lib/models/book.rb +31 -0
- data/lib/models/publisher.rb +37 -0
- data/lib/models/student.rb +102 -0
- data/lib/models/student_base.rb +100 -0
- data/lib/models/student_short.rb +50 -0
- data/lib/publisher/controllers/publisher_input_form_controller_create.rb +44 -0
- data/lib/publisher/controllers/publisher_input_form_controller_edit.rb +52 -0
- data/lib/publisher/controllers/publisher_list_controller.rb +99 -0
- data/lib/publisher/publisher_db_data_source.rb +63 -0
- data/lib/publisher/ui/publisher_input_form.rb +69 -0
- data/lib/publisher/ui/publisher_list_view.rb +168 -0
- data/lib/repositories/adapters/db_source_adapter.rb +54 -0
- data/lib/repositories/adapters/file_source_adapter.rb +37 -0
- data/lib/repositories/containers/data_list.rb +74 -0
- data/lib/repositories/containers/data_list_student_short.rb +18 -0
- data/lib/repositories/containers/data_table.rb +35 -0
- data/lib/repositories/data_sources/db_data_source.rb +32 -0
- data/lib/repositories/data_sources/file_data_source.rb +75 -0
- data/lib/repositories/data_sources/transformers/data_transformer_base.rb +15 -0
- data/lib/repositories/data_sources/transformers/data_transformer_json.rb +16 -0
- data/lib/repositories/data_sources/transformers/data_transformer_yaml.rb +16 -0
- data/lib/repositories/student_repository.rb +32 -0
- data/lib/state_holders/list_state_notifier.rb +60 -0
- data/lib/views/main_window.rb +32 -0
- data/lib/views/tab_students.rb +148 -0
- data/starproxima_library.gemspec +15 -0
- data/test/author_test.rb +51 -0
- data/test/book_test.rb +33 -0
- data/test/publisher_test.rb +39 -0
- data/test/state_notifier_test.rb +80 -0
- metadata +123 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'mysql2'
|
2
|
+
require_relative '../data_sources/db_client'
|
3
|
+
|
4
|
+
class AuthorDBDataSource
|
5
|
+
def initialize
|
6
|
+
@client = DBClient.instance
|
7
|
+
end
|
8
|
+
|
9
|
+
# def add(author)
|
10
|
+
# query = "INSERT INTO Author (FirstName, LastName, FatherName) VALUES ('#{author.first_name}', '#{author.last_name}', #{author.father_name.nil? ? 'NULL' : "'#{author.father_name}'"})"
|
11
|
+
# @client.query(query)
|
12
|
+
# end
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
# добавляет нового автора в базу данных, возвращает созданную запись.
|
17
|
+
def add(author)
|
18
|
+
query = "INSERT INTO Author (FirstName, LastName, FatherName) VALUES ('#{author.first_name}', '#{author.last_name}', #{author.father_name.nil? ? 'NULL' : "'#{author.father_name}'"})"
|
19
|
+
@client.query(query)
|
20
|
+
author_id = @client.last_id
|
21
|
+
get(author_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
# изменяет данные об авторе в базе данных, возвращает измененную запись.
|
25
|
+
def change(author)
|
26
|
+
query = "UPDATE Author SET FirstName='#{author.first_name}', LastName='#{author.last_name}', FatherName=#{author.father_name.nil? ? 'NULL' : "'#{author.father_name}'"} WHERE AuthorID=#{author.author_id}"
|
27
|
+
@client.query(query)
|
28
|
+
get(author.author_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
# удаляет запись об авторе из базы данных.
|
32
|
+
def delete(id)
|
33
|
+
query = "DELETE FROM Author WHERE AuthorID=#{id}"
|
34
|
+
@client.query(query)
|
35
|
+
end
|
36
|
+
|
37
|
+
# возвращает запись об авторе по заданному id.
|
38
|
+
def get(id)
|
39
|
+
query = "SELECT * FROM Author WHERE AuthorID=#{id}"
|
40
|
+
result = @client.query(query).first
|
41
|
+
if result
|
42
|
+
Author.new(result[:'AuthorID'], result[:'FirstName'], result[:'LastName'], result[:'FatherName'])
|
43
|
+
else
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# def get_list(page_size, page_num, sort_field, sort_direction)
|
49
|
+
# offset = (page_num - 1) * page_size
|
50
|
+
# query = "SELECT * FROM Author ORDER BY #{sort_field} #{sort_direction} LIMIT #{page_size} OFFSET #{offset}"
|
51
|
+
# results = @client.query(query)
|
52
|
+
#
|
53
|
+
# authors = []
|
54
|
+
# results.each do |result|
|
55
|
+
# authors << Author.new(result[:'AuthorID'], result[:'FirstName'], result[:'LastName'], result[:'FatherName'])
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# authors
|
59
|
+
# end
|
60
|
+
|
61
|
+
# возвращает список авторов с учетом фильтра по наличию отчества и сортировки, позволяет задавать количество элементов на странице и номер страницы.
|
62
|
+
def get_list(page_size, page_num, sort_field, sort_direction, has_father_name = nil)
|
63
|
+
offset = (page_num - 1) * page_size
|
64
|
+
query = "SELECT * FROM Author"
|
65
|
+
|
66
|
+
if has_father_name == true
|
67
|
+
query += " WHERE FatherName IS NOT NULL"
|
68
|
+
elsif has_father_name == false
|
69
|
+
query += " WHERE FatherName IS NULL"
|
70
|
+
end
|
71
|
+
|
72
|
+
query += " ORDER BY #{sort_field} #{sort_direction} LIMIT #{page_size} OFFSET #{offset}"
|
73
|
+
results = @client.query(query)
|
74
|
+
|
75
|
+
authors = []
|
76
|
+
results.each do |result|
|
77
|
+
authors << Author.new(result[:'AuthorID'], result[:'FirstName'], result[:'LastName'], result[:'FatherName'])
|
78
|
+
end
|
79
|
+
|
80
|
+
authors
|
81
|
+
end
|
82
|
+
|
83
|
+
# возвращает количество записей об авторах в базе данных.
|
84
|
+
def count
|
85
|
+
query = "SELECT COUNT(*) FROM Author"
|
86
|
+
result = @client.query(query).first
|
87
|
+
|
88
|
+
result[:'COUNT(*)']
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# # frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# require './lib/views/main_window'
|
4
|
+
# require './lib/repositories/student_repository'
|
5
|
+
# require './lib/repositories/adapters/db_source_adapter'
|
6
|
+
# require './lib/repositories/containers/data_list_student_short'
|
7
|
+
# require './lib/state_holders/list_state_notifier'
|
8
|
+
# require_relative '../author_db_data_source'
|
9
|
+
# require 'win32api'
|
10
|
+
#
|
11
|
+
# class AuthorController
|
12
|
+
#
|
13
|
+
#
|
14
|
+
# def initialize(view)
|
15
|
+
# @view = view
|
16
|
+
# @state_notifier = ListStateNotifier.new
|
17
|
+
# @state_notifier.add_listener(@view)
|
18
|
+
# @author_rep = AuthorDBDataSource.new
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# def edit (number)
|
22
|
+
# author = @state_notifier.get(number)
|
23
|
+
# puts author.id
|
24
|
+
# # @view.show_edit_dialog(author)
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# def add (number)
|
28
|
+
# author = @state_notifier.get(number)
|
29
|
+
# puts author
|
30
|
+
# # @view.show_add_dialog(author)
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
#
|
34
|
+
# def remove (number)
|
35
|
+
# author = @state_notifier.get(number)
|
36
|
+
# puts author
|
37
|
+
# # @view.show_remove_dialog(author)
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# def refresh_data(page, per_page)
|
41
|
+
# items = @author_rep.get_list(per_page, page, 'FirstName', 'ASC' )
|
42
|
+
# @state_notifier.set_all(items)
|
43
|
+
# @view.update_student_count(@author_rep.count)
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# def refresh()
|
47
|
+
# items = @author_rep.get_list(per_page, page, 'FirstName', 'ASC' )
|
48
|
+
# @state_notifier.set_all(items)
|
49
|
+
# @view.update_student_count(@author_rep.count)
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# def on_db_conn_error
|
53
|
+
# api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
54
|
+
# api.call(0, "No connection to DB", "Error", 0)
|
55
|
+
# exit(false)
|
56
|
+
# end
|
57
|
+
# end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'win32api'
|
4
|
+
|
5
|
+
class AuthorInputFormControllerCreate
|
6
|
+
def initialize(parent_controller)
|
7
|
+
@parent_controller = parent_controller
|
8
|
+
@author_rep = AuthorDBDataSource.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def set_view(view)
|
12
|
+
@view = view
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_view_created
|
16
|
+
# begin
|
17
|
+
# @student_rep = StudentRepository.new(DBSourceAdapter.new)
|
18
|
+
# rescue Mysql2::Error::ConnectionError
|
19
|
+
# on_db_conn_error
|
20
|
+
# end
|
21
|
+
end
|
22
|
+
|
23
|
+
def process_fields(fields)
|
24
|
+
begin
|
25
|
+
puts fields
|
26
|
+
item = Author.new(-1, *fields.values)
|
27
|
+
puts item
|
28
|
+
item = @author_rep.add(item)
|
29
|
+
@parent_controller.state_notifier.add(item)
|
30
|
+
@view.close
|
31
|
+
rescue ArgumentError => e
|
32
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
33
|
+
api.call(0, e.message, 'Error', 0)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def on_db_conn_error
|
40
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
41
|
+
api.call(0, "No connection to DB", "Error", 0)
|
42
|
+
@view.close
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'win32api'
|
4
|
+
|
5
|
+
class AuthorInputFormControllerEdit
|
6
|
+
def initialize(parent_controller, item)
|
7
|
+
@parent_controller = parent_controller
|
8
|
+
@item = item
|
9
|
+
@author_rep = AuthorDBDataSource.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_view(view)
|
13
|
+
@view = view
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_view_created
|
17
|
+
# begin
|
18
|
+
# @student_rep = StudentRepository.new(DBSourceAdapter.new)
|
19
|
+
# rescue Mysql2::Error::ConnectionError
|
20
|
+
# on_db_conn_error
|
21
|
+
# end
|
22
|
+
|
23
|
+
# @item = @author_rep.get(@item_id)
|
24
|
+
# @view.make_readonly(:git, :telegram, :email, :phone)
|
25
|
+
populate_fields(@item)
|
26
|
+
end
|
27
|
+
|
28
|
+
def populate_fields(item)
|
29
|
+
@view.set_value(:first_name, item.first_name)
|
30
|
+
@view.set_value(:last_name, item.last_name)
|
31
|
+
@view.set_value(:father_name, item.father_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_fields(fields)
|
35
|
+
begin
|
36
|
+
item = Author.new(@item.author_id, *fields.values)
|
37
|
+
item = @author_rep.change(item)
|
38
|
+
@parent_controller.state_notifier.replace(@item, item)
|
39
|
+
@view.close
|
40
|
+
rescue ArgumentError => e
|
41
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
42
|
+
api.call(0, e.message, 'Error', 0)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def on_db_conn_error
|
49
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
50
|
+
api.call(0, "No connection to DB", "Error", 0)
|
51
|
+
@view.close
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require './lib/state_holders/list_state_notifier'
|
4
|
+
require_relative '../ui/author_input_form'
|
5
|
+
require_relative 'author_input_form_controller_create'
|
6
|
+
require_relative 'author_input_form_controller_edit'
|
7
|
+
require_relative '../author_db_data_source'
|
8
|
+
require 'win32api'
|
9
|
+
|
10
|
+
# Класс AuthorListController отвечает за управление списком
|
11
|
+
# авторов, используя различные методы для обновления данных и
|
12
|
+
# взаимодействия с пользовательским интерфейсом.
|
13
|
+
class AuthorListController
|
14
|
+
|
15
|
+
attr_reader :state_notifier;
|
16
|
+
|
17
|
+
def initialize(view)
|
18
|
+
LoggerHolder.instance.debug('AuthorListController: initialize')
|
19
|
+
@view = view
|
20
|
+
@state_notifier = ListStateNotifier.new
|
21
|
+
@state_notifier.add_listener(@view)
|
22
|
+
@author_rep = AuthorDBDataSource.new
|
23
|
+
|
24
|
+
@sort_columns = %w[AuthorID FirstName LastName FatherName]
|
25
|
+
@sort_by = @sort_columns.first
|
26
|
+
|
27
|
+
@father_name_filter_columns = [nil, true, false]
|
28
|
+
@father_name_filter = @father_name_filter_columns.first
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_view_created
|
32
|
+
# begin
|
33
|
+
# @student_rep = StudentRepository.new(DBSourceAdapter.new)
|
34
|
+
# rescue Mysql2::Error::ConnectionError
|
35
|
+
# on_db_conn_error
|
36
|
+
# end
|
37
|
+
end
|
38
|
+
|
39
|
+
def show_view
|
40
|
+
@view.create.show
|
41
|
+
end
|
42
|
+
|
43
|
+
def show_modal_add
|
44
|
+
LoggerHolder.instance.debug('AuthorListController: show_modal_add')
|
45
|
+
controller = AuthorInputFormControllerCreate.new(self)
|
46
|
+
view = AuthorInputForm.new(controller)
|
47
|
+
controller.set_view(view)
|
48
|
+
view.create.show
|
49
|
+
end
|
50
|
+
|
51
|
+
# метод, который создает контроллер AuthorInputFormControllerEdit, представление AuthorInputForm, устанавливает связи между ними и показывает модальное окно.
|
52
|
+
def show_modal_edit(current_page, per_page, selected_row)
|
53
|
+
LoggerHolder.instance.debug('AuthorListController: show_modal_edit')
|
54
|
+
# item_num = (current_page - 1) * per_page + selected_row
|
55
|
+
|
56
|
+
item = @state_notifier.get(selected_row)
|
57
|
+
|
58
|
+
controller = AuthorInputFormControllerEdit.new(self, item)
|
59
|
+
view = AuthorInputForm.new(controller)
|
60
|
+
controller.set_view(view)
|
61
|
+
view.create.show
|
62
|
+
end
|
63
|
+
|
64
|
+
# метод, который получает выбранный элемент из state_notifier, удаляет его из базы данных и из state_notifier
|
65
|
+
def delete_selected(current_page, per_page, selected_row)
|
66
|
+
LoggerHolder.instance.debug('AuthorListController: delete_selected')
|
67
|
+
begin
|
68
|
+
item = @state_notifier.get(selected_row)
|
69
|
+
@author_rep.delete(item.author_id)
|
70
|
+
@state_notifier.delete(item)
|
71
|
+
rescue
|
72
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
73
|
+
api.call(0, "You cannot delete the author because he is associated with some book", "Error", 0)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# етод, который получает список авторов из базы данных, устанавливает их в state_notifier и обновляет пользовательский интерфейс
|
78
|
+
def refresh_data(page, per_page)
|
79
|
+
# begin
|
80
|
+
# @data_list = @student_rep.paginated_short_students(page, per_page, @data_list)
|
81
|
+
# @view.update_student_count(@student_rep.student_count)
|
82
|
+
# rescue
|
83
|
+
# on_db_conn_error
|
84
|
+
# end
|
85
|
+
items = @author_rep.get_list(per_page, page, @sort_by, 'ASC', @father_name_filter)
|
86
|
+
@state_notifier.set_all(items)
|
87
|
+
@view.update_student_count(@author_rep.count)
|
88
|
+
end
|
89
|
+
|
90
|
+
def sort(page, per_page, sort_index)
|
91
|
+
@sort_by = @sort_columns[sort_index]
|
92
|
+
refresh_data(page, per_page)
|
93
|
+
end
|
94
|
+
|
95
|
+
def filter_father_name(page, per_page, filter_index)
|
96
|
+
@father_name_filter = @father_name_filter_columns[filter_index]
|
97
|
+
refresh_data(page, per_page)
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def on_db_conn_error
|
103
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
104
|
+
api.call(0, "No connection to DB", "Error", 0)
|
105
|
+
exit(false)
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'glimmer-dsl-libui'
|
4
|
+
require_relative '../controllers/author_input_form_controller_create'
|
5
|
+
require './lib/models/author'
|
6
|
+
require 'win32api'
|
7
|
+
|
8
|
+
class AuthorInputForm
|
9
|
+
include Glimmer
|
10
|
+
|
11
|
+
def initialize(controller, existing_student = nil)
|
12
|
+
@item = existing_student.to_hash unless existing_student.nil?
|
13
|
+
@controller = controller
|
14
|
+
@entries = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_create
|
18
|
+
@controller.on_view_created
|
19
|
+
end
|
20
|
+
|
21
|
+
def create
|
22
|
+
@root_container = window('Автор', 300, 70) {
|
23
|
+
resizable false
|
24
|
+
|
25
|
+
vertical_box {
|
26
|
+
@student_form = form {
|
27
|
+
stretchy false
|
28
|
+
|
29
|
+
fields = [[:first_name, 'Имя автора'], [:last_name, 'Фамилия автора'], [:father_name, 'Отчество автора']]
|
30
|
+
|
31
|
+
fields.each do |field|
|
32
|
+
@entries[field[0]] = entry {
|
33
|
+
label field[1]
|
34
|
+
}
|
35
|
+
end
|
36
|
+
}
|
37
|
+
|
38
|
+
button('Сохранить') {
|
39
|
+
stretchy false
|
40
|
+
|
41
|
+
on_clicked {
|
42
|
+
values = @entries.transform_values { |v| v.text.force_encoding("utf-8").strip }
|
43
|
+
values.transform_values! { |v| v.empty? ? nil : v}
|
44
|
+
|
45
|
+
@controller.process_fields(values)
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
on_create
|
51
|
+
@root_container
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_value(field, value)
|
55
|
+
return unless @entries.include?(field)
|
56
|
+
|
57
|
+
@entries[field].text = value
|
58
|
+
end
|
59
|
+
|
60
|
+
def make_readonly(*fields)
|
61
|
+
fields.each do |field|
|
62
|
+
@entries[field].read_only = true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def close
|
67
|
+
@root_container.destroy
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'glimmer-dsl-libui'
|
4
|
+
require_relative '../controllers/author_list_controller'
|
5
|
+
require_relative '../controllers/author_controller'
|
6
|
+
require_relative 'author_input_form'
|
7
|
+
|
8
|
+
class AuthorListView
|
9
|
+
include Glimmer
|
10
|
+
|
11
|
+
PAGE_SIZE = 20
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@controller = AuthorListController.new(self)
|
15
|
+
@current_page = 1
|
16
|
+
@total_count = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_create
|
20
|
+
@controller.on_view_created
|
21
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Метод наблюдателя datalist
|
25
|
+
# def on_datalist_changed(new_table)
|
26
|
+
# arr = new_table.to_2d_array
|
27
|
+
# arr.map do |row|
|
28
|
+
# row[3] = [row[3][:value], contact_color(row[3][:type])] unless row[3].nil?
|
29
|
+
# end
|
30
|
+
# @table.model_array = arr
|
31
|
+
# end
|
32
|
+
|
33
|
+
def update(authors)
|
34
|
+
@items = []
|
35
|
+
|
36
|
+
i = 0
|
37
|
+
item_num = 0
|
38
|
+
authors.each do |author|
|
39
|
+
i += 1
|
40
|
+
item_num = ((@current_page - 1) * PAGE_SIZE) + i
|
41
|
+
@items << Struct.new(:№, :id, :имя_автора, :фамилия_автора, :отчество_автора).new(item_num, author.author_id, author.first_name, author.last_name, author.father_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
@table.model_array = @items
|
45
|
+
@page_label.text = "#{@current_page} / #{(@total_count / PAGE_SIZE.to_f).ceil}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def update_student_count(new_cnt)
|
49
|
+
@total_count = new_cnt
|
50
|
+
@page_label.text = "#{@current_page} / #{(@total_count / PAGE_SIZE.to_f).ceil}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def create
|
54
|
+
|
55
|
+
root_container = horizontal_box {
|
56
|
+
# Секция 1
|
57
|
+
vertical_box {
|
58
|
+
stretchy false
|
59
|
+
|
60
|
+
vertical_box {
|
61
|
+
stretchy false
|
62
|
+
|
63
|
+
label {
|
64
|
+
text 'Отчество'
|
65
|
+
}
|
66
|
+
combobox { |c|
|
67
|
+
items ['Не важно','Есть','Нет']
|
68
|
+
selected 0
|
69
|
+
on_selected do
|
70
|
+
@controller.filter_father_name(@current_page, PAGE_SIZE, c.selected)
|
71
|
+
end
|
72
|
+
}
|
73
|
+
|
74
|
+
label {
|
75
|
+
text 'Сортировка'
|
76
|
+
}
|
77
|
+
combobox { |c|
|
78
|
+
items ['ID','Имя автора','Фамилия автора', 'Отчество автора']
|
79
|
+
selected 0
|
80
|
+
on_selected do
|
81
|
+
@controller.sort(@current_page, PAGE_SIZE, c.selected)
|
82
|
+
end
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
}
|
88
|
+
|
89
|
+
# Секция 2
|
90
|
+
vertical_box {
|
91
|
+
@table = refined_table(
|
92
|
+
table_editable: false,
|
93
|
+
filter: lambda do |row_hash, query|
|
94
|
+
utf8_query = query.force_encoding("utf-8")
|
95
|
+
row_hash['Имя автора'].include?(utf8_query)
|
96
|
+
end,
|
97
|
+
table_columns: {
|
98
|
+
'№' => :text,
|
99
|
+
'ID' => :text,
|
100
|
+
'Имя автора' => :text,
|
101
|
+
'Фамилия автора' => :text,
|
102
|
+
'Отчество автора' => :text,
|
103
|
+
},
|
104
|
+
per_page: PAGE_SIZE,
|
105
|
+
|
106
|
+
)
|
107
|
+
|
108
|
+
@pages = horizontal_box {
|
109
|
+
stretchy false
|
110
|
+
|
111
|
+
button("<") {
|
112
|
+
stretchy true
|
113
|
+
|
114
|
+
on_clicked do
|
115
|
+
@current_page = [@current_page - 1, 1].max
|
116
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
117
|
+
end
|
118
|
+
|
119
|
+
}
|
120
|
+
@page_label = label("...") { stretchy false }
|
121
|
+
button(">") {
|
122
|
+
stretchy true
|
123
|
+
|
124
|
+
on_clicked do
|
125
|
+
@current_page = [@current_page + 1, (@total_count / PAGE_SIZE.to_f).ceil].min
|
126
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
127
|
+
end
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
# Секция 3
|
133
|
+
vertical_box {
|
134
|
+
stretchy false
|
135
|
+
|
136
|
+
button('Добавить') {
|
137
|
+
stretchy false
|
138
|
+
|
139
|
+
on_clicked {
|
140
|
+
@controller.show_modal_add
|
141
|
+
}
|
142
|
+
}
|
143
|
+
button('Изменить') {
|
144
|
+
stretchy false
|
145
|
+
|
146
|
+
on_clicked {
|
147
|
+
@controller.show_modal_edit(@current_page, PAGE_SIZE, @table.selection) unless @table.selection.nil?
|
148
|
+
}
|
149
|
+
}
|
150
|
+
button('Удалить') {
|
151
|
+
stretchy false
|
152
|
+
|
153
|
+
on_clicked {
|
154
|
+
@controller.delete_selected(@current_page, PAGE_SIZE, @table.selection) unless @table.selection.nil?
|
155
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
156
|
+
}
|
157
|
+
}
|
158
|
+
button('Обновить') {
|
159
|
+
stretchy false
|
160
|
+
|
161
|
+
on_clicked {
|
162
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
}
|
167
|
+
on_create
|
168
|
+
root_container
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require './lib/views/main_window'
|
4
|
+
require './lib/repositories/student_repository'
|
5
|
+
require './lib/repositories/adapters/db_source_adapter'
|
6
|
+
require './lib/repositories/containers/data_list_student_short'
|
7
|
+
require 'win32api'
|
8
|
+
|
9
|
+
class TabStudentsController
|
10
|
+
def initialize(view)
|
11
|
+
@view = view
|
12
|
+
@data_list = DataListStudentShort.new([])
|
13
|
+
@data_list.add_listener(@view)
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_view_created
|
17
|
+
begin
|
18
|
+
@student_rep = StudentRepository.new(DBSourceAdapter.new)
|
19
|
+
rescue Mysql2::Error::ConnectionError
|
20
|
+
on_db_conn_error
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def show_view
|
25
|
+
@view.create.show
|
26
|
+
end
|
27
|
+
|
28
|
+
def refresh_data(page, per_page)
|
29
|
+
begin
|
30
|
+
@data_list = @student_rep.paginated_short_students(page, per_page, @data_list)
|
31
|
+
@view.update_student_count(@student_rep.student_count)
|
32
|
+
rescue
|
33
|
+
on_db_conn_error
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_db_conn_error
|
38
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
39
|
+
api.call(0, "No connection to DB", "Error", 0)
|
40
|
+
# TODO: Возможность переключения на JSON помимо exit
|
41
|
+
exit(false)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'mysql2'
|
2
|
+
require_relative 'db_client'
|
3
|
+
class BookDBDataSource
|
4
|
+
def initialize
|
5
|
+
@client = DBClient.instance
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(book)
|
9
|
+
query = "INSERT INTO Book (BookID, Title, AuthorID, PublisherID) VALUES (#{book.id}, '#{book.title}', #{book.author_id}, #{book.publisher_id})"
|
10
|
+
@client.query(query)
|
11
|
+
end
|
12
|
+
|
13
|
+
def change(book)
|
14
|
+
query = "UPDATE Book SET Title='#{book.title}', AuthorID=#{book.author_id}, PublisherID=#{book.publisher_id} WHERE BookID=#{book.id}"
|
15
|
+
@client.query(query)
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete(id)
|
19
|
+
query = "DELETE FROM Book WHERE BookID=#{id}"
|
20
|
+
@client.query(query)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get(id)
|
24
|
+
query = "SELECT * FROM Book WHERE BookID=#{id}"
|
25
|
+
result = @client.query(query).first
|
26
|
+
if result
|
27
|
+
Book.new(result['BookID'], result['Title'], result['AuthorID'], result['PublisherID'])
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_list(page_size, page_num, sort_field, sort_direction)
|
34
|
+
offset = (page_num - 1) * page_size
|
35
|
+
query = "SELECT * FROM Book ORDER BY #{sort_field} #{sort_direction} LIMIT #{page_size} OFFSET #{offset}"
|
36
|
+
results = @client.query(query)
|
37
|
+
books = []
|
38
|
+
results.each do |result|
|
39
|
+
books << Book.new(result['BookID'], result['Title'], result['AuthorID'], result['PublisherID'])
|
40
|
+
end
|
41
|
+
books
|
42
|
+
end
|
43
|
+
end
|