Commit d8118bb7af72a20275f5d2f72621683f38815889

Authored by Alain Prouté
1 parent 0bccbc29

-

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  
... ...