Create a static AIMMS Library from a runtime library
As you may know, runtime libraries offer enormous flexibility. However, there are situations whereby the same runtime library is generated over and over again. In these situations it is more efficient to generate the runtime library once and persist it. The persisting only needs to rerun, when there is a change in the input defining the runtime library.
An example use case of that is when the context in which the app runs now and then changes slightly, for instance a database schema that changes by adding/removing tables, and/or adding/removing columns in tables.
This article provides an example of generating and persisting such a library on the one hand, and using it in another application. In so doing, this article combines:
How databases can be queried for structure.
How runtime libraries can be used to generate code and persist code from such a structure.
How a DEX Client can be used to obtain a UUID.
How the put statement can be used to create a
project.xml
file.
The Story
In the database, occasionally table columns are added/removed/changed (type) to tables, or even tables are added/removed. To facilitate easy reading of these tables, identifiers are created as follows:
For a column that is a primary key,
a set is created using the same name, but prefixed with
s_
an index is created using the same name, but prefixed with
i_
For a column that is not a primary key,
a parameter is created using the same name, but prefixed with
p_
if the column at hand is a numerical column, andsp_
otherwise.
In addition, the index domain consists of the indices made up from the primary key.
To avoid name clashes due to columns with the same name, but used in different tables, a module is created for every table.
A sample database table may look like:
Example generated code
The generated code for that table alone would be the following module:
1Module modReadTableTableAB {
2 Prefix: thisTableAB;
3 DeclarationSection decls {
4 Set s_NamesA {
5 Index: i_NamesA;
6 }
7 Set s_NamesB {
8 Index: i_NamesB;
9 }
10 Parameter p_Vals1 {
11 IndexDomain: (i_NamesA, i_NamesB);
12 }
13 Parameter p_vals2 {
14 IndexDomain: (i_NamesA, i_NamesB);
15 }
16 StringParameter sp_vals3 {
17 IndexDomain: (i_NamesA, i_NamesB);
18 }
19 DatabaseTable db_TableAB {
20 DataSource: sp_connectionString;
21 TableName: "TableAB";
22 Mapping: {
23 "NamesA"-->i_NamesA,
24 "NamesB"-->i_NamesB,
25 "Vals1"-->p_Vals1(i_NamesA, i_NamesB),
26 "vals2"-->p_vals2(i_NamesA, i_NamesB),
27 "vals3"-->sp_vals3(i_NamesA, i_NamesB)
28 }
29 }
30 }
31 Procedure pr_readThis {
32 Body: {
33 read from table db_TableAB ;
34 }
35 }
36}
The download
Example download with AIMMS 4.92 apps
Once expanded, this example contains the following folders:
data
: a SQLite database and.dsn
file.GenReadLib
an AIMMS application that queries the database for structure in thedata
folder.libs
a folder in which the generated libraries are placed.LeverageReadLib
an AIMMS application that uses a generated library as one of its libraries.
Generating the runtime library
Generating the runtime library uses:
SQLNumberOfTables and SQLTableName to obtain the collection of tables.
SQLNumberOfColumns and SQLColumnData to obtain the columns and their characteristics : name, data type, and whether it is a primary key.
With that information available, generating the runtime library can be coded using model editing procedures.
This is illustrated in the procedures in the section Generate Runtime Lib
of the app GenReadLib
.
More information about runtime libraries can be found at:
Differences between runtime libraries and static libraries
To take advantage of the differences between runtime libraries and static libraries, code for the following is generated as well:
Interface attribute. Here the identifiers declared in the
Public Section
are intended to be used from the outside, the contents of the interface attribute isPublic_Section
.Use of initialization and termination procedures such as
LibraryInitialization
,LibraryPostInitialization
,LibraryPreTermination
, andLibraryTermination
. They are typically not used in runtime libraries, but they are in static libraries. As they are not normally called from outside the library, they are put in a separate section within thePrivate Section
of the library.
Persisting the library
To persist the library, the following functions are used:
The DEX library for consuming REST APIs to make it a client of UUIDTools: the REST API for UUIDs. A UUID is needed in the project.xml file, generated next:
The PUT statement to generate the file
project.xml
.
Using the library
In the leveraging app,
AIMMS MEnu
>File
>Library Manager
you can add theExisting Library
, by pointing to folder containing the library on your disk. In the example, it is located in thelibs
folder next to the folders for the generation and leveraging apps.Direct use by name: In the app
LeverageReadLib
, the procedureMainExecution
can directly reference an identifier in the generated static lib:drl::pr_readAll();