· 8 years ago · May 02, 2018, 12:56 PM
1/*
2 * tables.
3 * Prints the names of all existing tables, one per line (use writeln/1 )
4 * It just get the list of all existing tables, then call the recursive
5 * list printer.
6*/
7
8tables :-
9 tables(Tables),
10 print_list(Tables).
11
12/*
13 * tables(-Tables)
14 * Unify -Tables with a list of the names of all existing tables.
15 * Findall used for that very purpose.
16*/
17
18tables(Tables) :-
19 findall(Name, table(Name, _, _), Tables).
20
21/*
22 * create(+Table, +Cols)
23 * Creation of a new table with the specified list of column names
24 * Exception is thrown if +Table name already exists
25*/
26
27create(Table, _) :-
28 table(Table, _, _),
29 table_exist_error(Table).
30
31create(Table, Cols) :-
32 length(Cols, Length),
33 prefix_list(Table, Cols, Columns),
34 assertz(table(Table, Columns, Length)).
35
36/*
37 * cols(+Table, -Cols)
38 * Unifies Cols with the (ordered) list of columns for the specified table.
39 * Exception is thrown if +Table name does not exist
40*/
41
42cols(Table, _) :-
43 not(table(Table, _, _)),
44 table_not_exist_error(Table).
45
46cols(Table, CleanedCols) :-
47 table(Table, Cols, _),
48 unprefix_list(Cols, CleanedCols).
49
50/*
51 * rows(+Table)
52 * Display all rows in the given table
53 * Exception is thrown if +Table name does not exist
54*/
55
56rows(Table) :-
57 not(table(Table, _, _)),
58 table_not_exist_error(Table).
59
60rows(Table) :-
61 findall(Rows, row(Table, Rows), Rows),
62 print_list(Rows).
63
64/*
65 * insert(+Table, +Row)
66 * Addition of a given +Row in the given +Table
67 * Exception is thrown if +Table does not exist
68 * Exception is thrown if Row elements does not satisfy Column number of table
69*/
70
71insert(Table, _) :-
72 not(table(Table, _, _)),
73 table_not_exist_error(Table).
74
75insert(Table, Row) :-
76 length(Row, Rowlength),
77 table(Table, _, Length),
78 dif(Rowlength, Length),
79 !,
80 throw("Incorrect number of elements").
81
82insert(Table, Row) :-
83 assertz(row(Table, Row)).
84
85/*
86 * drop(+Table)
87 * Remove the +Table and all associated Rows
88 * Exception is thrown if +Table does not exist
89*/
90
91drop(Table) :-
92 not(table(Table, _, _)),
93 table_not_exist_error(Table).
94
95drop(Table) :-
96 retract(table(Table, _, _)),
97 forall(row(Table, _), retract(row(Table, _))).
98
99/*
100 * delete(+Table)
101 * Remove all Rows from the +Table
102 * Exception is thrown if +Table does not exist
103*/
104
105delete(Table) :-
106 not(table(Table, _, _)),
107 table_not_exist_error(Table).
108
109delete(Table) :-
110 forall(row(Table, _),
111 retract(row(Table, _))).
112
113/*
114 * delete(+Table, +Conds)
115 * Deletion of all rows from the given table that match the given conditions
116 * Exception is thrown if +Table does not exist
117*/
118
119delete(Table, _) :-
120 not(table(Table, _, _)),
121 table_not_exist_error(Table).
122
123delete(Table, Conds) :-
124 full_selector(Table, ColumnList),
125 forall(row(Table, Attributes),
126 delete_row(Table, ColumnList, Conds, Attributes)).
127
128/*
129 * delete_row(+Table, +ColumnList, +CondList, +Attributes)
130 * This predicate checks that the conditions in +CondList can be
131 * applied to a row's +Attributes from table +Table, if so deleting that row.
132 * If conditions fails to be checked on the row, it just return true with
133 * an universal matcher. +ColumnList is the formatted title of column (in the
134 * order with data of the row. return always true to continue the forall
135*/
136
137delete_row(Table, ColumnList, ConditionList, Attributes) :-
138 check_conditions(ConditionList, ColumnList, Attributes),
139 retract(row(Table, Attributes)).
140
141delete_row(_, _, _, _).
142% Allow to return true, if the condition is not validated, and continue the forall.
143
144/*
145 * selec(+TableOrTables, +Selectors, +Conds, -Projection)
146 * Apply +Conds and +Selectors (if +Conds is validate) on +TableOrTables
147 * and unify -Projection (<CleanSelectors>/<Row>).
148 * - Create a full selector (concatenation of each column list of each table).
149 * - Clean the selectors of user (+Column => Table/Column).
150 * - ! to avoid multiple result of full_selector (Never append normally).
151 * - Select one row (of joined table)
152 * - Apply the selector th result only column want by the user.
153*/
154
155selec(TableOrTables, Selectors, Conds, Projection) :-
156 full_selector(TableOrTables, FullSelector),
157 clean_selector(FullSelector, Selectors, CleanSelectors),
158 !,
159 full_join(TableOrTables, Row),
160 check_conditions(Conds, FullSelector, Row),
161 apply_selectors(CleanSelectors, FullSelector, Row, Projection).
162
163% TOOLS : CONDITION MANAGER (FOR DELETE AND SELEC)
164/*
165 * check_conditions(+ConditionList, +Table, +Attributes)
166 * Recursively apply each condition from the +ConditionList
167 * on the +Attributes of given row from +Table, by creating a predicate
168 * from each condition and call it as a predicate.
169*/
170
171check_conditions([], _, _).
172
173check_conditions([HeadCondition | TailConditions], ColumnList, Attributes) :-
174 process_condition(Attributes, ColumnList, HeadCondition, Predicate),
175 call(Predicate),
176 !,
177 check_conditions(TailConditions, ColumnList, Attributes).
178
179/*
180 * process_condition(+Attributes, +ColumnList, +Condition, -Predicate)
181 * Apply +Condition on +Attributes from +ColumnList, creating -Predicate that
182 * can therefore be called to test its truth value.
183 * +Condition can be a single +column identifier, therefore checking
184 * for direct truth value in the row
185*/
186
187process_condition(Attributes, ColumnList, Condition, Predicate) :-
188 functor(Condition, _, Arity),
189 Arity > 1,
190 Condition =.. SpliteCond,
191 replace_identifiers(Attributes, ColumnList, SpliteCond, ParsedCond),
192 !,
193 Predicate =.. ParsedCond.
194
195process_condition(Attributes, ColumnList, +Condition, Predicate) :-
196 nth0(Index, ColumnList, Condition),
197 nth0(Index, Attributes, Value),
198 Predicate = Value.
199
200/*
201 * replace_identifier(+Attributes, +Table, +SplitedCondition, -ParsedCondition)
202 * Replace column identifiers in the +SplitedCondition with +Attributes
203 * values from the row of +Table, and unify with -ParsedCondition.
204 *
205 * Nested reference to identifiers are taken in account
206 * e.g : [+age < 2 * +weight]
207*/
208
209replace_identifiers(_, _, [], []).
210
211replace_identifiers(Attr, ColumnList, [+Column|TCond1], [Value|CondP2]) :-
212 find_column(ColumnList, Column, CleanCol),
213 replace_identifiers(Attr, ColumnList, [CleanCol|TCond1], [Value|CondP2]).
214
215replace_identifiers(Attr, ColumnList, [T/Column|TCond1], [Value|CondP2]) :-
216 nth0(Index, ColumnList, T/Column),
217 nth0(Index, Attr, Value),
218 replace_identifiers(Attr, ColumnList, TCond1, CondP2).
219
220replace_identifiers(Attr, ColumnList, [C1|TCond1], [C2|CondP2]) :-
221 functor(C1, _, Arity),
222 Arity > 1,
223 !,
224 process_condition(Attr, ColumnList, C1, C2),
225 replace_identifiers(Attr, ColumnList, TCond1, CondP2).
226
227replace_identifiers(Attr, ColumnList, [C1|TCond1], [C2|CondP2]) :-
228 C2 = C1,
229 replace_identifiers(Attr, ColumnList, TCond1, CondP2).
230
231% TOOLS : PREDICAT FOR THE SELEC
232
233/*
234 * full_selector(+TableOrTables, -FullSelector)
235 * Unify -FullSelector with the list joined columns between tables (or columns of one table)
236*/
237
238full_selector([Tail], Result) :-
239 table(Tail, Columns, _),
240 append(Columns, [], Result),
241 !.
242
243full_selector([Head|Tail], Result) :-
244 table(Head, Columns, _),
245 full_selector(Tail, R2),
246 append(Columns, R2, Result),
247 !.
248
249% IF ONE TABLE THEN NOT A LIST = cols with prefix
250full_selector(Table, Result) :-
251 table(Table, Columns, _),
252 append(Columns, [], Result),
253 !.
254
255/*
256 * clean_selector(+FullSelectors, +DirtySelectors, -CleanedSelectors)
257 * Rebuilds a list of -CleanedSelectors of the form table/column
258*/
259
260clean_selector(_, [], []).
261
262clean_selector(FullSel, [+Column|TSel], [CleanC|CleanSelector]) :-
263 find_column(FullSel, Column, CleanC),
264 clean_selector(FullSel, TSel, CleanSelector).
265
266clean_selector(FullSel, [C/T|TSel], [C/T|CleanSelector]) :-
267 clean_selector(FullSel, TSel, CleanSelector).
268
269clean_selector(FullSel, *, FullSel).
270
271/*
272 * find_column(+FullSelectors, +Column, -CleanedSelector)
273 * For a given +Column and its presence in +FullSelectors, binds
274 * -CleanedSelector to the standard form table/column
275*/
276
277find_column([Table/Column|_], Column, Table/Column) :- !.
278
279find_column([_/_|T], Column, CleanC) :-
280 find_column(T, Column, CleanC).
281
282/*
283 * full_join(+TableOrTables, -Product)
284 * Unifies -Product with the full join (row) of the given +TableOrTables
285*/
286
287full_join(Tail, Attributes) :-
288 row(Tail, Attributes).
289
290full_join([Tail], Attributes) :-
291 row(Tail, Attributes).
292
293full_join([HeadTable | Tail], Result) :-
294 row(HeadTable, HeadAttributes),
295 append(HeadAttributes, SubAppend, Result),
296 full_join(Tail, SubAppend).
297
298/*
299 * apply_selectors(+CleanSelectors, +FullSelectors, +Row, -Projection)
300 * The provided list of +CleanSelectors is applied to the +FullSelectors
301 * and +Row to select what is required and binds it to -Projection under
302 * the form [Columns]/[Attributes]
303*/
304
305apply_selectors([], _, _, []/[]).
306
307apply_selectors([HeadSel|TailSel], FullSel, Row, [HeadSel|NextSel]/[Attr|NextAttr]) :-
308 nth0(Index, FullSel, HeadSel),
309 nth0(Index, Row, Attr),
310 apply_selectors(TailSel, FullSel, Row, NextSel/NextAttr),
311 !.
312
313apply_selectors(Selector, FullSel, Row, Selector/Attr) :-
314 nth0(Index, FullSel, Selector),
315 nth0(Index, Row, Attr),
316 !.
317
318% TOOLS : OTHER PREDICATES
319/*
320 * print_list(List)
321 * Recursively apply writeln() on the first element of the list
322 * until list is empty
323*/
324
325print_list(List) :-
326 maplist(writeln, List).
327
328/*
329 * prefix_list(+Prefix, +List, -Result)
330 * Prefix each item of the List with Prefix
331 * and binds Result with this new list
332*/
333
334prefix_list(_, [], []).
335prefix_list(Prefix, [Head|Tail], [Prefix/Head | Result]) :-
336 prefix_list(Prefix, Tail, Result), !.
337
338/*
339 * unprefix_list(+List, -Result)
340 * Unrefix each item of the List with elements of the form Prefix/Element
341*/
342
343unprefix_list([], []).
344
345unprefix_list([_/Head|Tail], [Head | Result]) :-
346 unprefix_list(Tail, Result), !.
347
348/*
349 * column_to_index(+Column, +Table, -Index)
350 * From a +Column name and a +Table name,
351 * get the index in the list of attributes
352 * (Indexes are starting from 0)
353*/
354
355column_to_index(Column, Table, Index) :-
356 cols(Table, Cols),
357 nth0(Index, Cols, Column), !.
358
359
360/*
361 * ERROR MESSAGES -> EXCEPTION
362*/
363
364table_exist_error(Table) :-
365 string_concat(Table, " : Table already exists", String), throw(String).
366table_not_exist_error(Table) :-
367 string_concat(Table, " : Table does not exist", String), throw(String).