-
Notifications
You must be signed in to change notification settings - Fork 0
/
database.ml
204 lines (178 loc) · 6.85 KB
/
database.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
(*Implementation of the data file management*)
(********Types********)
type task = {id : int; assignee : string; title : string;
status : string; description : string}
type team = {team_name : string; members : string list}
type login_details = {username : string; password : string}
type search_result =
| Success of string list
| Unsuccessful of string
(********End Types********)
(********Exceptions********)
exception NotFound of string
(********End Exceptions********)
(********Constructors********)
(*Solve the case where you have ; in description, i.e.
a helper on List.hd description to link all of em tgth*)
let create_task string =
match String.split_on_char ';' string with
| id::assignee::title::status::description ->
{id = int_of_string id; assignee = assignee; title = title;
status = status;
description =
if List.length description = 1 && List.hd description = "" then "" else
let temp_descr =
List.fold_left (fun x y -> x ^ ";" ^ y) "" description in
String.sub temp_descr 1 ((String.length temp_descr) - 1)}
| _ -> failwith "mistake with the reading"
let create_team string =
match String.split_on_char ';' string with
| h::t -> {team_name = h; members = t}
| _ -> failwith "mistake creating a team"
let create_login string =
match String.split_on_char ';' string with
| [] -> failwith ""
| h::t -> begin
match t with
| h1::t1 -> {username = h; password = h1}
| [] -> failwith ""
end
(********End Constructors********)
(********General Helpers********)
let string_contains str1 str2=
let len1 = String.length str1 and len2 = String.length str2 in
if len1 < len2 then false else
let rec check i =
if i > len1 - len2 then false else
if (str2 = String.sub str1 i len2) then true else check (succ i) in
check 0
(** [string_of_task task] is the string representation of [task]. *)
let string_of_task (task : task) : string =
string_of_int task.id ^ ";" ^ task.assignee ^ ";" ^
task.title ^ ";" ^ task.status ^ ";" ^ "\"" ^ task.description ^ "\""
let get_search_results filename criterion : search_result =
let channel = open_in filename in
let rec parse_line chnl acc=
match input_line chnl with
| x -> if string_contains x criterion then parse_line chnl (x :: acc)
else parse_line chnl acc
| exception End_of_file -> acc in
let results = parse_line channel [] in
close_in channel;
if List.length results != 0 then Success results
else Unsuccessful ("Could not find anything matching: " ^ criterion)
let rec form_list lst acc constr =
match lst with
| [] -> acc
| h::t -> form_list t (constr h :: acc) constr
let form_task_list task_strings =
form_list task_strings [] create_task
let form_teams_list team_strings =
form_list team_strings [] create_team
let form_login_list login_strings =
form_list login_strings [] create_login
let update_task_field task data = function
| "id" -> {task with id = int_of_string data;
description = String.sub task.description 1
(String.length task.description - 2)}
| "assignee" -> {task with assignee=data;
description = String.sub task.description 1
(String.length task.description - 2)}
| "title" -> {task with title=data;
description = String.sub task.description 1
(String.length task.description - 2)}
| "status" -> {task with status=data;
description = String.sub task.description 1
(String.length task.description - 2)}
| "description" -> {task with description=data}
| _ -> raise Not_found
let total_tasks filename =
let chnl = open_in filename in
let first_line = input_line chnl in
close_in chnl;
match String.split_on_char ';' first_line with
| [] -> failwith "mistake"
| h::t -> int_of_string h
let new_line_task old_line change field =
let old_task = create_task old_line in
string_of_task (update_task_field old_task change field)
let dec_id task_line =
let delim = String.index task_line ';' in
let id = int_of_string (String.sub task_line 0 delim) in
let rest = String.sub task_line delim (String.length task_line - delim) in
string_of_int (id - 1) ^ rest
let list_to_string data =
String.concat ";" data
(********End General Helpers********)
let search_tasks criterion =
match get_search_results "issues.txt" criterion with
| Success x -> form_task_list x
| Unsuccessful x -> raise (NotFound criterion)
let search_teams criterion =
match get_search_results "teams.txt" criterion with
| Success x -> form_teams_list x
| Unsuccessful x -> raise (NotFound criterion)
let search_logins criterion =
match get_search_results "login_details.txt" criterion with
| Success x -> form_login_list x
| Unsuccessful x -> raise (NotFound criterion)
let mod_tasks
(mod_line : string -> int -> 'a -> out_channel -> unit)
(data : 'a) : unit =
let ic = open_in "issues.txt" in
let temp = "issues.txt.temp" in
let oc = open_out temp in
let rec process i =
match input_line ic with
| line -> mod_line line i data oc; process (pred i)
| exception (End_of_file) ->
begin
flush oc;
close_in ic;
close_out oc;
Sys.remove "issues.txt";
Sys.rename temp "issues.txt"
end
in process (total_tasks "issues.txt")
(*For all data types, use that*)
let add_data_all filename data id_required =
let temp_file = filename ^ ".temp" in
let inp = open_in filename and out = open_out temp_file in
let new_data = if id_required then (string_of_int (total_tasks filename + 1))
^ ";" ^ (String.concat ";" data)
else String.concat ";" data in
output_string out new_data; output_char out '\n';
let rec add_line i =
match input_line inp with
| line ->
output_string out line; output_char out '\n';
add_line i;
| exception (End_of_file) ->
begin
flush out;
close_in inp;
close_out out;
Sys.remove filename;
Sys.rename temp_file filename;
end in
add_line 1
let delete_task id =
let incl line i del oc =
if i <> del then
begin
let out_line = if i > del then dec_id line else line in
output_string oc out_line;
(* If i is 1, then don't make a new line.
If i is 2, and del is 1, then don't make a new line. *)
if not (i = 1 || (del = 1 && i = 2)) then output_char oc '\n'
end
in mod_tasks incl id
let edit_task change field id =
let edit line i (change, field, id) oc =
begin
let out_line = if i <> id then line
else new_line_task line change field
in output_string oc out_line;
if i > 1 then output_char oc '\n'
end
in mod_tasks edit (change, field, id)