Commit d8118bb7af72a20275f5d2f72621683f38815889
1 parent
0bccbc29
-
Showing
2 changed files
with
72 additions
and
33 deletions
Show diff stats
anubis_dev/library/data_base/metaSQL.anubis
| ... | ... | @@ -8,25 +8,64 @@ |
| 8 | 8 | Author: Alain Prouté |
| 9 | 9 | Last revision: March 30 2013 |
| 10 | 10 | |
| 11 | - The purpose of this piece of program is to ease the writing of SQL queries, at least | |
| 12 | - from the point of view of their interface to an Anubis program. | |
| 13 | - | |
| 14 | - Indeed, if a table is the result of a SELECT query for example, the data in the table | |
| 15 | - arrive in the form of byte arrays. They have to be converted into integers, strings, | |
| 16 | - dates, and such things. This conversion is not difficult per se but is uses functions | |
| 17 | - which may fail, like for example 'decimal_scan' which returns a 'Maybe(Int)', not an | |
| 18 | - 'Int'. Similarily, if the datum is supposed to be a boolean, it arrives in the form | |
| 19 | - of a byte array containing either the single character 't' or 'f', but for some | |
| 20 | - reason (bad network ...) this may be another byte array. Hence, there are many | |
| 21 | - things to check and programming such conversion functions, while not difficult, | |
| 22 | - is for sure tedious (and possibly error prone). | |
| 23 | - | |
| 24 | - Now, from a formal description of the structure of the database, such conversion | |
| 25 | - functions can generated automatically, and this is what this program does. In order | |
| 26 | - to use it, you have to describe the database using the types defined below, and | |
| 27 | - you have to describe your queries in a similar way. When this is done, this program | |
| 28 | - generates a set of function, one for each query, returning your data in precisely | |
| 29 | - the type which is convenient for using them. | |
| 11 | + The purpose of this piece of program is to ease the transformation of the raw result | |
| 12 | + returned by a SQL SELECT query, which arrives essentially in the form of a list of | |
| 13 | + lists of byte arrays (i.e. an 'untyped' table), into a list of data (one per row of | |
| 14 | + the table) suitable for use in an Anubis program, i.e. with each component of the right | |
| 15 | + Anubis type. Furthermore, the fonctions generated by this program handle possible errors | |
| 16 | + (there is a lot of them) in a clean way. | |
| 17 | + | |
| 18 | + Here is an example. The expression: | |
| 19 | + | |
| 20 | + _SELECT("select3", ["id","title","keywords","source","owner","lastmod"], pgrph_table) | |
| 21 | + | |
| 22 | + represents a SELECT query whose name is "select3", and which asks for the data in the | |
| 23 | + columns named "id", "title", ... from a table named 'pgrph_table'. This program | |
| 24 | + will produce the function: | |
| 25 | + | |
| 26 | + public define MetaSQL_Ret_select3 | |
| 27 | + select3 | |
| 28 | + ( | |
| 29 | + String -> MetaSQL_Answer qf, // the raw query function | |
| 30 | + String where_clause, // actually anything you want to append to the query | |
| 31 | + ). | |
| 32 | + | |
| 33 | + that you can use for executing the "seclect3" query. The type MetaSQL_Ret_select3 is defined | |
| 34 | + automatically as: | |
| 35 | + | |
| 36 | + public type MetaSQL_Ret_select3: | |
| 37 | + error (String message), | |
| 38 | + ok (List(MetaSQL_Row_select3)). | |
| 39 | + | |
| 40 | + where: | |
| 41 | + | |
| 42 | + public type MetaSQL_Row_select3: | |
| 43 | + row(Int id, Nullable(String) title, Nullable(String) keywords, String source, Int owner, Nullable(Int) lastmod). | |
| 44 | + | |
| 45 | + Of course, in order to generate these, the program uses informations taken from a | |
| 46 | + 'description' of the table 'prgph_table'. This description may look like this: | |
| 47 | + | |
| 48 | + define TableStruct prgph_table = | |
| 49 | + table("tb_prgph",with_pk, | |
| 50 | + [ | |
| 51 | + col ("alt", foreign, [indexed, refers_to("tb_prgph")]), | |
| 52 | + col ("module", foreign, [not_null, indexed, refers_to("tb_mod")]), | |
| 53 | + col ("title", vartext, []), | |
| 54 | + col ("comment", vartext, []), | |
| 55 | + col ("keywords", vartext, []), | |
| 56 | + col ("source", vartext, [not_null]), | |
| 57 | + col ("owner", foreign, [not_null, indexed, refers_to("tb_user")]), | |
| 58 | + col ("lastmod", date, []), | |
| 59 | + col ("history", binary, [not_null]) | |
| 60 | + ]). | |
| 61 | + | |
| 62 | + i.e. it records for each column of the table pertinent informations used to generate | |
| 63 | + the types and fonctions. | |
| 64 | + | |
| 65 | + In order to use this program, you have to describe the database using the types | |
| 66 | + defined below, and you have to describe your queries in a similar way. When this | |
| 67 | + is done, this program generates a set of function, one for each query, returning | |
| 68 | + your data in precisely the type which is convenient for using them. | |
| 30 | 69 | |
| 31 | 70 | |
| 32 | 71 | *** (1) How it works ? |
| ... | ... | @@ -37,7 +76,8 @@ |
| 37 | 76 | |
| 38 | 77 | read data_base/metaSQL.anubis (to be put in column 0) |
| 39 | 78 | |
| 40 | - At the end of 'my_metaSQL_queries.anubis' you write something like: | |
| 79 | + Next, you write the complete description of your database (see below), and | |
| 80 | + at the end of 'my_metaSQL_queries.anubis' you write something like: | |
| 41 | 81 | |
| 42 | 82 | global define One (to be put in column 0) |
| 43 | 83 | make_my_queries // this module will generate you query functions |
| ... | ... | @@ -64,9 +104,8 @@ |
| 64 | 104 | |
| 65 | 105 | *** (2) The public types you must be aware of. |
| 66 | 106 | |
| 67 | - The type 'MetaSQL_Scheme' describes SQL queries, not all of them but the most common ones for normal execution | |
| 68 | - of a database (in particular, not those which are reserved to the administrators), and mainly just in the | |
| 69 | - respect of type conversion. According to | |
| 107 | + The type 'MetaSQL_Scheme' describes SQL queries, not all of them but just those which return an | |
| 108 | + answer in the form of a table, i.e. mainly SELECT. According to | |
| 70 | 109 | your needs, you may add alternatives at the end of this type, but preferably, do not modify already |
| 71 | 110 | existing alternatives, otherwise already written metaqueries will have to be modified. Since auxiliary |
| 72 | 111 | types are needed, we first declare the type: |
| ... | ... | @@ -78,7 +117,7 @@ public type MetaSQL_Scheme:... (defined below) |
| 78 | 117 | Sorts of data we can find in the database: (this is of course rudimentary; you may want to extend it) |
| 79 | 118 | |
| 80 | 119 | public type DatabaseType: |
| 81 | - binary, // contains a serialized datum | |
| 120 | + binary, // may contain a serialized datum | |
| 82 | 121 | boolean, |
| 83 | 122 | date, // date without time of day |
| 84 | 123 | foreign, // foreign key to another table (actually an 'Int') |
| ... | ... | @@ -116,7 +155,7 @@ public type PrimaryKey: |
| 116 | 155 | Description of a column: |
| 117 | 156 | |
| 118 | 157 | public type ColumnStruct: |
| 119 | - col (String name, // ordinary column (all but 'id') | |
| 158 | + col (String name, // ordinary column (i.e. all but 'id') | |
| 120 | 159 | DatabaseType type, |
| 121 | 160 | List(ColumnAttribute) attributes). |
| 122 | 161 | |
| ... | ... | @@ -145,9 +184,6 @@ public type MetaSQL_Scheme: |
| 145 | 184 | List(String) column_names, // names of the columns to select |
| 146 | 185 | TableStruct table_description). // description of the table structure |
| 147 | 186 | |
| 148 | - _INSERT(), | |
| 149 | - _UPDATE(), | |
| 150 | - _DELETE(). | |
| 151 | 187 | |
| 152 | 188 | |
| 153 | 189 | The answer to a query is assumed to be of the following type. This means that you |
| ... | ... | @@ -165,7 +201,7 @@ public type MetaSQL_Answer: |
| 165 | 201 | |
| 166 | 202 | *** (3) The metafunction. |
| 167 | 203 | |
| 168 | - We describe the 'metafunction', i.e. the function which actually generates the content | |
| 204 | + Here is the 'metafunction', i.e. the function which actually generates the content | |
| 169 | 205 | of the file 'my_SQL_queries.anubis'. |
| 170 | 206 | |
| 171 | 207 | public define One |
| ... | ... | @@ -177,10 +213,6 @@ public define One |
| 177 | 213 | |
| 178 | 214 | |
| 179 | 215 | |
| 180 | - *** (4) An simple example. | |
| 181 | - | |
| 182 | - | |
| 183 | - | |
| 184 | 216 | |
| 185 | 217 | |
| 186 | 218 | --- That's all for the public part ! ----------------------------------------------------------- | ... | ... |
anubis_dev/library/data_base/metaSQL_test.anubis
| ... | ... | @@ -120,7 +120,14 @@ global define One |
| 120 | 120 | ). |
| 121 | 121 | |
| 122 | 122 | |
| 123 | + Generate 'metaSQL_test_output.anubis': | |
| 124 | + | |
| 123 | 125 | execute anbexec make_my_queries |
| 124 | 126 | |
| 127 | + The next line is just for testing that the generated file compiles ok: | |
| 128 | + | |
| 129 | +read metaSQL_test_output.anubis | |
| 130 | + | |
| 131 | + | |
| 125 | 132 | |
| 126 | 133 | ... | ... |