papaSquidLib 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +69 -0
  4. data/lib/controllers/tab_students_controller.rb +43 -0
  5. data/lib/data_sources/db_client.rb +35 -0
  6. data/lib/db_config/config.yaml +5 -0
  7. data/lib/db_config/library_config.yaml +5 -0
  8. data/lib/db_config/migrations/create_db.sql +3 -0
  9. data/lib/db_config/migrations/create_tables.sql +29 -0
  10. data/lib/db_config/mock_data/mock_data.sql +72 -0
  11. data/lib/logger.rb +27 -0
  12. data/lib/main.rb +6 -0
  13. data/lib/manager/controllers/manager_input_form_controller_create.rb +44 -0
  14. data/lib/manager/controllers/manager_input_form_controller_edit.rb +54 -0
  15. data/lib/manager/controllers/manager_list_controller.rb +99 -0
  16. data/lib/manager/manager_db_data_source.rb +63 -0
  17. data/lib/manager/ui/manager_input_form.rb +69 -0
  18. data/lib/manager/ui/manager_list_view.rb +168 -0
  19. data/lib/models/manager.rb +41 -0
  20. data/lib/models/student.rb +102 -0
  21. data/lib/models/student_base.rb +100 -0
  22. data/lib/models/student_short.rb +50 -0
  23. data/lib/models/task.rb +49 -0
  24. data/lib/models/user.rb +32 -0
  25. data/lib/papaSquidLib/version.rb +5 -0
  26. data/lib/papa_squid_lib.rb +6 -0
  27. data/lib/repositories/adapters/db_source_adapter.rb +54 -0
  28. data/lib/repositories/adapters/file_source_adapter.rb +37 -0
  29. data/lib/repositories/containers/data_list.rb +74 -0
  30. data/lib/repositories/containers/data_list_student_short.rb +18 -0
  31. data/lib/repositories/containers/data_table.rb +35 -0
  32. data/lib/repositories/data_sources/db_data_source.rb +32 -0
  33. data/lib/repositories/data_sources/file_data_source.rb +75 -0
  34. data/lib/repositories/data_sources/transformers/data_transformer_base.rb +15 -0
  35. data/lib/repositories/data_sources/transformers/data_transformer_json.rb +16 -0
  36. data/lib/repositories/data_sources/transformers/data_transformer_yaml.rb +16 -0
  37. data/lib/repositories/student_repository.rb +32 -0
  38. data/lib/state_holders/list_state_notifier.rb +60 -0
  39. data/lib/task/controllers/task_input_form_controller_create.rb +43 -0
  40. data/lib/task/controllers/task_input_form_controller_edit.rb +57 -0
  41. data/lib/task/controllers/task_list_controller.rb +93 -0
  42. data/lib/task/task_db_data_source.rb +85 -0
  43. data/lib/task/ui/task_input_form.rb +67 -0
  44. data/lib/task/ui/task_input_form_factory.rb +26 -0
  45. data/lib/task/ui/task_list_view.rb +163 -0
  46. data/lib/user/controllers/user_input_form_controller_create.rb +42 -0
  47. data/lib/user/controllers/user_input_form_controller_edit.rb +53 -0
  48. data/lib/user/controllers/user_list_controller.rb +99 -0
  49. data/lib/user/ui/user_input_form.rb +69 -0
  50. data/lib/user/ui/user_list_view.rb +170 -0
  51. data/lib/user/user_db_data_source.rb +71 -0
  52. data/lib/views/main_window.rb +32 -0
  53. data/lib/views/tab_students.rb +148 -0
  54. data/papaSquidLib.gemspec +15 -0
  55. data/test/manager_test.rb +27 -0
  56. data/test/state_notifier_test.rb +82 -0
  57. data/test/task_test.rb +51 -0
  58. data/test/user_test.rb +39 -0
  59. metadata +113 -0
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './lib/repositories/containers/data_table'
4
+
5
+ class DataList
6
+ # Это "абстрактный" класс
7
+ private_class_method :new
8
+
9
+ attr_writer :objects
10
+
11
+ # Конструктор, принимает массив любых объектов
12
+ def initialize(objects)
13
+ self.objects = objects
14
+ @listeners = []
15
+ end
16
+
17
+ def add_listener(listener)
18
+ @listeners << listener
19
+ end
20
+
21
+ def remove_listener(listener)
22
+ @listeners.delete(listener)
23
+ end
24
+
25
+ def notify
26
+ @listeners.each { |lst| lst.on_datalist_changed(data_table) }
27
+ end
28
+
29
+ # Выбрать элемент по номеру
30
+ def select_element(number)
31
+ self.selected_num = number < objects.size ? number : nil
32
+ end
33
+
34
+ def selected_id
35
+ objects[selected_num].id
36
+ end
37
+
38
+ # Получить DataTable со всеми элементами.
39
+ def data_table
40
+ result = []
41
+ counter = 0
42
+ objects.each do |obj|
43
+ row = []
44
+ row << counter
45
+ row.push(*table_fields(obj))
46
+ result << row
47
+ counter += 1
48
+ end
49
+ DataTable.new(result)
50
+ end
51
+
52
+ # Добавить элементы в конец списка
53
+ def replace_objects(objects)
54
+ self.objects = objects.dup
55
+ notify
56
+ end
57
+
58
+ protected
59
+
60
+ # Список значений полей для DataTable. Переопределить в наследниках
61
+ def table_fields(_obj)
62
+ []
63
+ end
64
+
65
+ # Имена атрибутов объектов по порядку. Переопределить в наследниках
66
+ def column_names
67
+ []
68
+ end
69
+
70
+ private
71
+
72
+ attr_reader :objects
73
+ attr_accessor :selected_num
74
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'data_list'
4
+
5
+ class DataListStudentShort < DataList
6
+ # Делаем приватный new предка публичным
7
+ public_class_method :new
8
+
9
+ def column_names
10
+ ['Фамилия И. О.', 'Гит', 'Контакт']
11
+ end
12
+
13
+ protected
14
+
15
+ def table_fields(obj)
16
+ [obj.last_name_and_initials, obj.git, obj.contact]
17
+ end
18
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DataTable
4
+ attr_reader :rows_count, :cols_count
5
+
6
+ # Конструктор, принимает 2D Array
7
+ def initialize(table)
8
+ self.rows_count = table.size
9
+ max_cols = 0
10
+ table.each { |row| max_cols = row.size if row.size > max_cols }
11
+ self.cols_count = max_cols
12
+ self.table = table
13
+ end
14
+
15
+ # Получить значение в ячейке [row, col]
16
+ def get_item(row, col)
17
+ return nil if row >= rows_count
18
+ return nil if col >= cols_count
19
+
20
+ table[row][col].dup
21
+ end
22
+
23
+ def to_2d_array
24
+ table.dup
25
+ end
26
+
27
+ def to_s
28
+ "DataTable (#{rows_count}x#{cols_count})"
29
+ end
30
+
31
+ private
32
+
33
+ attr_accessor :table
34
+ attr_writer :rows_count, :cols_count
35
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mysql2'
4
+
5
+ class DBDataSource
6
+ private_class_method :new
7
+ @instance_mutex = Mutex.new
8
+
9
+ def initialize
10
+ db_config = YAML.load_file('./lib/db_config/config.yaml').transform_keys(&:to_sym)
11
+ @client = Mysql2::Client.new(db_config)
12
+ @client.query_options.merge!(symbolize_keys: true)
13
+ end
14
+
15
+ def self.instance
16
+ return @instance if @instance
17
+
18
+ @instance_mutex.synchronize do
19
+ @instance ||= new
20
+ end
21
+
22
+ @instance
23
+ end
24
+
25
+ def prepare_exec(statement, *params)
26
+ @client.prepare(statement).execute(*params)
27
+ end
28
+
29
+ def query(statement)
30
+ @client.query(statement)
31
+ end
32
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './lib/models/student'
4
+ require './lib/models/student_short'
5
+ require './lib/repositories/containers/data_list_student_short'
6
+
7
+ class FileDataSource
8
+ attr_writer :data_transformer
9
+
10
+ def initialize(data_transformer)
11
+ self.students = []
12
+ self.seq_id = 1
13
+ self.data_transformer = data_transformer
14
+ end
15
+
16
+ def load_from_file(file_path)
17
+ hash_list = data_transformer.str_to_hash_list(File.read(file_path))
18
+ self.students = hash_list.map { |h| Student.from_hash(h) }
19
+ update_seq_id
20
+ end
21
+
22
+ def save_to_file(file_path)
23
+ hash_list = students.map(&:to_hash)
24
+ File.write(file_path, data_transformer.hash_list_to_str(hash_list))
25
+ end
26
+
27
+ def student_by_id(student_id)
28
+ students.detect { |s| s.id == student_id }
29
+ end
30
+
31
+ # Получить page по счету count элементов (страница начинается с 1)
32
+ def paginated_short_students(page, count, existing_data_list = nil)
33
+ offset = (page - 1) * count
34
+ slice = students[offset, count].map { |s| StudentShort.from_student(s) }
35
+
36
+ return DataListStudentShort.new(slice) if existing_data_list.nil?
37
+
38
+ existing_data_list.replace_objects(slice)
39
+ existing_data_list
40
+ end
41
+
42
+ def sorted
43
+ students.sort_by(&:last_name_and_initials)
44
+ end
45
+
46
+ def add_student(student)
47
+ student.id = seq_id
48
+ students << student
49
+ self.seq_id += 1
50
+ student.id
51
+ end
52
+
53
+ def replace_student(student_id, student)
54
+ idx = students.find_index { |s| s.id == student_id }
55
+ students[idx] = student
56
+ end
57
+
58
+ def remove_student(student_id)
59
+ students.reject! { |s| s.id == student_id }
60
+ end
61
+
62
+ def student_count
63
+ students.count
64
+ end
65
+
66
+ private
67
+
68
+ # Метод для актуализации seq_id
69
+ def update_seq_id
70
+ self.seq_id = students.max_by(&:id).id + 1
71
+ end
72
+
73
+ attr_reader :data_transformer
74
+ attr_accessor :students, :seq_id
75
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DataTransformerBase
4
+ private_class_method :new
5
+
6
+ protected
7
+
8
+ def str_to_hash_list(str)
9
+ raise NotImplementedError('Should be implemented in child')
10
+ end
11
+
12
+ def hash_list_to_str(hash_list)
13
+ raise NotImplementedError('Should be implemented in child')
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'data_transformer_base'
4
+ require 'json'
5
+
6
+ class DataTransformerJSON < DataTransformerBase
7
+ public_class_method :new
8
+
9
+ def str_to_hash_list(str)
10
+ JSON.parse(str, { symbolize_names: true })
11
+ end
12
+
13
+ def hash_list_to_str(hash_list)
14
+ JSON.pretty_generate(hash_list)
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'data_transformer_base'
4
+ require 'yaml'
5
+
6
+ class DataTransformerYAML < DataTransformerBase
7
+ public_class_method :new
8
+
9
+ def str_to_hash_list(str)
10
+ YAML.safe_load(str).map { |h| h.transform_keys(&:to_sym) }
11
+ end
12
+
13
+ def hash_list_to_str(hash_list)
14
+ hash_list.map { |h| h.transform_keys(&:to_s) }.to_yaml
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class StudentRepository
4
+ def initialize(data_source_adapter)
5
+ @data_source_adapter = data_source_adapter
6
+ end
7
+
8
+ def student_by_id(student_id)
9
+ @data_source_adapter.student_by_id(student_id)
10
+ end
11
+
12
+ # Получить page по счету count элементов (страница начинается с 1)
13
+ def paginated_short_students(page, count, existing_data_list = nil)
14
+ @data_source_adapter.paginated_short_students(page, count, existing_data_list)
15
+ end
16
+
17
+ def add_student(student)
18
+ @data_source_adapter.add_student(student)
19
+ end
20
+
21
+ def replace_student(student_id, student)
22
+ @data_source_adapter.replace_student(student_id, student)
23
+ end
24
+
25
+ def remove_student(student_id)
26
+ @data_source_adapter.remove_student(student_id)
27
+ end
28
+
29
+ def student_count
30
+ @data_source_adapter.student_count
31
+ end
32
+ end
@@ -0,0 +1,60 @@
1
+ class ListStateNotifier
2
+ attr_reader :items
3
+
4
+ def initialize
5
+ @items = []
6
+ @listeners = []
7
+ end
8
+
9
+ # устанавливает новое значение для items и уведомляет всех слушателей.
10
+ def set_all(objects)
11
+ LoggerHolder.instance.debug('ListStateNotifier: set_all')
12
+ @items = objects
13
+ notify_listeners
14
+ end
15
+
16
+ # добавляет объект в массив items и уведомляет всех слушателей.
17
+ def add(object)
18
+ LoggerHolder.instance.debug('ListStateNotifier: add')
19
+ @items << object
20
+ notify_listeners
21
+ end
22
+ # возвращает объект из массива items по индексу.
23
+ def get(number)
24
+ LoggerHolder.instance.debug('ListStateNotifier: get')
25
+ @items[number]
26
+ end
27
+
28
+ # удаляет объект из массива items и уведомляет всех слушателей.
29
+ def delete(object)
30
+ LoggerHolder.instance.debug('ListStateNotifier: delete')
31
+ @items.delete(object)
32
+ notify_listeners
33
+ end
34
+
35
+ # заменяет объект в массиве items на новый объект и уведомляет всех слушателей.
36
+ def replace(object, new_object)
37
+ LoggerHolder.instance.debug('ListStateNotifier: replace')
38
+ index = @items.index(object)
39
+ @items[index] = new_object
40
+ notify_listeners
41
+ end
42
+ # добавляет нового слушателя в массив listeners.
43
+ def add_listener(listener)
44
+ LoggerHolder.instance.debug('ListStateNotifier: add_listener')
45
+ @listeners << listener
46
+ end
47
+ # удаляет слушателя из массива listeners.
48
+ def delete_listener(listener)
49
+ LoggerHolder.instance.debug('ListStateNotifier: delete_listener')
50
+ @listeners.delete(listener)
51
+ end
52
+
53
+ # уведомляет всех слушателей о изменении массива items.
54
+ def notify_listeners
55
+ LoggerHolder.instance.debug('notify_listeners')
56
+ @listeners.each do |listener|
57
+ listener.update(@items)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ require 'win32api'
3
+
4
+ class TaskInputFormControllerCreate
5
+ def initialize(parent_controller)
6
+ @parent_controller = parent_controller
7
+ @task_rep = TaskDbDataSource.new
8
+ end
9
+
10
+ def set_view(view)
11
+ @view = view
12
+ end
13
+
14
+ def on_view_created
15
+ # begin
16
+ # @student_rep = StudentRepository.new(DBSourceAdapter.new)
17
+ # rescue Mysql2::Error::ConnectionError
18
+ # on_db_conn_error
19
+ # end
20
+ end
21
+
22
+ def process_fields(fields)
23
+ begin
24
+ values = fields.values
25
+ values.insert(-2, Time.now.strftime("%Y-%m-%d"))
26
+ item = Task.new(-1, *values)
27
+ item = @task_rep.add(item)
28
+ @parent_controller.state_notifier.add(item)
29
+ @view.close
30
+ rescue ArgumentError => e
31
+ api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
32
+ api.call(0, e.message, 'Error', 0)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def on_db_conn_error
39
+ api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
40
+ api.call(0, "No connection to DB", "Error", 0)
41
+ @view.close
42
+ end
43
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TaskInputFormControllerEdit
4
+ def initialize(parent_controller, item)
5
+ @parent_controller = parent_controller
6
+ @item = item
7
+ @task_rep = TaskDbDataSource.new
8
+ end
9
+
10
+ def set_view(view)
11
+ @view = view
12
+ end
13
+
14
+ def on_view_created
15
+ # begin
16
+ # @student_rep = StudentRepository.new(DBSourceAdapter.new)
17
+ # rescue Mysql2::Error::ConnectionError
18
+ # on_db_conn_error
19
+ # end
20
+
21
+ # @item = @author_rep.get(@item_id)
22
+ # @view.make_readonly(:git, :telegram, :email, :phone)
23
+ populate_fields(@item)
24
+ end
25
+
26
+ def populate_fields(item)
27
+ @view.set_value(:description, item.description)
28
+ @view.set_value(:completed, item.completed)
29
+ end
30
+
31
+ def process_fields(fields)
32
+
33
+ begin
34
+ print "\n"
35
+ print"ITEM ID=#{@item.task_id}"
36
+ print "\n"
37
+ item = Task.new(@item.task_id, @item.user_id, @item.manager_id, @item.date, *fields.values)
38
+ print "\n"
39
+ print"NEW ITEM ID=#{item.task_id}"
40
+ print "\n"
41
+ item = @task_rep.change(item)
42
+ @parent_controller.state_notifier.replace(@item, item)
43
+ @view.close
44
+ rescue ArgumentError => e
45
+ api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
46
+ api.call(0, e.message, 'Error', 0)
47
+ end
48
+ end
49
+
50
+ private
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
+ @view.close
56
+ end
57
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+ require './lib/state_holders/list_state_notifier'
3
+ require_relative '../ui/task_input_form'
4
+ require_relative 'task_input_form_controller_create.rb'
5
+ require_relative 'task_input_form_controller_edit'
6
+ require_relative '../task_db_data_source'
7
+ require_relative '../ui/task_input_form_factory'
8
+ require 'win32api'
9
+
10
+ class TaskListController
11
+
12
+ attr_reader :state_notifier
13
+ def initialize(view)
14
+ @view = view
15
+ @state_notifier = ListStateNotifier.new
16
+ @state_notifier.add_listener(@view)
17
+ @task_rep = TaskDbDataSource.new
18
+
19
+ @sort_columns = %w[TaskID UserID ManagerID Date Description Completed]
20
+ @sort_by = @sort_columns.first
21
+
22
+ @completed_filter_columns = [nil, 'Done', 'Undone']
23
+ @completed_filter = @completed_filter_columns.first
24
+ end
25
+
26
+
27
+
28
+ def on_view_created
29
+ # begin
30
+ # @student_rep = StudentRepository.new(DBSourceAdapter.new)
31
+ # rescue Mysql2::Error::ConnectionError
32
+ # on_db_conn_error
33
+ # end
34
+ end
35
+
36
+ def show_view
37
+ @view.create.show
38
+ end
39
+
40
+ def show_modal_add
41
+ controller = TaskInputFormControllerCreate.new(self)
42
+ view = TaskInputFormFactory.create_create_form(controller)
43
+ controller.set_view(view)
44
+ view.create.show
45
+ end
46
+
47
+ def show_modal_edit(current_page, per_page, selected_row)
48
+ item = @state_notifier.get(selected_row)
49
+ controller = TaskInputFormControllerEdit.new(self, item)
50
+ view = TaskInputFormFactory.create_edit_form(controller, item)
51
+ controller.set_view(view)
52
+ view.create.show
53
+ end
54
+
55
+ def delete_selected(current_page, per_page, selected_row)
56
+ begin
57
+ item = @state_notifier.get(selected_row)
58
+ @task_rep.delete(item.task_id)
59
+ @state_notifier.delete(item)
60
+ rescue
61
+ api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
62
+ api.call(0, "You cannot delete the user because he is associated with some user or manager", "Error", 0)
63
+ end
64
+ end
65
+
66
+ def refresh_data(page, per_page)
67
+ print "\n"
68
+ print "completed filter:#{@completed_filter}"
69
+ print "\n"
70
+ items = @task_rep.get_list(per_page, page, @sort_by, 'ASC', @completed_filter)
71
+ @state_notifier.set_all(items)
72
+ @view.update_student_count(@task_rep.count)
73
+ end
74
+
75
+ def sort(page, per_page, sort_index)
76
+ @sort_by = @sort_columns[sort_index]
77
+ refresh_data(page, per_page)
78
+ end
79
+
80
+ def filter_completed(page, per_page, filter_index)
81
+ @completed_filter = @completed_filter_columns[filter_index]
82
+ refresh_data(page, per_page)
83
+ end
84
+
85
+
86
+ private
87
+
88
+ def on_db_conn_error
89
+ api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
90
+ api.call(0, "No connection to DB", "Error", 0)
91
+ exit(false)
92
+ end
93
+ end
@@ -0,0 +1,85 @@
1
+ require 'mysql2'
2
+ require_relative '../data_sources/db_client'
3
+ class TaskDbDataSource
4
+ def initialize
5
+ @client = DBClient.instance
6
+ end
7
+ def add(task)
8
+ user_exists = user_exists?(task.user_id)
9
+ manager_exists = manager_exists?(task.manager_id)
10
+ query = "INSERT INTO Task (UserID, ManagerID, Date, Description, Completed) VALUES (#{task.user_id}, #{task.manager_id}, '#{task.date}', '#{task.description}', '#{task.completed}')"
11
+ @client.query(query)
12
+ task_id = @client.last_id
13
+ get(task_id)
14
+ end
15
+
16
+ def change(task)
17
+ user_exists = user_exists?(task.user_id)
18
+ manager_exists = manager_exists?(task.manager_id)
19
+ query = "UPDATE Task SET Completed='#{task.completed}', Description='#{task.description}' WHERE TaskID=#{task.task_id}"
20
+ @client.query(query)
21
+ get(task.task_id)
22
+ end
23
+
24
+
25
+ def delete(id)
26
+ query = "DELETE FROM Task WHERE TaskID=#{id}"
27
+ @client.query(query)
28
+ end
29
+
30
+ def get(id)
31
+ query = "SELECT * FROM Task WHERE TaskID=#{id}"
32
+ result = @client.query(query).first
33
+ if result
34
+ Task.new(result[:'TaskID'], result[:'UserID'], result[:'ManagerID'], result[:'Date'], result[:'Description'], result[:'Completed'])
35
+ else
36
+ nil
37
+ end
38
+ end
39
+
40
+ def get_list(page_size, page_num, sort_field, sort_direction, completed = nil)
41
+ offset = (page_num - 1) * page_size
42
+ query = "SELECT * FROM Task"
43
+ print "\n"
44
+ print "completed:#{completed}"
45
+ print "\n"
46
+ if completed == 'Done'
47
+ query += " WHERE Completed='Done'"
48
+ elsif completed == 'Undone'
49
+ query += " WHERE Completed='Undone'"
50
+ end
51
+
52
+ query += " ORDER BY #{sort_field} #{sort_direction} LIMIT #{page_size} OFFSET #{offset}"
53
+ results = @client.query(query)
54
+
55
+ tasks = []
56
+ results.each do |result|
57
+ tasks << Task.new(result[:'TaskID'], result[:'UserID'], result[:'ManagerID'], result[:'Date'], result[:'Description'], result[:'Completed'])
58
+ end
59
+
60
+ tasks
61
+ end
62
+
63
+ def count
64
+ query = "SELECT COUNT(*) FROM Task"
65
+ result = @client.query(query).first
66
+ result[:'COUNT(*)']
67
+ end
68
+
69
+ def user_exists?(user_id)
70
+ query = "SELECT COUNT(*) FROM User WHERE UserID=#{user_id}"
71
+ result = @client.query(query).first
72
+ unless result[:'COUNT(*)'] > 0
73
+ raise ArgumentError, "User with ID=#{user_id} doesn't exist"
74
+ end
75
+ end
76
+
77
+ def manager_exists?(manager_id)
78
+ query = "SELECT COUNT(*) FROM Manager WHERE ManagerID=#{manager_id}"
79
+ result = @client.query(query).first
80
+ unless result[:'COUNT(*)'] > 0
81
+ raise ArgumentError, "Manager with ID=#{manager_id} doesn't exist"
82
+ end
83
+ end
84
+
85
+ end