-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.json
252 lines (252 loc) · 165 KB
/
index.json
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
{
"articles/apps-building-gaia-apps.html": {
"href": "articles/apps-building-gaia-apps.html",
"title": "Building apps with Gaia | Gaia Platform Documentation",
"keywords": "Building apps with Gaia After your design phase, the Gaia Platform architecture lends itself best to the following workflow: Create a schema for your application. The schema defines tables and fields that contain the state of your system at any given time. Add tables to manage the state of your application. Determine which columns in the schema drive the behavior. Your Rules act on these fields. In your CMakeLists.txt run gaiac to import the schema and create tables for your database. Gaiac generates a header that contains the Direct Access Classes (DAC) that map your schema in code. You include in this header your Ruleset definition file. Create your Ruleset. Identify the actions to be performed when a field changes. Run gaiat to translate the Ruleset into a C++ file. Create your application and add the gaiat generated C++ file in your app. The Rules Engine generates events when changes are committed to the database. For instance, if a database table stores the state of a sensor, the Rules Engine fires an update/insert event in response to the change of the sensor value. Currently system only supports insert and update events. Events are defined at the source of the change (a sensor's input stream, a schema entry) and a type of event. This is, of course, an iterative process. As you refine your application, you will make changes to the schema and Ruleset. A good start is to add the input table with an Active Field, then add a Ruleset that contains a Rule that fires when rows are inserted. Build from there (iterate) with tables for output and managing the application's state. You define the schema in a Data Definition Language (DDL)file. create table if not exists names ( name string ); create table if not exists greetings ( greeting string ); When you run gaiac, the composer creates the tables in the catalog and outputs header files that you include in your application. When designing your solution for the Gaia Platform, keep in mind that each Rule runs within a separate OS thread, and each thread can only have one outstanding transaction at a time. This provides transaction isolation which means, two simultaneously running Rules (each with a unique thread and transaction) will never see each other's changes. When a rule successfully executes, it automatically commits its transaction. If an exception is thrown within the rule body, the rule engine catches the exception and rollback the current transaction. To state this another way: Rules run on separate threads. When data identified by an Active Field changes, it is possible for your app to check the database before Rules based on the field run. Rules processing is transactional, a Rule must complete before you can see the results of actions due to the changes. Rules only fire after the transaction that contains the change to the Active Field is committed. Said more succinctly, Rules run post-commit. See Also Gaia Data Definition Language"
},
"articles/apps-direct-access.html": {
"href": "articles/apps-direct-access.html",
"title": "Using the Direct Access Classes | Gaia Platform Documentation",
"keywords": "Using the Direct Access Classes The Direct Access Classes (DAC) provide an API that allows you to work directly with the Gaia database in conjunction with the Declarative C++ rules. Gaiac and gaiat generate the headers and API calls that allow you to access data in a copy-free way, transactional, thread-safe way. Accessing a value in a database record in Gaia is as fast as accessing a variable; this sets Gaia apart from most other in-memory databases. This walkthrough models the doctor/patient relationships in a hospital setting. Generating Direct Access Classes You use gaiac to read the schema of a database and generate the Direct Access Classes (DAC) for the tables contained in it. The following shows the contents of a Data Definition Language (DDL) file (hospital.ddl) that contains a simple schema for a database that relates patients to their doctor. database hospital table doctor ( name string, patients references patient[] ) table patient ( name string, height uint8 optional, is_active bool, analysis_results float[], doctor references doctor, address references address ) table address ( street string, city string, patient references patient ) To load the schema contained in the hospital.ddl to the Gaia Catalog and generate the direct access classes, run the following command: gaiac hospital.ddl -d hospital -g The (-g) option tells gaiac to generate the direct access classes, and the (-d hospital) option specifies which database to use. If the DDL is already loaded in the Gaia database, we can run the following command. -o hospital tells to generate the header into the hospital folder: gaiac -d hospital -g -o hospital This set of options generates a hospital folder with three files: hospital/ gaia_hospital.h gaia_hospital.cpp hospital_generated.h gaia_hospital.h: The public header that you include in your code. It defines the direct access API methods that you use. gaia_hospital.cpp: The implementation of gaia_hospital.h. hospital_generated.h: Included by gaia_hospital.h; contains the serialization logic. Typically you will not need to reference this file directly. The filenames are determined by gaiac, and there isn't a provided way to change the names of the output files. The following is a simple example of direct access API usage that creates a doctor record with the name \"Gregory House\" (hospital.cpp): #include <gaia/db/db.hpp> #include \"gaia_hospital.h\" using namespace gaia::hospital; int main() { gaia::db::begin_session(); gaia::db::begin_transaction(); doctor_t::insert_row(\"Gregory House\"); gaia::db::commit_transaction(); gaia::db::end_session(); } Use the following command to manually compile the code: clang++-10 hospital.cpp hospital/gaia_hospital.cpp /usr/local/lib/libgaia.so -I hospital/ -I /opt/gaia/include -lpthread -o hospital_app CMake helper functions The Gaia SDK provides CMake functions to facilitate the integration with the Gaia tools. The function process_schema , within the file cmake/gaia.cmake, handles importing a DDL file and generating the Direct Access classes. project(hospital) # We need pthreads support. set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) find_package(Threads REQUIRED) # Includes the gaia cmake functions include(\"/opt/gaia/cmake/gaia.cmake\") # Generate Direct Access classes from DDL process_schema( DDL_FILE ${PROJECT_SOURCE_DIR}/hospital.ddl DATABASE_NAME hospital ) add_executable(hospital hospital.cpp ) # Automatically adds \"gaia_hospital.cpp\" to the gaia_app target target_add_gaia_generated_sources(gaia_app) target_include_directories(hospital PRIVATE ${GAIA_INC}) target_link_libraries(hospital PRIVATE gaia rt Threads::Threads) Direct Access Classes"
},
"articles/apps-filtering.html": {
"href": "articles/apps-filtering.html",
"title": "Filtering | Gaia Platform Documentation",
"keywords": "Filtering Direct Access provides a filtering API. The core of the filtering API is the where() method exposed by each Gaia container which takes a predicate as input and returns a container with the filtered elements as output. The predicate is expressed as std::function<bool (const T_class&)where T_class is the Direct Access class contained by the container. Lamda predicates You can create arbitrary predicates through Lambda: auto doctors = doctor_t::list().where( [](const doctor_t& p) { return strcmp(p.name(), \"Dr. House\") == 0; }); if (doctors.begin() == doctors.end()) { gaia_log::app().warn(\"No doctors found.\"); return; } // Assuming there is only one result. doctor_t house = *doctors.begin(); Relationship containers also expose the where() method. In this example, we are searching among the patients of a specific doctor: auto patients = house.patients().where( [](const patient_t& p) { return strcmp(p.name(), \"Jack\") == 0; }); if (patients.begin() == patients.end()) { gaia_log::app().warn(\"No patients found!\"); return; } // Assuming there is only one result. patient_t jack = *patients.begin(); Gaia Predicates As part of the Direct Access classes, we generate predicates that are more expressive than raw C++ lambdas. If you look at the doctor_t class, you will see an expr_ section and right outside the class a doctor_exp r namespace. That namespace contains the predicates that you can use instead of the lambdas. class doctor_t : public gaia::direct_access::edc_object_t<...> { ... struct expr_ { static gaia::direct_access::expression_t<doctor_t, gaia::common::gaia_id_t> gaia_id; static gaia::direct_access::expression_t<doctor_t, const char*> name; static gaia::direct_access::expression_t<doctor_t, doctor_t::patients_list_t> patients; }; using expr = expr_<void>; ... }; namespace doctor_expr { static auto& gaia_id = doctor_t::expr::gaia_id; static auto& name = doctor_t::expr::name; static auto& patients = doctor_t::expr::patients; }; Operators on strings String fields support == and != operators, allowing you to rewrite the example above as: auto doctors = doctor_t::list().where(doctor_expr::name == \"Dr. House\"); if (doctors.begin() == doctors.end()) { gaia_log::app().warn(\"No doctors found!\"); return; } // Assuming there is only one result. doctor_t house = *doctors.begin(); auto patients = house.patients().where(patient_expr::name == \"Jack\"); if (patients.begin() == patients.end()) { gaia_log::app().warn(\"No patients found!\"); return; } patient_t jack = *patients.begin(); Operators on numbers Numerical fields support all the basic operators on numerical values: >, >=, <, <=, ==, !=. auto female_patients = patient_t::list().where(patient_expr::is_female == true); gaia_log::app().info(\"There are {} female patients\", female_patients.size()); auto higher_than_160 = patient_t::list().where(patient_expr::height >= 160); gaia_log::app().info(\"There are {} patients higher than 160\", higher_than_160.size()); Operators on containers It is possible to evaluate predicates on relationships. The supported predicates are: contains , empty , count . contains() evaluates to true when a container contains a certain predicate or a specific object. The following example looks for all the doctors that have a specific patient: // Contains with predicate. auto jacks_doctor_container = doctor_t::list().where( doctor_expr::patients.contains( patient_expr::name == \"Jack\")); auto jacks_doctor = *jacks_doctor_container.begin(); gaia_log::app().info(\"Jack's doctor is {}\", jacks_doctor.name()); // Contains with specific object. auto jane = patient_t::get(...); auto jane_doctor_container = doctor_t::list().where( doctor_expr::patients.contains(jane)); auto janes_doctor = *jane_doctor_container.begin(); gaia_log::app().info(\"Jane's doctor is {}\", janes_doctor.name()); empty() evaluates to true if a container is empty. the following example searches for all the doctors with no patients: doctor_t::list().where(doctor_expr::patients.empty()); count() evaluates to true when a container contains the specified number of elements: auto doctors_with_one_patient = doctor_t::list().where( doctor_expr::patients.count() >= 1); for (doctor_t& doctor : doctors_with_one_patient) { gaia_log::app().info(\"{} has at least one patient\", doctor.name()); }"
},
"articles/apps-inside-direct-access-classes.html": {
"href": "articles/apps-inside-direct-access-classes.html",
"title": "Inside the Direct Access Classes | Gaia Platform Documentation",
"keywords": "Inside the Direct Access Classes What's inside the generated code, and how do you use it? If you look inside gaia_hospital.h you will find one c++ class for each table in the specified database (-d hospital) when gaiac was run. Classes are not generated for tables outside of the requested database; you need to rerun gaiac with a different database to generate those classes. The Direct Access Classes map the structure of the DB table at the time of generation. Let's take a look at a simplified version of the patient_t class: typedef gaia::direct_access::edc_writer_t<...> patient_writer; class patient_t : public gaia::direct_access::edc_object_t<...> { public: patient_t() : edc_object_t() {} // Static helpers. static const char* gaia_typename(); static gaia::common::gaia_id_t insert_row(const char* name, uint8_t height, bool is_female); static gaia::direct_access::edc_container_t<c_gaia_type_patient, patient_t> list(); // Primitive type fields. const char* name() const; uint8_t height() const; bool is_female() const; // Relationships. doctor_t doctor() const; address_ref_t address() const; ... private: // You can build objects by calling patient_t::get(gaia::common::gaia_id_t). explicit patient_t(gaia::common::gaia_id_t id) : edc_object_t(id) {} }; The most important aspect of this class is the presence of one method per table column ( name() , height() , is_female() ). You can use these methods to access the column value of a given record. Each Data Definition Language (DDL) type maps to a CPP type. There are methods for relationships too. We will look at those later in the document. Create DB records There are two ways of creating DB records: The insert_row() method. The _writer object. insert_row() accepts a list of values corresponding to the primitive fields. The patient table has three primitive columns name , height , and is_female ; hence you need to specify a value for them all as parameters: gaia_id_t id = patient_t::insert_row(\"Jane\", 183, true); // You can later use the id to lookup the record. The _writer object allows you to specify only some of the values. Values that are not specified are assigned a default value. In this example, we do not specify a height; hence the value will default to 0. patient_writer patient_w ; patient_w.name = \"Jane\"; patient_w.is_female = true; gaia_id_t id = patient_w.insert_row(); For more information on default values, see insert and remove . Retrieve specific DB records In the examples above, we obtained a gaia_id_t as a result of the record creation. You can use the id to retrieve the record: patient_t jane = patient_t::get(jane_id); Note : the get method is not directly exposed by the patient_t class but is inherited from its superclass. Direct Access also provides a filtering API; we'll look into it in the following sections. Each EDC class overrides the bool() operator so that you can evaluate its validity with if: gaia_id_t invalid_id = 12344; patient_t john = patient_t::get(invalid_id); if (john) { gaia_log::app().info(\"Patient name: {}\", john.name()); } else { gaia_log::app().info(\"Cannot find patient with id: {}\", invalid_id); } If you access an invalid record, you get an invalid_object_id exception: patient_t john = patient_t::get(12344); john.name(); terminate called after throwing an instance of 'gaia::db::invalid_object_id' what(): Cannot find an object with ID '0'. Iterate through all table records The list() method exposes an iterator over all the records in a table: for (auto& patient : patient_t::list()) { gaia_log::app().info( \"Patient name:{}, height:{}\", patient.name(), patient.height()); } Delete DB records To delete a record, use the delete_row() method. This method is inherited from the doctor_t superclass. doctor_t house = doctor_t::get(doctor_t::insert_row(\"Dr. House\")); house.delete_row(); if (!house) { gaia_log::app().info(\"The record has been deleted\"); } If you want to remove all the records in a table, you may be tempted to do the following: doctor_t house = doctor_t::get(doctor_t::insert_row(\"Dr. House\")); doctor_t dorian = doctor_t::get(doctor_t::insert_row(\"Dr. Dorian\")); doctor_t reid = doctor_t::get(doctor_t::insert_row(\"Dr. Reid\")); for (auto& doctor : doctor_t::list()) { doctor.delete_row(); } terminate called after throwing an instance of'gaia::db::invalid_object_id' what(): Cannot find an object with ID '0'. This approach does not work because you are modifying the container while iterating over it. One of the correct ways to do this is: for (auto doctor_it = doctor_t::list().begin(); doctor_it != doctor_t::list().end();) { auto next_doctor_it = doctor_it++; (*next_doctor_it).delete_row(); } gaia_log::app().info(\"Num doctors: {}\", doctor_t::list().size()); Num doctors: 0 In the following sections, we will deal with the referential integrity in cases where the doctor is connected to other tables."
},
"articles/apps-relationships.html": {
"href": "articles/apps-relationships.html",
"title": "Relationships | Gaia Platform Documentation",
"keywords": "Relationships In the example DDL, we declare relationships that link the tables. The relationships are reflected in the generated classes the manner as other columns in the table. These are our relationships: doctor 1 --> n patient patient 1 --> 1 address Let's look at the generated code: class address_t : public gaia::direct_access::edc_object_t<...> { public: ... patient_t patient() const; ... }; class patient_t : public gaia::direct_access::edc_object_t<...> { public: ... doctor_t doctor() const; address_ref_t address() const; ... }; class doctor_t : public gaia::direct_access::edc_object_t<...> { public: typedef gaia::direct_access::reference_chain_container_t<patient_t> patients_list_t; ... patients_list_t patients() const; ... }; The methods to access the relationships are named after the identifiers used in the DDL references clause: table doctor ( ... patients references patient[] ) table patient ( ... doctor references doctor, address references address ) table address ( ... patient references patient ) One-to-many relationships Let's consider the doctor 1 --> n patient relationship. The doctor_t class exposes the patients() method which returns a container of patient_t ( patients_list_t) that allows you to iterate over all of the doctor's patients. Each patient_t has a backlink to the doctor: doctor_t doctor() . patients_list_t is a typedef to reference_chain_container_t<patient_t> , which is an internal Gaia type compatible with STL containers. The one side of a 1:n relationship has one of these typedefs for every outgoing relationship. Connecting objects in 1:n relationships To connect objects in a 1:n relationship, you first need to create the objects, and then you can connect them with the insert() method: doctor_t house = doctor_t::get(doctor_t::insert_row(\"Dr. House\")); patient_t jane = patient_t::get(patient_t::insert_row(\"Jane\", 183, true)); patient_t jack = patient_t::get(patient_t::insert_row(\"Jack\", 176, false)); gaia_id_t john_id = patient_t::insert_row(\"John\", 175, false); // Type safe insert. house.patients().insert(jane); house.patients().insert(jack); // Type unsafe insert. house.patients().insert(john_id); gaia_log::app().info(\"Num patients: {}\", house.patients().size()); insert() has two overrides: One that accepts gaia_id_t , which isn't typesafe, and avoids the creation of objects if we already have the Gaia id at hand. One that accepts an instance of a Direct Access class, which is typesafe, and does not allow passing instances of the wrong type. For example, you cannot pass an address to patients().insert() . Traversing objects in 1:n relationships Traversing the relationship is straightforward. You can use the enhanced for loop to iterate through the doctor's patients ( house.patients() ) and use the backlink from patients to access the patient's doctor ( patient.doctor() ): for (auto& patient : house.patients()) { gaia_log::app().info(\"Patient name: {}\", patient.name()); gaia_log::app().info(\"Patient's doctor: {}\", patient.doctor().name()); } Deleting objects in 1:n relationships When you delete objects involved in relationships, you need to consider referential integrity. In the example above, you cannot delete either side of the relationship before disconnecting the instances; if you do so, you'll get an object_still_referenced exception: house.delete_row(); terminate called after throwing an instance of 'gaia::db::object_still_referenced' what(): Cannot delete object with ID '99', type '4211092936', because it is still referenced by another object with ID '102', type '40335167' jane.delete_row(); terminate called after throwing an instance of 'gaia::db::object_still_referenced' what(): Cannot delete object with ID '102', type '40335167', because it is still referenced by another object with ID '99', type '4211092936 ' To avoid the exception, you need to unlink the objects first: // You can unlink a single element (there are still 2 connected). house.patients().remove(jane); // You can now delete the patient. jane.delete_row(); // Unlink all the remaining patients. house.patients().clear(); // You can now delete the doctor. house.delete_row(); One-to-one relationships Let's consider the patient 1 --> 1 address relationship. The patient_t class exposes the address() method, which returns an object of address_ref_t . address_ref_t it's a subclass of address_t , which allows to treat it as an address, but adds methods for linking/unlinking the address. The address class has a backlink to patient_t via the method patient() . Connecting objects in 1:1 relationships To connect objects in a 1:1 relationship, you first need to create the objects, and then you can connect them with the connect( ) method: patient_t jane = patient_t::get(patient_t::insert_row(\"Jane\", 183, true)); address_t kissimmee = address_t::get(address_t::insert_row(\"Hamlet Ln\", \"Kissimmee\")); jane.address().connect(kissimmee); // You can also pass the id: jane.address().connect(kissimmee.gaia_id()); Traversing objects in 1:1 relationships To traverse the relationship, you can use the address() and patient() methods: address_t address = patient.address(); // Actually returns address_ref_t. gaia_log::app().info(\"City {}\", address.city()); gaia_log::app().info(\"Patient {}\", address.patient().name()); Delete objects in 1:1 relationships Similar to 1:n relationships, you cannot delete objects that are in a 1:1 relationship before unlinking them. Otherwise, you'll get an object_still_referenced exception: patient.delete_row(); terminate called after throwing an instance of 'gaia::db::object_still_referenced' what(): Cannot delete object with ID '81', type '40335167', because it is still referenced by another object with ID '82', type '1084090863' address.delete_row(); terminate called after throwing an instance of 'gaia::db::object_still_referenced' what(): Cannot delete object with ID '82', type '1084090863', because it is still referenced by another object with ID '81', type '40335167' To avoid the exception: patient.address().disconnect(); patient.delete_row(); address.delete_row();"
},
"articles/apps-Troubleshooting.html": {
"href": "articles/apps-Troubleshooting.html",
"title": "Troubleshooting | Gaia Platform Documentation",
"keywords": "Troubleshooting Cannot delete object with ID '..', type '...', because it is still referenced by another object with ID '..', type '...' This error occurs when you try to delete an object that is still in a relationship (see Delete objects in 1:n/1:1 relationships). An example of the message could be: Cannot delete object with ID' 98', type '4211092936', because it is still referenced by another object with ID' 101', type '40335167'. What you need to do is to look up what types are '4211092936' and '40335167' using gaiac: gaiac -i > \\l +-----------+-------------------+----+------------+ | Database | Name | ID | Type | +-----------+-------------------+----+------------+ ... +-----------+-------------------+----+------------+ | hospital | doctor | 59 | 4211092936 | +-----------+-------------------+----+------------+ | hospital | patient | 61 | 40335167 | +-----------+-------------------+----+------------+ | hospital | address | 65 | 1084090863 | +-----------+-------------------+----+------------+ 4211092936 → doctor 40335167 → patient This error indicates that somewhere you are trying to delete an object of type doctor that still references a patient. You need to look for that code and explicitly disconnect the doctor object from the patient."
},
"articles/gaia-glossary.html": {
"href": "articles/gaia-glossary.html",
"title": "Gaia Terminology | Gaia Platform Documentation",
"keywords": "Gaia Terminology A Active Fields ( Rules Engine ) These are Database Column names that can be referred to in the body of a Declarative Rule expression. When any code in the system refers to one of these Fields with a read operation an Event ( defined below ) is generated to cause the associated Declarative Rule to be scheduled for execution. Anchor Row (\"Rules Engine\") C Catalog D Declarative Chaining - Forward Chaining ( Rules Engine ) Declarative Chaining is a contract that defines specific automatic computation or transformation that is guaranteed by the system to occur as Fields, represented by nodes in the network, are modified. Forward Chaining describes the 'automatic' recomputation of the values of fields that have defined declarative relationships. When a Field with a declarative Rule defined on it changes at some point in processing, the value of any dependent Fields are reevaluated based on the declarative Rule's definition. This means that Forward Chaining can result in an open ended cascade of Rule firing as the output from one declaratively defined Field is updated by the firing of other Field updates. Forward Chaining performs optimally on Fields that are updated infrequently where the resulting recomputed values are read frequently. Forward Chaining should be used instead of Backward Chaining in these cases. Declarative Rules ( Rules Engine ) Rules that are automatically fired by events when fields are updated. The definition of a declarative Rule does not require a Rule name, but must be annotated as declarative in some way. Upon entry Declarative Rules are parsed to generate the list of Fields that are referenced in the expression. The import and enabling of a Component containing declarative rules causes all referenced fields to be annotated in the schema as 'Active' fields. The field on the right side of the expression is also marked as read-only (for performance sake) since changing it would also immediately queue an event to reset its value. Declarative Rules should be designed to be as light-weight as possible. Forward Chaining allows breaking up complex relationships into multiple rules. E Edge ( Database ) Aliases: Link An edge captures a relationship between two Nodes. The edge metadata captures the type of the nodes that are linked as well as whether the edge is directional or not. An edge may also be thought of as a schematized list of properties. Event ( Rules Engine ) Describes input to the system that Gaia uses to fire a Rule. Events can be generated from incoming sensor data, Database operations (such as a commit), Field updates; pretty much anything that you can attach to a processing action (a Rule). Events are defined at the source of the change (a sensor's input stream, a schema entry) and a type of event. The event also names a Describes input to the system that Gaia uses to fire a Rule. Events can be generated from incoming sensor data, Database operations (such as a commit), Field updates; pretty much anything that you can attach to a processing action (a Rule). Events are defined at the source of the change (a sensor's input stream, a schema entry) and a type of event. The event also names a rRuleule that is to be fired when the specific type of event occurs. that is to be fired when the specific type of event occurs. Ex: Database:Insert, Database:Commit, ML:Identified (a pic), (in the schema)Field x:changed, Sensor Y: Output-Available, etc. Events are managed by a subsystem of the Rules Engine. Data Access Classes G Gaia Declarative Policy Platform Gaia Field Pointer ( Database ) A Gaia Field Pointer provides direct access to a field of a TrueGraphDB entity. Needs discussion about the implementation Gaia ID ( Database )** A persistent identifier of entities stored in TrueGraphDB (nodes and edges, not records). Internally, a Gaia ID maps to a locator, to allow access to its corresponding entity; this mapping is established at database startup or entity creation. Gaia Platform [TBD] Gaia Pointer ( Database ) A Gaia Pointer is an opaque handle that can be used to reference a TrueGraphDB entity. It is implemented as a locator reference. L Locator (Database) An in-memory entity reference. Internally, a locator is implemented as a slot id in a slot table that contains memory offsets. P Policy Set R Record (Database) A record is a basic entity container. Unlike a Node, it cannot be referenced by edges or nodes. Rule ( Rules Engine ) Declarative Rules that are executed automatically in response to access or changes to the values of Fields that they contain references to. When Declarative Rules are created, they generate the metadata required to update the schema with the information required to cause the database to take note of when the associated Fields are changed, and provide the name of the defining Declarative Rule that will be triggered when Fields are accessed. Rule Author ( Rules Engine ) The user who is Authoring Rules to configure the system. Ruleset ( Rules Engine ) This is a logical container for a set of related rules to exist within. Rulesets are named & versioned. These containers will be used for importing and exporting blocks of rules, managing system updates. A Ruleset in an active system can be enabled or disabled; when disabled none of the rules within are visible or executable. Rules Engine ( Rules Engine ) The subsystem that handles the management, code generation and execution of rules."
},
"articles/getting-started-with-gaia.html": {
"href": "articles/getting-started-with-gaia.html",
"title": "Getting Started with the Gaia Platform | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Getting Started with the Gaia Platform NOTE The information contained in this document represents information about prerelease features of the product. Features might change when the product is released for general availability. This document provides guidance on setting up the Gaia SDK, which includes the Gaia Database Server. Prerequisites Before you begin, make sure that you have the following prerequisites: Ubuntu Linux 20.04 An environment that supports the x64 or the arm64 architecture. This can be: A physical machine A virtual machine A subsystem such as Windows Subsystem for Linux The clang compiler version 8 or higher. CMake is the officially supported method for building Gaia applications. In addition, the Gaia SDK uses CMake to automate code generation from Data Definition Language (DDL) and Ruleset files. If you don't currently have cmake and clang installed, you can use the following commands to install them: sudo apt update && sudo apt upgrade && sudo apt install cmake clang To build Gaia examples using CMake and make tools, specify the Clang compiler by setting the following variables in your environment: export CC=/usr/bin/clang-10 export CPP=/usr/bin/clang-cpp-10 export CXX=/usr/bin/clang++-10 export LDFLAGS=\"-B/usr/lib/llvm-10/bin/ -fuse-ld=lld\" Download the Gaia SDK The Gaia SDK is delivered as a Debian software package (DEB): gaia-x.y.z_amd64.deb Where x.y.z represents the Gaia version number. The Gaia SDK includes the Database Server executable and the Gaia Declarative C++ SDK. To download the package, use the URL that you were sent in your welcome email. Install the package You must have sudo privileges to install the package. To install the package: Open a terminal session. Navigate to the folder that contains the downloaded package. At the command prompt, run the following commands; replacing the x.y.z with the correct version number: sudo apt-get update sudo apt-get install ./gaia-x.y.z_amd64.deb During the installation process Gaia asks whether you want to install Gaia server as a systemd service. If you do not install the database as a service, you must run it from the command line prior running the Gaia tools or running a Gaia app. NOTE : The database is configured as a systemd service. On platforms that do not support systemd the request to install as a service is not honored. To reconfigure whether the database is installed as a service, run the following command: sudo dpkg-reconfigure gaia To remove the package: At the command prompt, run the following command: sudo apt-get remove gaia To update the package, remove it and install the updated package: Download the updated package. Remove the currently installed package, run the following command: sudo apt-get remove gaia Navigate to the folder that contains the updated package. After replacing the x.y.z with the version number of the package that you are installing, run the following command: sudo apt-get install ./gaia-x.y.z_amd64.deb Installed components /opt/gaia/bin gaia_db_server - The Gaia Database Server. gaiac - Gaia Catalog Tool. gaiat - Gaia Translation Engine. /opt/gaia/etc gaia.conf - Contains configuration settings for the platform and application loggers that the Gaia Platform uses. gaia_log.conf - Contains configuration settings for the Database Server and rules engine that comprise the Gaia Platform. /opt/gaia/examples/ Example apps. /opt/gaia/include Include files for the Gaia Platform. /opt/gaia/lib Library files for the Gaia Platform. Starting the Gaia server To build or run any solution that is based on the Gaia Platform, the Gaia server must be running . We recommend that you don't run gaia_db_server in production under the root user. As with any daemon process that is accessible to the outside, running the Database Server process as root, or any other account with special access rights, is a security risk. As best practice in production, run Gaia under a separate user account. This user account should only own the data that is managed by the server, and should not be used to run other daemons. For example, using the user nobody is not recommended. To prevent a compromised server process from modifying the Gaia executables, in production the user account should not own the Gaia executable files. When starting the Database Server, we recommend that you use the --data-dir argument to specify the location to store the database and that you create a separate database for each project. When the installer configures the database server to run as a server, it specifies the default database location. To start the server from the command line: gaia_db_server --data-dir .benchmark_db During development and testing it can be useful to start with a clean database. To facilitate this, you can run the server with data persistence disable. To start the server from the command line with persistence disabled: gaia_db_server --persistence disable Gaia server command line arguments: Option Description --persistence <mode> If not specified, the default mode is enabled. The data location is specified with --data-dir. - : Persist data [default]. - : Do not persist any data. - : Load data from the datastore and disable persistence. --data-dir <database-folder-path> Specifies the location in which to store the database. --configuration-file-path <config-file-name> Specifies the location in which to store the Gaia configuration file. --reinitialize-persistent-store All previous changes to the database are deleted from persistent storage and will not be visible after the Database Server is started, Changes to the database made while the Database Server is running will be visible after it is restarted. Configuration settings Overcommit policy The Database Server can run normally with an overcommit policy value of 0 (heuristic overcommit.), but might become unstable under rare conditions. To ensure stable performance under all conditions, we recommend changing the overcommit policy to 1 (always overcommit.) To temporarily enable this policy, open a shell with root privileges and type the following command: echo 1 > /proc/sys/vm/overcommit_memory To permanently enable this policy: Open /etc/sysctl.conf in an editor with root privileges and add the line vm.overcommit_memory=1 Save the file, and in a shell with root privileges type sysctl -p Open file descriptor limit The Database Server requires a per-process open file descriptor limit of at least 65535. To temporarily set the minimum open file descriptor limit, open a shell with root privileges and type the following command: ulimit -n 65535 To permanently set the minimum open file descriptor limit: Open /etc/security/limits.conf in an editor with root privileges and add the following lines: * soft nofile 65535 * hard nofile 65535 Note : For enhanced security, replace the wild card '*' in these file entries with the user name of the account that is running the Database Server. Save the file and start a new terminal session. Starting the Gaia Database Server on a machine that supports systemd To start the server on a machine that supports systemd: sudo systemctl start gaia Starting the Gaia Database Server on Windows Subsystem for Linux (WSL) To start the server on WSL2 running Ubuntu and run it in the background (Gaia has not been tested on WSL1): gaia_db_server --data-dir .<dbname> & Next Steps Building apps with Gaia Write your first Gaia App Learn more about Gaia Rulesets"
},
"articles/reference/da-class-api.html": {
"href": "articles/reference/da-class-api.html",
"title": "Direct Access Classes API | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Direct Access Classes API The Direct Access Classes model the tables in the database. For each table in the database, gaiac generates code for a Direct Access Class (DAC) that includes the following items. Direct Access Classes implements reader and writer classes that provide zero-copy reads and direct references to related records. Since the Gaia database resides in memory, accessing a record is the same as accessing a local variable. This eliminates the need to cache database values in the client code. Accessors The DAC implements an accessor for each field in the table to retrieve the value of the field. For example: const char* doctor_t::field_name1() const uint64_t doctor_t::field_name2() const float doctor_t::field_name3() const bool doctor_t::field_name4() const For information on the full set of supported types, see create table . Examples in these articles are taken from the Direct Access sample app that is installed with the SDK at /opt/gaia/examples/direct_access. Constructors doctor_t:doctor_t() Public default constructor. Creates an empty DAC instance. It is valid to cache DAC across transaction boundaries. The system guarantees that the correct data is maintained. Methods insert_row gaia::common::gaia_id_t doctor_t::insert_row(<field 1>, <field2>,...) Adds a row to the table described by the class. gaia_typename const char* doctor_t::gaia_typename() Returns the class name doctor_t . list gaia::direct_access::edc_container_t<c_gaia_type_address, doctor_t doctor_t::list() Exposes an iterator over all the records in a table. Structure for filtering Provides predicates that you use to filter rows using the container class predicates. Example It this example doctor is the class name that replaces [class name] in the template above. struct expr_ { static gaia::direct_access::expression_t\\<doctor_t, gaia::common::gaia_id_t gaia_id; static gaia::direct_access::expression_t<doctor_t, const char* street; static gaia::direct_access::expression_t<doctor_t, const char* city; static gaia::direct_access::expression_t<doctor_t, patient_t patient; }; In addition, the DAC exposes additional methods that enable you to work with table data. gaia_type gaia::common::gaia_type_t gaia_type() override; Returns the type id for the DAC. get static T_gaia get(gaia::common::gaia_id_t id); Retrieves a specific object of the type T_gaia based on its ID. An exception is thrown if the object represented by the ID is not of type T_gaia . @param ID the gaia_id_t of a specific database object, of type container_type_id . delete_row void delete_row(); Delete the database object. This doesn't destroy the extended data class object. static void delete_row(gaia::common::gaia_id_t id); Delete the database object specified by the ID. has_value has_value(); Returns a boolean indicating whether there is a value in the field. writer doctor_t writer(); Returns a reference that is pre-populated with values from the row. Writer Class API doctor_writer (as a typedef in the generated code) The writer class provides methods that allow you to add, update, and delete rows from DAC. This includes setters for each field in the class. delete_row doctor_t::delete_row() Deletes the current row pointed to by the Direct Access doctor_t object. The following code snippet deletes all the values in the table doctor. for (auto doctor_it = doctor_t::list().begin(); doctor_it != doctor_t::list().end();) { auto next_doctor_it = doctor_it++; next_doctor_it->delete_row(); } insert_row doctor_writer::insert_row Adds a new row in a Direct Access *class name*_t object. update_row doctor_writer::update_row Updates current row pointed to by a DA_t object. Example The following code snippet inserts a new patient and then update his information after the row was inserted. gaia_id_t id = patient_t::insert_row(\"John\", 175, false, nullptr, {}); patient_t john = patient_t::get(id); gaia_log::app().info(\"Patient name is: {}\", john.name()); // Obtain the writer object for an existing record. patient_writer john_w = john.writer(); john_w.name = \"Jane\"; john_w.height = 178; john_w.analysis_results = {1.0, 1.2, 0.3}; john_w.is_active = true; john_w.update_row(); gaia_log::app().info(\"Patient name now is: {}\", john.name());"
},
"articles/reference/da-container-class-api.html": {
"href": "articles/reference/da-container-class-api.html",
"title": "Container Class API | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Container Class API The Direct Access Classes implement a reader and a writer class which provides zero-copy reads and direct references to related records. This allows you to cache values in a local variable without the overhead of performing copy every time you read a field value. The following are exposed as part of the container patient _list_t . Examples in these articles are taken from the Direct Access sample app that is installed with the SDK at /opt/gaia/examples/direct_access. patients_t::list() Methods on the container insert patients_t::insert() - Creates a relationship between the rows. insert() has two overrides: One that accepts a gaia_id_t, which isn't typesafe, and avoids the creation of objects if you already have the Gaia id. One that accepts an instance of a Direct Access class, which is typesafe, and does not allow passing instances of the wrong type. Synonym for disconnect(). remove patients_t::[list_name]().remove() Breaks a relationship between rows. Synonym for disconnect(). connect patients_t::[list_name]().connect() Synonym for connect(). disconnect patients_t::[list_name]().disconnect() Aliased to remove. clear patients_t::[list_name]().clear() Removes all relationships (1 side of 1:1 or N side of 1:N) from this reference. erase patients_t::[list_name]().erase() The erase() method is functionally the equivalent to the disconnect() method except that it takes an iterator that points to the item to disconnect and returns an iterator to the next item in the list. size patients_t::[list_name]().size() Gets the number of linked rows. Example patient_t jane = patient_t::get(patient_t::insert_row(Jane, 183, true)); address_t kissimmee = address_t::get(address_t::insert_row(Hamlet Ln, Kissimmee)); jane.address().connect(kissimmee); // You can also pass the id: jane.address().connect(kissimmee.gaia_id()); void delete_one_to_many_relationship(gaia_id_t doctor_id) { PRINT_METHOD_NAME(); doctor_t doctor = doctor_t::get(doctor_id); // Pick one of the doctor\\'s patients. patient_t patient = *(doctor.patients().begin()); // You can unlink a single element (there are still 2 connected). doctor.patients().remove(patient); // You can now delete the patient. patient.delete_row(); // Unlink all the remaining patients. doctor.patients().clear(); // You can now delete the doctor. doctor.delete_row(); } Methods on Value Linked References patients_t::list().begin() patients_t::list().end() patients_t::list().where() The where() takes a predicate as input and returns a container with the filtered elements as output. The predicate is expressed as std::function bool (const > T_class&) where the T_class is the Direct Access class contained by the container. edc_invalid_object_type : Argument does not match the class type. Example // Contains with expression. auto jacks_doctor_container = doctor_t::list().where( doctor_expr::patients.contains( patient_expr::name == Jack)); auto jacks_doctor = *jacks_doctor_container.begin(); gaia_log::app().info(\"Jack's doctor is {}\", jacks_doctor.name()); // Contains with constant. auto jane = *(patient_t::list().where(patient_expr::name ==Jane).begin()); auto janes_doctor_container = doctor_t::list().where( doctor_expr::patients.contains(jane)); auto janes_doctor = *janes_doctor_container.begin(); gaia_log::app().info(\"Jane's doctor is {}\", janes_doctor.name()); auto doctors_with_no_patients = doctor_t::list().where(doctor_expr::patients.empty()); if (doctors_with_no_patients.begin() == doctors_with_no_patients.end()) { gaia_log::app().info(All the doctors have at least one patient); } ... Operators on containers The following methods are used to evaluate predicates on relationships. contains contains() Evaluates to true when at least one object in the container matches a filter predicate. empty empty() Evaluates to true if a container is empty. count count() Evaluates to true when a container contains the specified number of elements. Example The following code snippet shows the usage of the contains() and empty() methods. // Contains with expression. auto jacks_doctor_container = doctor_t::list().where( doctor_expr::patients.contains(patient_expr::name == Jack)); auto jacks_doctor = *jacks_doctor_container.begin(); gaia_log::app().info(\"Jack's doctor is {}\", jacks_doctor.name()); // Contains with constant. auto jane = *(patient_t::list().where(patient_expr::name == Jane).begin()); auto janes_doctor_container = doctor_t::list().where( doctor_expr::patients.contains(jane)); auto janes_doctor = \\janes_doctor_container.begin(); gaia_log::app().info(\"Jane's doctor is {}\", janes_doctor.name()); auto doctors_with_no_patients = doctor_t::list().where(doctor_expr::patients.empty()); ..."
},
"articles/reference/da-exceptions.html": {
"href": "articles/reference/da-exceptions.html",
"title": "Exceptions | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Exceptions edc_invalid_member A child's parent pointer must match the parent record. edc_inconsistent_list The child refers to a parent but is not found in that parent's list. edc_invalid_state To connect two objects, a gaia_id is needed but not available until create is called during the insert_row() . edc_already_inserted An attempt was made to insert a member that has already been inserted. invalid_object_id An attempt was made by a transaction to reference an object ID that does not exist. no_open_transaction There is no open transaction in this session. transaction_update_conflict The transaction conflicts with another transaction."
},
"articles/reference/da-overview.html": {
"href": "articles/reference/da-overview.html",
"title": "Direct Access API overview | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Direct Access API overview The Direct Access Classes (DAC) provide an API to work directly with the Gaia database. You use gaiac to read a schema from the database and generate the headers that contain the API that you use to access data. For information on loading a schema to the database, see Specifying the Hello database schema in \"Writing your first Gaia application\". Examples in these articles are taken from the Direct Access sample app that is installed with the SDK at /opt/gaia/examples/direct_access. For a discussion of the sample, see Using the Direct Access Classes . There are four classes that you use when interacting with your data: DA class (class_name_t) There is one class generated for each table defined in the database schema. In addition to the DA classes, there are three other classes that are defined that you will use when writing DA code: writer (class_name_writer) reference (class_name_ref_t) -> for 1:1 relationships container (class_name_list_t) -> for 1:n relationships The container class is also used to iterate over all the top-level objects of a specific type in a database. The class_name for each of these class types is the table name listed in the schema. For example, for the following table definition: table doctor ( name string, email string unique, patients references patient[] ) The following classes are generated: Direct Access Class: doctor_t writer class: doctor_writer Container class: doctor_t::patients_list_t To simplify the explanations of the generated classes, the articles in this section will refer to a specific instance of a generated class, address, doctor, or patient as defined in the DDL in the Direct Access sample."
},
"articles/reference/da-reference-class-api.html": {
"href": "articles/reference/da-reference-class-api.html",
"title": "Reference Class API | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Reference Class API Provides access for one-to-one relationships. Examples in these articles are taken from the Direct Access sample app that is installed with the SDK at /opt/gaia/examples/direct_access. class_name_ref_t Reference order is determined by the order of the tables in the Data Definition Language (DDL)). The _ref_t class is only exposed on the first table that specifies the relationship in the DDL. This means that you can change membership of the related records using the first table and not the second. The second table only exposes the table_t type for the 1:1 link and not the table_ref_t type. Referential order - as a basis to replace parent/child) Exposes: Constructor doctor_t(gaia::common::gaia_id_t parent, gaia::common::gaia_id_t child, gaia::common::reference_offset_t child_offset); Connect and Disconnect methods The connect() and disconnect() methods link rows in an explicit relationship . bool connect(gaia::common::gaia_id_t id); bool connect(const doctor_t_t& object); Links rows between two tables based on an existing relationship between the tables. bool disconnect(); bool disconnect(common::gaia_id_t id); Breaks the connection between rows."
},
"articles/reference/ddl-create-database.html": {
"href": "articles/reference/ddl-create-database.html",
"title": "create database | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. create database Optional. Creates a new database. If the database already exists, gaiac returns an error and the database is not created. [create] database [if not exists] database_name; The create keyword is optional. The if not exists keyword is optional. If a database with the same name already exists, the command is ignored. However, there is no verification that the existing database has a structure identical to the one specified by the create database statement. Remarks The create database statement automatically switches you to the new database. There is no need to invoke use if the intention is to create tables in the database that was just created. The short form of the create database statement, in which you omit the create operator, drops the table before attempting to create it and has the same effect as the following: drop database if exists database_nam; create database database_name; Use the interactive feature of gaiac to list the instantiated databases: gaiac> \\ld +-----------+-----+ | Name | ID | +-----------+-----+ | catalog | 1 | +-----------+-----+ | event_log | 40 | +-----------+-----+ | hello | 125 | +-----------+-----+ | flights | 140 | +-----------+-----+"
},
"articles/reference/ddl-create-index.html": {
"href": "articles/reference/ddl-create-index.html",
"title": "create index | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. create index Creates an index that you can use as a field constraint. create unique hash index index_name on table_name(field_name?) Using the unique keyword specifies that the field can only contain unique values. The index name serves as the constraint name. Unique constraints A unique constraint on a table field is defined when creating tables using the following syntax. CREATE TABLE flight ( number INT32 UNIQUE, miles_flown INT32 ); CREATE TABLE flight ( number INT32 CONSTRAINT flight_number_idx UNIQUE, miles_flown INT32 ); Using the unique keyword in the table creation statement is the preferred method to define uniqueness. Note : When inserting multiple rows into a table that has a unique index, you must specify a value for the indexed field with each insert. If you do not specify a value, Gaia will use the default value for the type of the indexed field, which will cause an index collision."
},
"articles/reference/ddl-create-table.html": {
"href": "articles/reference/ddl-create-table.html",
"title": "create table | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. create table Creates a new table. If the table already exists, gaiac returns an error and the table is not created. [CREATE] TABLE [if not exists] table_name ( [ { fieldname datatype [unique][optional] [, ... ] ] ); The if not exists operator is optional. If a table with the same name already exists, the command is ignored. However, there is no verification that the existing table has a structure identical to that indicated by the create table statement. The fieldname parameter specifies the name of a field in the table. The datatype parameter specifies the type of data the field holds (e.g. varchar, integer, date, etc.). Valid data types are: bool - Boolean data type int8 - 8-bit integer Uint8 - unsigned 8-bit integer Int16 - 16-bit integer uint16 - unsigned 16-bit integer int32 - 32-bit integer uint32 - unsigned 32-bit integer int64 - 64-bit integer uint64 - unsigned 64-bit integer float - signed 4-byte floating-point number double - signed 8-byte floating-point number string - A null-terminated vector of bytes up to the limit of the available payload. Typically ASCII or utf-8. Arrays of scalar types. For example, history int32[] . For more information, see Scalar Arrays . Remarks Use the optional `if not exists' to prevent an error from occurring if the table exists. If a table with the same name already exists, the command is ignored. However, there is no verification that the existing table has a structure identical to that indicated by the CREATE TABLE statement. The short form of the create table statement, in which you omit the create operator, drops the table before attempting to create it and has the same effect as the following: drop table if exists table_nam; create table table_name; The following example creates a table named \"department.\" CREATE TABLE if not exists department ( name string, current bool active); Optional values When you declare an optional value in your Data Definition Language (DDL), you can specify both optional and unique. Null values are not considered when evaluating values. Fields that are speicified as optional differ from non-optional in the following manner: If you do not use the optional keyword, Gaia assigns a default value. If you use the option keyword, Gaia assigns a null value. Optional values in Gaia are implemented in the Direct Access Classes using containers that provide functionality similar to C++17 optional values. You can expect an optional value to behave like a C++17 optional. The following table declares the height field as optional. table patient ( name string, height uint8 optional, is_active bool, analysis_results float[], doctor references doctor, address references address ) The following examples show inserting a row that contains no value for the height field and then accessing that field to include it in the log output. void optional_values() { // You can pass nullopt instead of height to denote the absence of value. gaia_id_t id = patient_t::insert_row(\"John\", gaia::common::nullopt, false, {}); patient_t john = patient_t::get(id); // john.height() return a gaia::common::optional_t<uint8> which behaves // similarly to a C++17 std::optional. if (john.height().has_value()) { throw std::runtime_error(\"The value for john.height() should be missing.\"); } else { gaia_log::app().info(\"No height provided for patient {}\", john.name()); } // You can update the missing value with a value. patient_writer john_w = john.writer(); john_w.height = 178; john_w.update_row(); if (john.height().has_value()) { gaia_log::app().info(\"{}'s height is {}\", john.name(), john.height().value()); } else { throw std::runtime_error(\"The height column is supposed to have a value.\"); } } Use the interactive feature of gaiac to list the instantiated tables: gaiac> \\lt +-----------+-------------------+-----+------------+ | Database | Name | ID | Type | +-----------+-------------------+-----+------------+ | catalog | gaia_database | 2 | 4294967291 | +-----------+-------------------+-----+------------+ | catalog | gaia_table | 4 | 4294967294 | +-----------+-------------------+-----+------------+ | catalog | gaia_field | 11 | 4294967295 | +-----------+-------------------+-----+------------+ | catalog | gaia_relationship | 19 | 4294967290 | +-----------+-------------------+-----+------------+ | catalog | gaia_ruleset | 31 | 4294967292 | +-----------+-------------------+-----+------------+ | catalog | gaia_rule | 37 | 4294967293 | +-----------+-------------------+-----+------------+ | event_log | event_log | 41 | 4294963200 | +-----------+-------------------+-----+------------+ | hello | names | 126 | 9 | +-----------+-------------------+-----+------------+ | hello | greetings | 128 | 10 | +-----------+-------------------+-----+------------+ | hello | another_table | 131 | 11 | +-----------+-------------------+-----+------------+ | catalog | gaia_index | 134 | 4294967289 | +-----------+-------------------+-----+------------+ | flights | airplane | 141 | 9 | +-----------+-------------------+-----+------------+ | flights | route | 144 | 10 | +-----------+-------------------+-----+------------+ | flights | flight | 147 | 11 | +-----------+-------------------+-----+------------+ | flights | segment | 154 | 12 | +-----------+-------------------+-----+------------+ | flights | trip | 158 | 13 | +-----------+-------------------+-----+------------+ | flights | traveller | 161 | 14 | +-----------+-------------------+-----+------------+ Gaia provides two ways to connect data in your tables: Explicitly connect tables in your Ruleset code Use references to common fields in your DDL To explicitly connect two tables using references you use the connect statement in your Ruleset code to establish the relationship between the tables. For more information about the connect and disconnect statements, see connect and disconnect . Value Linked References allow to you create links between tables. You can establish a relationship between two tables by specifying fields that, when set to the same value, allows Gaia to automatically relate rows in those tables to each other in either a 1:1 or 1:M relationship. For more information on Value Linked References, see Common fields . You can have 4 types of connections between tables defined in the DDL: A 1:1 relationship which is unidirectional A 1:N relationship which is unidirectional A 1:1 relationship which is bi-directional A 1:N relationship which is bi-directional"
},
"articles/reference/ddl-drop-database.html": {
"href": "articles/reference/ddl-drop-database.html",
"title": "drop database | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. drop database Removes the database from the catalog. drop database database_name;"
},
"articles/reference/ddl-drop-index.html": {
"href": "articles/reference/ddl-drop-index.html",
"title": "drop index | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. drop index Removes the specified index. drop index;"
},
"articles/reference/ddl-drop-table.html": {
"href": "articles/reference/ddl-drop-table.html",
"title": "drop table | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. drop table Removes the table from the catalog. drop table table_name; Important : In the preview version of the database,"
},
"articles/reference/ddl-gaia.html": {
"href": "articles/reference/ddl-gaia.html",
"title": "Gaia Data Definition Language | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Gaia Data Definition Language The Gaia Data Definition Language (DDL) is similar to SQL; many of the platform’s features, such as tables, indexes, and constraints, map naturally to similar or equivalent relational database features. The structure of a DDL file is: /* create database is optional */ [CREATE] DATABASE [if not exists] database_name; /* use is optional */ USE database_name; [CREATE] TABLE [if not exists] table_name ( [ { fieldname datatype [UNIQUE] [, ... ] ] ); NOTE: The create keyword is optional. Use of semicolons Semicolons separate statements in the DDL into logical groupings of create statements. A sequence of statements ending in a semicolon can contain forward references to subsequent statements in the group of statements and any logical groupings that precede it. It can not refer to logical groupings that follow it. Semicolons in the DDL text are optional as long as the DDL file contains only create statements. If semicolons are omitted from the DDL, gaiac compiles the file as if there is a semicolon at the end of the file. No forward references are possible to definitions currently in the schema. Comments in DDL files Single line comment /* comment */ or -- comment Block comment /** Comment **/"
},
"articles/reference/ddl-implicit-relationships.html": {
"href": "articles/reference/ddl-implicit-relationships.html",
"title": "Implicit Relationships | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Implicit Relationships Implicit relationships link rows in tables by defining a relationship between fields in those tables. In the Data Definition Language (DDL) file you specify a Value Linked Reference that will establish the relationship. An implicit relationship is defined similarly to an explicit relationship except that you use a where clause to specify the fields that define the relationship. field_name references table_name [using [table_name].field_name] where table_1.field = table_2.field The relationship is considered implicit because links between rows are created automatically based on the values of their linked fields as specified by the where clause. This relationship is data-dependent: the linked fields in two related rows must have identical values. options using : Indicates the reference in the referenced table for the current reference definition to match. It is only needed when you have more than one reference between the two specified tables. Forward References Forward References allow an identifier to reference an entity whose definition appears after the identifier. In other words, the order of the data definition statements does not matter. In Gaia DDL you build a statement that include a Forward Reference by including all of the statement segments in a single statement terminated by a semicolon. For example, the following DDL segment defines two tables: doctor and patient. The doctor table creates a reference to the patient table, which is defined after the doctor table. create table doctor ( name string, patients references patient[] ) create table patient ( name string, doctor references doctor.patients ); If the doctor table definition is terminated with a semicolon, the compilation of the DDL will fail since the patient table has not yet been defined."
},
"articles/reference/ddl-relationships.html": {
"href": "articles/reference/ddl-relationships.html",
"title": "Relationships | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Relationships Relationships in the Gaia Database allow a row in one table to reference one or more rows in another table. There are two ways to create a relationship between tables: Explicit Relationships Implicit Relationships Explicit Relationships To create an Explicit Relationship you link the rows using the connect() method. To unlink the row you call the disconnect() method. The relationship is considered explicit because you specify links between specific rows in the database, independently of the data in those rows. Implicit Relationships To associate two tables with an Implicit Relationship, specify a Value Linked Reference in the Data Definition Language (DDL) file. When two rows in different tables contain the same value in their linked fields, a link is automatically created between the rows and a relationship is created between the tables. The relationship is considered implicit because links between rows are data-dependent: two rows are linked if the values in their linked fields are identical. For more information on Implicit Relationships, see Implicit Relationships . create Creates a one-to-one or a one-to-many link between tables. [create] relationship [if not exists] relationship_name ( table_name_1.field_name_1 -> table_name_2[], table_name_2.field_name_2 -> table_name_1 [, USING table_name_2(field_name_3,...), table_name_1(field_name_4, ...)] ); options if not exists : Specifies that the relationship is to be created only if a relationship of the specified name doesn't already exist. using : Indicates the relationship in the referenced table for the current relationship definition to match. It is only needed when you have more than one relationship between the two specified tables. The short form of the create relationship statement, in which you omit the create operator, drops the table before attempting to create it and has the same effect as the following: drop relationship if exists foo; create relationship relationship_name; drop drop relationship_name; Removes the specified relationship from the catalog. Remarks The relationship statement adds virtual fields to each of the specified tables. The following examples create relationships named \"incubator_sensors\" and \"incubator_actuators\". create relationship if not exists incubator_sensors ( incubator.sensors -> sensor[], sensor.incubator -> incubator ); create relationship if not exists incubator_actuators ( incubator.actuators -> actuator[], actuator.incubator -> incubator ); In incubator_sensors the incubator.sensors -> sensor[] statement adds a virtual field to the incubators table that links to the sensor.incubator -> incubator statement adds a virtual field to the sensor table that links back to the incubator table. To create a one to one relationship omit the brackets ([]). incubator.sensors -> sensor Use the interactive feature of gaiac to list the instantiated relationships: gaiac> \\lr +----------------------------------+--------------------------+--------------------------------------------+----+ | Name | Parent (link) | Child (link) | ID | +----------------------------------+--------------------------+--------------------------------------------+----+ | gaia_catalog_database_table | gaia_database (database) | gaia_table (gaia_tables) | 10 | +----------------------------------+--------------------------+--------------------------------------------+----+ | gaia_catalog_table_field | gaia_table (table) | gaia_field (gaia_fields) | 19 | +----------------------------------+--------------------------+--------------------------------------------+----+ | gaia_catalog_relationship_parent | gaia_table (parent) | gaia_relationship (outgoing_relationships) | 32 | +----------------------------------+--------------------------+--------------------------------------------+----+ | gaia_catalog_relationship_child | gaia_table (child) | gaia_relationship (incoming_relationships) | 33 | +----------------------------------+--------------------------+--------------------------------------------+----+ | gaia_catalog_ruleset_rule | gaia_ruleset (ruleset) | gaia_rule (gaia_rules) | 42 | +----------------------------------+--------------------------+--------------------------------------------+----+ | gaia_catalog_table_index | gaia_table (table) | gaia_index (gaia_indexes) | 48 | +----------------------------------+--------------------------+--------------------------------------------+----+ | incubator_sensors | incubator (incubator) | sensor (sensors) | 72 | +----------------------------------+--------------------------+--------------------------------------------+----+ | incubator_actuators | incubator (incubator) | actuator (actuators) | 73 | +----------------------------------+--------------------------+--------------------------------------------+----+"
},
"articles/reference/ddl-use.html": {
"href": "articles/reference/ddl-use.html",
"title": "use | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. use Specifies the database to use when compiling the Data Definition Language (DDL). use database_name;"
},
"articles/reference/declarative-connect-disconnect.html": {
"href": "articles/reference/declarative-connect-disconnect.html",
"title": "Connect and Disconnect | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Connect and Disconnect Connect and Disconnect are methods on a field in the class representation of a table in the Gaia catalog. Connect Connect links rows between two tables based on an existing relationship between the tables. [Identifier].field_name1.connect(Table_name2) The identifier can be either a table name or a tag. Table_name1.connect(Table_name2) You can use connect/disconnect directly on tables if there is only one relationship between the two tables. Otherwise, you need to use the link name as defined in the Data Definition Language (DDL). Disconnect Disconnect unlinks the rows. Disconnecting a one to many relationship: [identifier].link_name.disconnect(row) Disconnecting a one to one relationship: [identifier].link_name.disconnect(row) Remarks Connecting rows allows you to navigate from a row to a connected row using a Navigation Path. You can use connect/disconnect directly on tables if there is no ambiguity; otherwise, you need to use the link name as defined in the DDL. You can specify a tag or a table name for the identifier. For more information about Tags, see Tags. Example Connect and Disconnect for a one to one relationship: on_insert(Flight) { // Connect a new flight to an existing passenger. if (/P:Passenger.name == \"Bill Clinton\") { // Equivalent to Fight.passenger_1.Connect(P) passenger_1.Connect(P); } } on_update(Flight) { // Disconnect a passenger from an existing flight if (passenger_1.name == \"Bill Clinton\") { // Equivalent to Fight.passenger_1.Disonnect() passenger_1.Disconect(); } } on_insert(Passenger) { // Connect a new passenger to an existing flight if (/F:Flight.number == 32) { // Equivalent to Passenger.return_flight_1.Connect(F) return_flight_1.Connect(F); break; } } on_update(Passenger) { // Disconnect a flight from an existing passenger if (return_flight_1.number == 32) { // Equivalent to Passenger.return_flight.Disconnect() return_flight_1.Disconnect(); } } on_insert(Flight) { // Connect multiple passengers to a new flight. if (/P:Passenger.name == \"Bill Clinton\" || P.name == \"Greg Fine\" || P.name == \"Wayne Warren\") { // Equivalent to Flight.passengers_M.Connect(P) passengers_M.Connect(P); } } Connect and Disconnect for a one to many relationship: on_update(Flight) { // Remove multiple passengers from an existing flight. if (P:passengers.name == \"Bill Clinton\" || P.name == \"Greg Fine\" || P.name == \"Wayne Warren\") { passengers_M.Disconnect(P); } } on_insert(Passenger) { // Add a flight to a new passenger if (/F:Flight.number == 32) { // Equivalent to Passenger.flight_1.Connect(F) flight_1.Connect(F); break; } } on_update(Passenger) { // Remove a flight from an existing passenger // Equivalent to Passenger->Flight.flight_1.number if (flight_1.number == 32) { // Equivalent to Passenger.flight.Disconnect() flight_1.Disconnect(); } }"
},
"articles/reference/declarative-extentions.html": {
"href": "articles/reference/declarative-extentions.html",
"title": "| Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Gaia's Declarative C++ implements extensions that enable you to write rules that react to changes in the Gaia database."
},
"articles/reference/declarative-for-statement.html": {
"href": "articles/reference/declarative-for-statement.html",
"title": "for(. . . ) | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. for(. . . ) The for statement allows you to iterate over a set of rows in the database: for(table) statement: Executes \"statement\" once for each row in the table. for(Table->Table1) statement: executes the statement once for each row in the 1:m list implied by the Navigation Path The declarative for statement is similar to the range-based for statement in standard C++. `for(range_declaration : range_expression)` The for statement in Gaia’s Declarative C++ has the following differences: A tag specifies the range_declaration. Unlike the standard C++ for, you can declare multiple tags to allow access to multiple \"loop\" variables within the scope of the for. You must specify a tag if you want to reference the rows in the body of the for. The range_expression in the for statement is a table or a path to a table. A label can precede the for statement. You can use the label with the continue and break keywords. An optional nomatch statement can follow the body of the for. Code in a nomatch clause is executed if nothing in the body of the for loop executes. The for statement has the general form of: [label:] for (Table or Navigation Path) { [continue [label]]; [break [label]]; } [nomatch { } Let’s consider a simple example: for(Flight->Segments->Trips->T:Travellers) CheckDocuments(T) This statement causes the system to check the documents for each passenger on a flight. Notice the use of the T as a tag. This effectively translates into: for each Flight for each Segment in the Flight for each Trip in the Segment for each Traveler T in the Trip then checkDocument(T) for (. . .) if (. . .) {. . .} Combine the declarative for with an if to perform filtered iteration on the data. For example: for(T:Travellers) if (T.age>65) {. . .} Fires a rule that applies only to travelers over 65. As before, we can iterate and apply the filter to either an entire table or just to the target of a 1:m relationship."
},
"articles/reference/declarative-if-statement.html": {
"href": "articles/reference/declarative-if-statement.html",
"title": "if Statement | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. if Statement The declarative if statement is very similar to the C++ if statement with two important exceptions. In Gaia a navigation path can return a set of rows over which the if statement will iterate. You can use the break and continue statements to control how iteration proceeds. A nomatch clause is added to indicate when the condition in an if or else-if could not be evaluated if there are no rows returned in the navigation path. If the nomatch clause is omitted and there are no rows, then execution continues with the next statement after the if , as if nomatch {} is specified. A nomatch{} statement is bound to its closest matching if or else-if statement. The if statement has the following form: [label:] if (condition) { [continue [label]]; [break [label]]; } [else if (condition) { [continue [label]]; [break [label]]; }] [else { [continue [label]]; [break [label]]; }] [nomatch] // matches else if { } [[nomatch] // matches if { } The if statement has the following extensions: You can associate a label with the if statement in the form label: . The label must immediately precede the if statement. The break statement is used to terminate the execution of a navigation path iteration. It can reference an optional label to specify where the Rule resumes executing. The label must be pre-declared preceding the if statement. The continue statement causes early execution of the next iteration of the navigation path. It can reference an optional label to specify where the continuation starts from. The label must be pre-declared preceding the if statement. The nomatch statement is optional. The code associated with nomatch is executed if the navigation path returns 0 rows. Every if construct can be associated with a nomatch clause."
},
"articles/reference/declarative-insert-remove.html": {
"href": "articles/reference/declarative-insert-remove.html",
"title": "insert and remove | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. insert and remove Insert and remove are methods on a table in the Gaia catalog. Insert Inserts a row into a table. [Table_name].Insert(field_1: value_1,..., field_2: value_2) Table_name: a table in the Catalog. The parameters to the insert statement set the fields in a row of the specified table. If you do not specify the value for a field in the table Gaia inserts a default value; 0 for numeric fields and an empty string for string fields. The insert statement only allows inserting into primitive types. Example Schema: create table if not exists flight ( airline string, departure_time int64, arrival_time int64, flight_number int64 ); create table if not exists passenger ( first_name string, last_name string, has_ticket boolean, flight references flight ); Example // Note that the following methods do not list all the parameters. flight.insert( airline: \"Alaska\", flight_number: 23 ) td::string auto tengiz = passenger.insert( first_name: \"Tengiz\", last_name: \"Kharatishvili\" ) remove Removes one or more rows from a table. [Table_Name].remove() : Removes the current row based on the anchor and the reference, on_update(p:passenger) { p.remove(); } Note : Attempting to remove a row that is currently connected will result in an error. Call disconnect() first and then remove the row."
},
"articles/reference/declarative-on_change.html": {
"href": "articles/reference/declarative-on_change.html",
"title": "on_change | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. on_change Specifies that the rule fires when there is an insertion or change of a row that contains the specified fields in the specified table. Syntax: on_change(field1, field2,..., fieldn){ . . . } field: A comma separated list of fields in the database to watch for changes. All fields specified in the must be from the same table. on_change(table){ . . . } table: Specifies the table to watch for changes in the database."
},
"articles/reference/declarative-on_insert.html": {
"href": "articles/reference/declarative-on_insert.html",
"title": "on_insert | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. on_insert Specifies that the rule fires on the insertion of a row in the specified table. Syntax: on_insert(table){ . . . } table: Specifies the table in the database to watch for insertions. Remarks: Unlike the other On prefixes, on_insert takes a single parameter that must be a table name. Example // Rule 1: Whenever a name is inserted, // insert a new greeting into the greetings table. on_insert(names) { // Form the greeting using the name. string new_greeting = \"Hello \" + string(names.name) + \"!\"; // Insert the greeting. gaia::hello::greetings_t::insert_row(new_greeting.c_str()); }"
},
"articles/reference/declarative-on_update.html": {
"href": "articles/reference/declarative-on_update.html",
"title": "on_update | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. on_update Specifies that the rule fires when a change occurs to the specified fields in existing rows in a table or a change to a specified table. Syntax: on_update(Field names){ . . . } Field Names: A list of comma separated field names in the format: field1, field2, …, fieldn. on_update(table name){ . . . } table name: The name of the table. If any field in the table changes, Gaia fires the rule. Remarks If the fields are unique in the Catalog, you can omit specifying which table they are in. Example // Rule 2: Verify the temperature is kept in range if the // incubator temperature limits change. on_update(incubator.max_temp, incubator.min_temp) { if (!incubator.is_on) { return; } sensor_loop: for (S:sensor) { if (S.value < min_temp || S.value > max_temp) { for (A:actuator) { A.value = adjust_temperature(min_temp, max_temp, S.value, A.value); A.timestamp = g_timestamp; } break sensor_loop; } } }"
},
"articles/reference/declarative-rule_context-structure.html": {
"href": "articles/reference/declarative-rule_context-structure.html",
"title": "rule_context structure | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. rule_context structure Contains rule specific information that you can use to log which rule fired. rule_context.rule_name rule_context.ruleset_name rule_context.event_type rule_context.gaia_type rule_name The ordinal corresponding to the Rule name. ruleset_name A string containing the name of the Ruleset. event_type An event_type_t enumeration value gaia_type The numeric type ID of the rule. Remarks You can view the Gaia type by running gaiac in interactive mode and using the list \"\\l\" commands."
},
"articles/reference/declarative-serial_group.html": {
"href": "articles/reference/declarative-serial_group.html",
"title": "serial_group | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. serial_group Specifies that all of the Rules within the Ruleset are guaranteed to be serialized. The optional group_name parameter allows you to use the serial_group attribute in multiple Rulesets to ensure that all of the Rules in the Rulesets that specify the same group_name are serialized as a group. The serial_group attribute has the following form: ruleset ruleset_name : serial_group(group_name) group_name: An optional identifier that Gaia uses to group rulesets for serializing. Remarks Gaia's default execution model is to run Rules in parallel. Your application could contain Rules that need to be run sequentially. For example, your app has a single field that must have a guaranteed to be correct value. To ensure that this value is only modified by one instance of a rule at time, use the serial_group attribute. To specify that all of the Rules within a Ruleset are serialized, use the serial_group attribute as part of the Ruleset header. If you have multiple Rulesets that must be serialized, use the optional group_name parameter to ensure that all of the Rules from all Rulesets with the matching group_name are treated as a single set of serialized rules. Note : When specifying the serial_group attribute, the rules are run strictly in the order in which they fire. This includes separate instances of the same rule. Example ruleset BuildingPopulationTracker : serial_group(Pop_Tracker) { on_update(scan badge_scan) { building.visitors++; building.population++; } on_update(scan badge_exit_scan) { building.population--; } } Where the scan has a reference to the building that it is in and the building has a field to track the number of people entering and leaving via entry and exit badge scans. We’re also tracking the number of visitors to date, because why not? Feel free to change this up, but this is the essential requirement - we have a single field that we need to have a guaranteed-to-be-correct (fire insurance requirement?) value for."
},
"articles/reference/declarative-tables.html": {
"href": "articles/reference/declarative-tables.html",
"title": "tables | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. tables Specifies the tables in the catalog from which fields are referenced. The tables attribute has the following form: tables(name1,. . .) By using the tables attribute you ensure disambiguation both immediately, and later if you add tables to the database that use the same field names."
},
"articles/reference/declarative-while-do-while.html": {
"href": "articles/reference/declarative-while-do-while.html",
"title": "while and do while | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. while and do while The while and do while statements allow you to iterate over a set of rows in the database. while (Table->Table1) { …} do {...} while(Table->Table1) Remarks The navigation path does not guarantee the order of the returned results. Tags and navigation paths and tags in while loops: References or navigation paths that result in an iteration are not allowed in the condition of a while expression. Tag declarations are not allowed in the while loop. It is permissible to use a tag that is already declared in an enclosing scope. Note : Labels on while() , do-while() statements are not supported."
},
"articles/reference/index.html": {
"href": "articles/reference/index.html",
"title": "Gaia Reference | Gaia Platform Documentation",
"keywords": "Gaia Reference NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability."
},
"articles/release-notes.html": {
"href": "articles/release-notes.html",
"title": "Release Notes | Gaia Platform Documentation",
"keywords": "Release Notes Version 0.4.0.0-beta 02/07/2022 Added C++17 style optional value support allowing for null values. Added Scalar optional scalar values support in DDL. Improvements in rule translation to make writing rules more intuitive. Relaxed referential integrity restraints to allow the deletion of connected nodes. The delete_row public API now accepts an additional optional parameter to force the deletion of connected parent nodes. If the catalog encounters a fatal exception, gaiat now emits single diagnostic rather than a full dump of internal gaiat errors. Refactored expressions into their own namespace. Fixed an error where using #define in a rule caused a compilation error. Changed the parameter name for autotransaction_t from auto_begin to auto_restart . Installing the Gaia SDK no longer installs Clang. Version 0.3.1.0-beta 10/15/2021 The drop table command, in both it's long and short form does not remove any existing records from the database. The database will be in an inconsistent state since the catalog entries will not match that data in the database and any data operation can fail or have unintended results. Before dropping a table, you should first programmatically remove all records from the table."
},
"articles/rulesets-analyzing-rules.html": {
"href": "articles/rulesets-analyzing-rules.html",
"title": "Analyzing your rules | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Analyzing your rules Rule Statistics The rules engine logs statistics according to settings in the `gaia.conf` configuration. The following options determining logging behavior: Option Default if Unspecified Description stats_log_interval 10 seconds The interval in seconds for how frequently the rules engine logs statistics. All stats (counts, averages, etc) are calculated anew for each interval. log_individual_rule_stats False If set to true, then in addition to rollup statistics for all rules, the same statistics are calculated for each Rule. Here is sample output when of the Rule_stats log when individual Rule statistics are not collected: 2020-11-30T15:15:37 30026 <rules_stats>;: ------------------------- sched invoc pend aband retry excep avg lat max lat avg exec max exec 2020-11-30T15:15:37 30026 <rules_stats>;: thread load: 0.49 % 21 21 0 0 0 0 15.26 ms 23.59 ms 1.46 ms 9.31 ms 2020-11-30T15:15:47 30026 <rules_stats>;: thread load: 0.65 % 30 30 0 0 0 0 13.66 ms 19.66 ms 0.28 ms 7.01 ms For example, the first data row shows that 21 rules were scheduled and 21 rules were invoked. If individual Rule statistics are turned on, sample output might look like: 2020-11-30T15:13:25 28975 <rules_stats>: ------------------------- sched invoc pend aband retry excep avg lat max lat avg exec max exec 2020-11-30T15:13:25 28975 <rules_stats>: thread load: 0.73 % 28 28 0 0 0 1 15.11 ms 24.91 ms 0.74 ms 10.61 ms 2020-11-30T15:13:25 28975 <rules_stats>;: incubator_ruleset::1_sensor 27 27 0 0 0 1 15.25 ms 24.91 ms 0.77 ms 10.61 ms 2020-11-30T15:13:25 28975 <rules_stats>;: incubator_ruleset::3 1 1 0 0 0 0 11.30 ms 11.30 ms 0.01 ms 0.01 ms Here we see that of the 28 scheduled/invocations in this time interval, the rules engine invoked incubator_ruleset::1_sensor 27 times and incubator_ruleset::3 once. Rule Tracing To display the rules traces to the console, edit your gaia_log.conf file and add the following entry: logger name = \"rules\" sinks = \"console\", \"file_rotating\" level = \"trace\" Sample output from on console will appear similar to the following: 2020-11-30T15:35:33-08:00 trace 30862 30878 <rules>: call: incubator_ruleset::1_sensor 2020-11-30T15:35:33-08:00 trace 30862 30874 <rules>: call: incubator_ruleset::1_sensor 2020-11-30T15:35:33-08:00 trace 30862 30878 <rules>: return: incubator_ruleset::1_sensor 2020-11-30T15:35:33-08:00 trace 30862 30874 <rules>: return: incubator_ruleset::1_sensor Note that the first number following \"trace\" is the process id. The second number is the thread id. If an exception occurs, the tracing displays output similar to the following: 2020-11-30T15:46:34-08:00 trace 31036 31068 <rules>: exception: incubator_ruleset::2, The rules engine has not been initialized yet."
},
"articles/rulesets-cursors-in-gaia.html": {
"href": "articles/rulesets-cursors-in-gaia.html",
"title": "Cursors in Gaia | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Cursors in Gaia When getting a list of records from the database, Gaia gets a dynamic cursor to access the data. This means that all changes to the data are immediately visible to the transaction making the changes. The current Rule has a 'live view' of the data to process based on the data in fields that are being modified and the declarative language operates as if the Rule is operating on 'local data'. When writing Rules, be aware that when the execution of the Rule adds new rows to that list, these changes are also seen 'live' in the results coming back from the database. Situations can occur where you are adding rows that are then processed resulting in adding rows and your app can enter an endless loop of processing data."
},
"articles/rulesets-gaia-ddl.html": {
"href": "articles/rulesets-gaia-ddl.html",
"title": "Rulesets and Gaia DDL | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Rulesets and Gaia DDL Every Rule must refer to a catalog entity defined in the DDL for that application. Although Data Defintion Language (DDL) source code and Rule source code exist in separate source files and are compiled and translated separately (DDL first, followed by rules), they are always considered together when reading a Rule's logic. It follows that a DDL change forces a re-translation of the rules that refer to the catalog entries generated by the DDL. In addition to identifying the names of tables and the fields within those tables, the DDL defines the relationships between tables. Unless the DDL shows a relationship between two tables, there can be no navigation directly from one to the other. For more information on the Gaia DDL, see Gaiac and DDL ."
},
"articles/rulesets-gaia-programming-model.html": {
"href": "articles/rulesets-gaia-programming-model.html",
"title": "Gaia programming model | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Gaia programming model Gaia's Declarative C++ operates on Active Fields that are described in the Catalog. Active Fields are references to the columns described in the database schema. In addition, you can define local C++ variables to provide temporary storage during the processing of a Rule. For clarity, this document refers to local C++ variables simply as variables and Active Fields as field references. Gaia enables you to write multi-threaded applications with components that execute asynchronously and in parallel with each other. When multiple database events, either insertion of or changes to fields, occur simultaneously, any corresponding rules associated with those fields fire automatically in parallel. Binding Rulesets to a named thread using the SerialStream method allows only one Rule in the SerialStream to execute at a time. This allows each Rule in the SerialStream to see the committed changes of the previous one. A Rule operates in the context of an anchor row from the database. It is the row that changes that prompted the Rule to fire. The definition of the table for this anchor row drives the interpretation of all references to fields and anchor-related tables in the database. There can be only one anchor specified for a Rule. Active Fields An Active Field is a reference to a field defined in the Gaia Catalog that causes any Rule containing the field reference to fire when its value changes in the database. You can designate any field defined in the Catalog as active in your rules. You can specify which fields are active in two ways: By specifying fields in an on_update or on_change attribute: on_change(person.location){ ... } By prepending an @ symbol to the field: if (@person.location == some_location) … Many of the rules you will write will be very short with one or two Active Fields, and in those cases, using the @ syntax can keep your code readable and concise. If your Rule is more complex, keeping track of the field references using the @ identifier method can become confusing. In this case, identifying all of the field references using an 'On' attribute keeps your rules cleaner and allows you to identify all of the Active Fields at a glance. All active fields must be part of the same table in a single Rule. Gaia Platform does not support \"multi-anchor\" rules. NOTE : These two methods of specifying the field references in a Rule are mutually exclusive. If you inadvertently mix them, gaiat notifies you with the following error message: \"Since a Rule attribute was provided, specifying Active Fields inside the Rule is not supported.\" At the beginning of each Ruleset, you can use the optional Table attribute to specify which tables in the Catalog that Gaia uses to disambiguate field references: table(table1, table2, ...): This helps ensure disambiguation immediately and later if you add other tables with the same field names to the database. The table name is a qualifier specifying the table that contains the field name being referenced. A period '.' is required to separate this qualifier from the rest of the reference. This qualifier is optional and can be omitted whenever the associated field name is unique within the table scope for this Ruleset. Ruleset Structure Rules are created by authoring text files with the extension .ruleset. In the source file, Rulesets are defined using the ruleset name { . . . } syntax. Each Ruleset name must be unique so that it can be tracked and managed through the Catalog. Rulesets should encapsulate a set of rules for a common purpose. That purpose can be anything from the rules for a small application to independent units of business or application logic. Rule structure Each Rule is bracketed {. . .} to delineate the scope of the Rule. The body of a Rule contains a mix of C++ statements and declarative statements. The C++ is unrestricted, so any valid statements are permitted. The declarative statements can contain field references. The way to think about references is that they are predefined variable references to fields defined in the Catalog that are globally visible to the rules you define. The reference is to either the 'current' row for which the rules engine fires the Rule (the Anchor Row) or the row(s) referenced in another table with a relationship with the Anchor Row. The Anchor Row specifies the starting point for the data that the Rule processes. The general structure is: <filename>.ruleset ruleset <rulesetname1> { { rule code } { rule code } } ruleset <rulesetname2> { { rule code } { rule code } } Note : While the structure of Ruleset code is similar C++ there are differences. Specifically, within the body of a Ruleset, no code is permitted outside of rule definitions. For example, the following Ruleset psuedocode defines a variable, x, which does not belong to any rule and is therefore not permitted: Maybe, \"no code is permitted outside of rule definitions\"? And then, for example the int x does not belong to any rule and is therefore not allowed ruleset sample_ruelset { int x; { rule code } { rule code } } Field Names Every field reference is to a field of a row in a table. To ensure that your field names are unambiguous, qualify them with the table name. However, Gaia also allows for unqualified field names. If a field name is unique across all tables, you can use it without qualification. If a field name occurs in more than one table other than in a key reference, you must qualify it with the table name. The translation engine flags cases when the qualification is necessary. As the definition of your database changes and expands, a previously unique field name can become ambiguous. The Gaia translation engine reports these cases out so that you can decide how to address them. on_xxxx Rule prefixes The on_xxxx prefix specifies the fields or tables that cause the Rule to fire when a row or a field changes. If the fields are unique in the Catalog, you can omit specifying the table in which they are defined. In either case, all of the fields specified must be defined in the same table. The arguments to on_xxxx consist of a set of table and field references. The Rule on_change(Traveller){. . . } causes the Rule to fire whenever a row changes in the Traveller table. The Rule on_update(Traveller.MemberMiles, Traveller.MemberLevel){. . .} causes the Rule to fire when either of the fields change. There are three forms of On: on_update (field1, field2, …, fieldn){ . . . } or on_update(table){ . . . }: Reacts to the change of the specified fields in existing rows in a table or a change to a specified table. If the fields are unique in the Catalog, you can omit specifying which table they are in. on_change (field1, field2,..., fieldn){ . . . } or on_change(table){ . . . }: Reacts to the Insertion or change of a row that contains the specified fields in the specified table. on_insert (table){ . . . }: Reacts to the insertion of a new row. Unlike the other On prefixes, on_insert takes a single parameter. // Rule 1: Whenever a name is inserted, // insert a new greeting into the greetings table. on_insert(names) { // Form the greeting using the name. string new_greeting = \"Hello \" + string(names.name) + \"!\"; // Insert the greeting. gaia::hello::greetings_t::insert_row(new_greeting.c_str()); } The on_xxxx prefix provides a finer-grained control on the kind of data change that fires a Rule. Additionally, the on_xxxx prefixes are more flexible than the '@'. They allow you to define rules that address active fields that are part of an Update vs an Insert, whereas '@' always behaves like on_change. You might also find that as rules grow more complex, the on_xxxx() prefix aids in readability and understanding among different developers."
},
"articles/rulesets-gaia-rulesets.html": {
"href": "articles/rulesets-gaia-rulesets.html",
"title": "Gaia Rulesets | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Gaia Rulesets Overview Gaia applications are built around sets of rules interacting tightly with a database. The Gaia programming environment enables intermixed declarative and procedural code. There are many approaches to declarative programming, each of which can provide programmer productivity gains. Gaia declarative programming focuses on policy-based applications. Gaia extends C++ with declarative programming functionality. These declarative extensions couple directly with Gaia's in-memory database, where you can model your application’s state and data. When the data changes, declarative policies are immediately dispatched to trigger high-speed, responsive behavior. Policies are expressed as rules. In Gaia, Rules react to changes to the database. When the data changes, the Gaia rules engine fires an event, which causes the body of the Rule to fire. This allows you to focus on what behavior you want; not how it gets implemented. This means that you define the logic behind your goals without needing to describe the control flow. Rules are encapsulated in Rulesets. The Gaia rules engine manages the execution of the Rules across all the Rulesets of your application. It fires rules by following the data change events made to the Gaia database from both other Rules and the procedural code of your application. The Declarative System What makes rules declarative is that the rules engine determines the execution order based on each rule’s definition and its use of the database. Thus, in a declarative system, the programmer is relieved of the need to specify the flow of control between rules manually. The declarative nature of Gaia makes it possible to write applications with much less code. There are several ways that Gaia makes this possible. Gaia eliminates most of the complex control flow; the platform resolves that for you. Additionally, the declarative system understands the database; this allows Gaia to accomplish the following tasks without you having to provide code: Navigation across and between tables is automatic. In many cases, accessing sets of rows and changing sets of rows is as simple as it is for single rows. The entire system depends on the fact that the Catalog fully describes the structure of the active database. The Catalog is the Gaia system component that manages interactions between your code and the database. The names and types of all fields are rowed there. In addition, the relationships between all the rows/tables are in the Catalog too. The Catalog makes it possible for row navigation to be invisible and automatic in declarative code. When a value in the database changes, Gaia consults the Catalog and fires the rules that are associated with the field. The Rule starts at the correct row, so no code is required to get there. It is the rules engine that decides which Rule to fire, not code that you provide. When writing your declarative code, keep in mind that each Rule runs within a separate OS thread, and each thread can only have one outstanding transaction at a time. This provides transaction isolation. Two simultaneously running rules (each with a unique thread and transaction) will never see each other's changes. Before the rest of the system can see the actions resulting from the Rule, the Rule must exit to commit the transaction. To state this another way: Rules run on separate threads. When data identified by an Active Field changes, your app can check the database before rules based on the field run. Rules processing is atomic. A Rule must complete execution before you can see the results of actions due to the changes."
},
"articles/rulesets-navigation-paths.html": {
"href": "articles/rulesets-navigation-paths.html",
"title": "Navigation Paths | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Navigation Paths In Gaia, references to a field in the database can take two forms: A Direct Reference to a single row and field. A Navigation Path that refers to a set of related data through table relationships and can represent 0, 1, or more results. You can declare a Navigation Path explicitly as a path through data relationships expressed as references. While this allows you to identify each relationship and to know exactly how the Path is constructed, it can result in long, unwieldy names that reduce comprehension. An explicit Navigation Path defines the path based on the relationships defined your Data Definition Language (DDL) file. Alternatively, you can choose to use abbreviated Navigation Paths. When Gaia can derive the references from the schema defined in the DDL, you can omit the explicit segments in the path to create an abbreviated Navigation Path. This can result in clearer and simpler Rule code. A Rule statement can contain multiple Navigation Paths. Each Navigation Path in the statement can expand to 0 or more results. This means that the number of times the statement executes can be the product of the result counts of each Navigation Path. For example, if a statement contains three Navigation Paths, with result set sizes 3, 1, and 15, the statement might execute up to 3x1x15 times. The following Ruleset example shows two rules that contain a multi \"segment\" path. The first rule iterates using explicit navigation while the second rule iterates using implicit navigation. Each Rule fires when the clinic is closed. ruleset clinics_ruleset { on_update(clinic.closed) { if(closed==true) { for(C:clinic->D:doctor->P:patient) { gaia_log::app().info( \"{} patient of doctor {} in clinic {} notified of closure using explicit navigation.\", P.name, D.name, C.name); } } else { gaia_log::app().info( \"{} is open. All patients welcome.\", clinic.name); } } on_update(clinic.closed) { if(clinic.closed==true) { gaia_log::app().info( \"{} patient of doctor {} in clinic {} notified of closure using implicit navigation.\", C:clinic->D:doctor->patient.name, D.name, C.name); } } } In the following sample run, there are two clinics. Each clinic as two doctors, each of which has two patients. When a Rule fires, it iterates four times; once for each patient. [2022-01-18T12:54:04.289] [info] [12886 12886] <app>: Setting Mal's Practice to closed. [2022-01-18T12:54:04.290] [info] [12886 12886] <app>: Setting Doc in the Box to closed. [2022-01-18T12:54:04.290] [info] [12886 12913] <app>: Leela patient of doctor Who in clinic Mal's Practice notified of closure using explicit navigation. [2022-01-18T12:54:04.290] [info] [12886 12908] <app>: Leela patient of doctor Who in clinic Mal's Practice notified of closure using implicit navigation. [2022-01-18T12:54:04.290] [info] [12886 12913] <app>: Rose patient of doctor Who in clinic Mal's Practice notified of closure using explicit navigation. [2022-01-18T12:54:04.290] [info] [12886 12908] <app>: Rose patient of doctor Who in clinic Mal's Practice notified of closure using implicit navigation. [2022-01-18T12:54:04.290] [info] [12886 12913] <app>: Clea patient of doctor Strange in clinic Mal's Practice notified of closure using explicit navigation. [2022-01-18T12:54:04.290] [info] [12886 12908] <app>: Clea patient of doctor Strange in clinic Mal's Practice notified of closure using implicit navigation. [2022-01-18T12:54:04.290] [info] [12886 12913] <app>: Wong patient of doctor Strange in clinic Mal's Practice notified of closure using explicit navigation. [2022-01-18T12:54:04.290] [info] [12886 12908] <app>: Wong patient of doctor Strange in clinic Mal's Practice notified of closure using implicit navigation. [2022-01-18T12:54:04.291] [info] [12886 12886] <app>: Setting Mal's Practice to open. [2022-01-18T12:54:04.291] [info] [12886 12912] <app>: Maurice patient of doctor Bombay in clinic Doc in the Box notified of closure using explicit navigation. [2022-01-18T12:54:04.291] [info] [12886 12909] <app>: Maurice patient of doctor Bombay in clinic Doc in the Box notified of closure using implicit navigation. [2022-01-18T12:54:04.291] [info] [12886 12912] <app>: Samantha patient of doctor Bombay in clinic Doc in the Box notified of closure using explicit navigation. [2022-01-18T12:54:04.291] [info] [12886 12909] <app>: Samantha patient of doctor Bombay in clinic Doc in the Box notified of closure using implicit navigation. [2022-01-18T12:54:04.291] [info] [12886 12912] <app>: Mayfair patient of doctor Savage in clinic Doc in the Box notified of closure using explicit navigation. [2022-01-18T12:54:04.291] [info] [12886 12909] <app>: Mayfair patient of doctor Savage in clinic Doc in the Box notified of closure using implicit navigation. [2022-01-18T12:54:04.291] [info] [12886 12912] <app>: Littlejohn patient of doctor Savage in clinic Doc in the Box notified of closure using explicit navigation. [2022-01-18T12:54:04.291] [info] [12886 12909] <app>: Littlejohn patient of doctor Savage in clinic Doc in the Box notified of closure using implicit navigation. [2022-01-18T12:54:04.291] [info] [12886 12886] <app>: Setting Doc in the Box to open. [2022-01-18T12:54:04.291] [info] [12886 12911] <app>: Mal's Practice is open. All patients welcome. [2022-01-18T12:54:04.292] [info] [12886 12919] <app>: Doc in the Box is open. All patients welcome. Navigation Paths occur when a Rule contains a reference to a field in the database. For example, we this field from the baggage handler scenario described in Writing Rules with Gaia Declarative C++ : @Traveler.MemberMiles This essentially says: Select the MilesFlown from Traveler for the current anchor row. Navigate: flight->segment->trip->traveller Iterate: flight->segment is 1:m -- update all passengers on flight A Navigation Path iterates over the set of rows related to the anchor. To iterate over all of the rows in a table, independent of any relationships, use the \"/\" operator. flight->Segment->Trip->Traveler You can use multiple navigation paths in a single statement. This creates multiple iterations of the returned sets of rows which are evaluated from left to right. Abbreviated Navigation Paths An abbreviated Navigation Path is one in which a database field or table reference does not start with an absolute path (that is, the anchor row, a defined tag, or an \"entire table\" notation - \"/\"). Gaia analyzes the DDL and locates the shortest path between the anchor and the field or table. The anchor row is invariant through the entire Rule and is the starting point for every abbreviated Navigation Path. A Navigation path can contain abbreviated components. The following example shows abbreviated components in a complete Navigation Path. on_update(Traveller) { print(FlightMiles); // FlightMiles is found via Traveller. Various paths are equivalent: // Traveller->Trip->Segment->Flight.FlightMiles // Trip->Segment->Flight.FlightMiles // Segment->Flight.FlightMiles // Flight.FlightMiles // FlightMiles } Why not always abbreviate? Some common reasons are: There are multiple paths from the anchor to the field, and you want to make sure the correct one is used. There are two or more paths that are of equal length between the anchor and field, and you are forced to pick one. You want to tag a segment of the path in order to refer to its fields. For example: on_update(Traveller)> { for (T:Trip->Segment->F:Flight) { print(T.TripMiles, F:FlightMiles); } } Navigation Paths with multiple relationships (need better heading) The Table->Table[.fieldname] navigation path syntax is applicable when only a single relationship exists between the related tables. However, suppose a table is related to another table via multiple relationships. In that case, you need to use the relationship name in the navigation path instead of the table name to disambiguate which path you wanted to follow. The following DDL is a fragment from a sample course registration system. It defines two tables, course which contains the available courses and prerequisites which contains prerequisites for courses. It also defines two relationships: course_prereq which is a many-to-many relationship between courses where one direction is all of the courses required as prerequisites to a course. prereq_course which is all the courses for which this is the prerequisite of. create table if not exists course ( course_id string, name string, hours int32 ); create table if not exists prereq ( prereq_id string, min_grade string ); create relationship if not exists prereq_course ( course.required_by -> prereq[], prereq.prereq -> course ); create relationship if not exists course_prereq ( course.requires -> prereq[], prereq.course -> course ); The following is a snippet from a Ruleset the defines navigation paths based on the DDL. // Path for list of courses that are required by this course. course.required_by->prereq.course->course // Path for list of courses that require this course course.requires->prereq.prereq->course"
},
"articles/rulesets-using-tags.html": {
"href": "articles/rulesets-using-tags.html",
"title": "Using Tags | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Using Tags When performing iterations in a Navigation Path, it is convenient to have a way to reference the current row. To address this, Gaia provides a tag feature that allows you to automatically create a local variable that you can use to work with the row in question. A Tag is a special form of identifier. It has a type, which is the table type it is attached to. Its value is a row of that type (table). A Tag can be any valid C++ variable name. Tags must be unique within the scope of the Rule. Declaring a local variable that has the same name as a Tag causes an error at the time of translation. Tags are explicitly associated with a segment of a navigational path and are used to represent the current row of the segment type during an iteration of the path. The scope of the tag is limited to the statement in which it is defined. Tags are defined in the form: tag:table-name For example: Flight->Segment->Trip->T:Traveller Tags represent \"the current row of a table,” allowing the Rule to access fields and relationships in that row by using the tag within the scope of the statement that encloses the tag definition. The Tag creates a local variable that points to travelers one by one as we iterate through the people on a flight. So, T.MemberMiles references the miles for the passenger with which we are currently working. Tags become particularly important as we consider dealing with multiple lists in the next section. Any single statement also defines the scope of a tag. Within the scope of its usage, the tag becomes the name of an instance of a single row in the table. // note: If you want to reference the current row in a for statement // then you must use a tag. for (/S:student) { if (strcmp(S.student_id, \"stu001\") == 0) { S.registrations.connect(registration); break; } } The scope for an on_xxxx() statement is the entire Rule. This can be a single-line statement, or a more complex statement like for, while, or if. You can define multiple tags in a single statement. Using tags in an on_xxxx() prefix Tags can appear in the on_xxxx() prefix to a Rule or in a variable reference. The Tag then represents the Rule's anchor row throughout the body of the Rule. However, the name must not conflict with any other name used in the Rule or on_xxxx statement (table, field, or other variables.) In a Navigation Path You can use any previously set tag in a navigation path as the source row for a subsequent in-scope navigation path declaration. The generalized form, shown below, allows tag0 to be any tag that is valid and visible in the current lexical scope: tag0->Segment1->Segment2->...->Segmentn In the above notation, the first tag is being referenced or \"used\", while all others that appear in the path (as an optional part of the Segment) are being set or defined. Flight->Segment->Trip->T:Traveller Traveller.Name T.Name"
},
"articles/rulesets-writing-rules.html": {
"href": "articles/rulesets-writing-rules.html",
"title": "Writing Rules with Gaia Declarative C++ | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Writing Rules with Gaia Declarative C++ Gaia rules are written in Declarative C++. Gaia Declarative C++ differs from traditional C++ in several ways: Declarative rules cannot be called directly. Instead, they are invoked by the Gaia system in response to changes to the database. In traditional C++ your code determines the order of execution. When you write Rules in Gaia Declarative C++, the Gaia platform determines the execution order of Rules In a Rule, Gaia Declarative C++ can reference tables and fields within the database as well as local variables. You do not have to declare types that are in the database. Field references do not have type declarations in a Ruleset; the translation engine supplies these from the Schema definitions in the database. Gaia converts the fields that you reference into code-based accessors. The Gaia system passes system contexts to the Rules context from which you can access related rows. These are: data context: you are handed the exact row that changed so you are working on the relevant data. navigation context: you can navigate to related data in other tables relative to the data context. Because the Rule functions are invoked by the Gaia system, you are automatically operating on the data that caused the change. Since Gaia knows the type of relationship that exists between tables, it can automatically generate iteration over M rows in a 1:M relationship.In the case of a one-to-many relationship, referencing a related table can result in iteration over all of the rows related to the parent data context. Depending on the relationships in your schema, a field reference can return 0,1, or multiple rows. Because the Rule functions are invoked by the Gaia system, you are automatically operating on the data that caused the change. Gaia Declarative C++ rules are multi-threaded by default. Each Rule is scheduled to run on a thread in a configurable thread pool and each thread runs in its own transaction. The Gaia system takes care of the synchronization of data in the database for you. Note : While Gaia Declarative C++ doesn’t prohibit the use of global static variables, we recommend against it due to added overhead that you incur ensuring that your code is thread safe. The Gaia tools translate the Declarative C++ code to traditional C++ code based on what Gaia knows about your data as represented in the Gaia Catalog. This means that you don't have to hand-write traditional data access and navigation code. In Gaia, Rules and rows are directly connected. In a Rule, data that resides in the Gaia database are field references. Field References in the Rule look like variables, but they reference fields in rows of the database; there is no need to declare them as variables. When data changes in the database, Rules that reference the data execute automatically. In addition to the Ruleset level declarations, you can declare any number of local variables at the start of a specific Rule using standard C++ syntax, such as int BagCount. Local variables are scoped to the Rule that they are defined in. Picture an application that manages airplane flights, passengers, and baggage. There is a table that tracks actual flights. At the end of each flight, the unique row for that flight has a field called FlightMiles to reflect the miles flown in the flight. In another table, there is a row for each traveler reflecting MemberMiles. Let’s start with four simple rules based on the following schema: Member Rule 1 // Update the number of miles the member has flown { MemberMiles += @FlightMiles; } The key to understanding this Rule is that FlightMiles is designated as an Active Field. Whenever a change to that field is committed, the Rule engine automatically fires the Rule. Each flight has many passengers. There is a 1:many relationship between the Flight row in the database, which contains FlightMiles, and the Traveler row, which contains MemberMiles. The rules engine recognizes that relationship from the Catalog and automatically iterates this statement in the Rule for every passenger on the flight. So, that one assignment causes the system to: Recognize that there are many passengers on the flight. Finds all the passengers on this flight; the Rule then iterates over the result set. Starting from the Flight row, navigate to the correct Traveler row in that table for each passenger. Even here, the rules engine is automatically navigating through several intermediate rows to get from Flight to Traveler. Complete the update for every passenger. Navigation paths execute against sets of rows completely transparently and automatically. Member Rule 2 // Update member status { if ( @MemberMiles > 75000 ) { MembershipLevel = Silver }; } In this example, MemberMiles is an Active Field. The rules engine automatically fires the Rule each time MemberMiles changes. Rule 1 changes the value of the field and causes the rules engine to fire Rule 2. This is referred to as Forward Chaining which we discuss further in the next section. We track each trip in a table called Trips which has a counter for TripSegments. How do we know a segment is complete? One answer could be to add a field in Flights called FlightLanded. Then we could write: { if (@FlightLanded) { TripSegments +=1} } Before moving on, let’s examine what is taking place with both of these conditional statements. A flight segment was completed. An Active Field caused the rules engine to fire a Rule. That Rule relates to a particular row for a particular flight. That row, in turn, is related to many Trip rows. Not only that, the path from the flight row to the appropriate trip row involves navigating through an intermediate segment row. We start with a simple one statement conditional and end up with: Code is generated to locate all segment rows that are related to the flight row. The Rule is fired once for each of the many hops between airports (segments) associated with this flight. The system navigates through the segment row in each case, which fires the event to update the SegmentsFlown. Now consider the baggage that is loaded onto the plane. The baggage is scanned and the loaded baggage weight is tracked in a table. // Track weight of baggage loaded on flight on_insert(BaggageLoadScan) { FlightWeight += Weight } In this case, the Rule is defined using the on_insert prefix. // Check for overweight situation and raise the alarm { If (@FlightWeight > MaxWeight ) { ActivateWeightAlarm(FlightWeight) } } Since rules are written with statements which are, at their core, C++ statements, you can call functions that perform external actions from the body of the Rule. The first Rule uses a C++ utility function which tracks the weight of the baggage loaded on the flight. This procedural utility could also update the database, which would in turn trigger the execution of Rules. Through Forward Chaining, the rules system fires the second Rule each time the value of FlightWeight changes. If the value of FlightWeight exceeds the maximum allowed baggage weight, the Rule calls the ActivateWeightAlarm method, which is a C++ function that can be external to the rules declarations. Forward chaining When the value of a field reference changes in the active database, Gaia fires the Rule automatically. As rules get fired, they might also change fields, and any active field changes can, in turn, fire other rules. We call this process Forward Chaining. The combination of rules firing automatically, making changes, then cascading to the execution of other rules is the basis for our declarative system. Sometimes when a field’s value changes, a Rule fires against the individual row. In other cases, though, a Rule might update fields in many rows. For example, after a flight lands, all the luggage might be marked as arrived. The rules engine generates the underlying query for the Navigation Path to make this work automatically. This is a key part of eliminating control flow. One of the fundamental results of Forward Chaining is that the order in which Rules execute is determined by the order in which commits that contain changes to active fields occur. The power derives from the fact that there is no need to create queries, navigate through tables, copy, and map data: Gaia handles all of that automatically. Transactions Transactions are complex to think about in a world with forward chaining since cascading rules, particularly across multiple Rulesets and authors, a transaction could go on forever. For this reason, the Gaia platform focuses on the use of transactions to ensure the consistency of operations within the scope of each Rule. The rules engine automatically brackets every Rule with a Begin and Commit Transaction sequence. As each transaction is committed, Forward Chaining fires subsequent Rules. All forward chaining takes place after the transaction is committed. When a transaction aborts, usually due to a conflict with another transaction, the aborted Rule is automatically rescheduled for execution by the Rules Engine. For example, two concurrent transactions might change the same field value. In this case, the first one to commit 'wins,’ and the second one must re-execute. In the declarative system, rules based on field changes are the only mechanism for moving from one Rule to the next; there is no explicit control flow. A single Rule, particularly if it has multiple statements, might cause several other rules to fire. Parallelism Gaia automatically fires all rules in parallel by default. This is made possible by the Rules Engine’s managed execution environment and the implementation of transactions in the database itself. Important : Be careful when using objects that have a shared mutable state, such as static variables. There are no protections to prevent all the usual race conditions, timing, and visibility issues common in procedural programming. In short, all multithreading best practices apply when dealing with procedural code. There are two mechanisms available to control this behavior. Primarily you can add the SerialStream(stream-name) attribute to a Ruleset to force all rules in that Ruleset to execute in a serialized fashion. Be aware that even when run serially, the ordering is not deterministic, e.g. the scheduler does not perform any type of sorting on the pending rules-to-be-run. It might be worth explicitly stating that. Rules in Rulesets with a common stream-name never run in parallel with each other. Be aware that serialized rules are not guaranteed to run in the same hardware thread; this means that writing code that relies on data persistence is not recommended. To put it more fundamentally, thread local storage is not guaranteed to work and should not be used inside rules. For applications requiring a single-threaded approach, you can specify the number of threads that Gaia uses to process rules. To guarantee single-threaded semantics are applied, set thread_pool_count to 1 in the gaia.config file. If a transaction fails due to a concurrent transaction exception, the rules engine retries the transaction. You can configure the global setting for the number of retries for a transaction. Note that this setting is global and applies to all transactions in the database. To specify that Gaia should not retry transactions, set rule_retry_count to 0. Nested Iteration In a Rule, statements that contain references to fields in the database can initiate iterative behavior over the returned result set. Gaia iterates through all indicated values (based on the reference) until the statement has exited, either by running out of values or it is forced to exit via a 'break' or 'return' statement, before proceeding to the next statement in the Rule. The Rules translator translates statements that generate loops from left to right with each successive loop executing within the scope of the previous loop. Suppose we have an if statement that iterates over all passengers, which references the luggage for each passenger. If ( @passengerstatus == “missing” ) { if ( luggagestatus == “loaded” ) { . . . } } Here we have a loop within a loop. The entire statement is executed once for each passenger. Then, while focused on that passenger, the inner if is executed once for each piece of luggage that belongs to the passenger."
},
"articles/tools/tool-gaiac.html": {
"href": "articles/tools/tool-gaiac.html",
"title": "Gaiac | Gaia Platform Documentation",
"keywords": "Gaiac NOTE The information contained in this document represents information about prerelease features of the product. Features might change when the product is released for general availability. The Gaia Catalog Tool (gaiac) creates the datastore and tables that support your application. It also translates Gaia Data Definition Language (DDL) files into the Gaia headers you include in your Ruleset and app code files. Usage Usage: gaiac [options] [ddl_file] Command line arguments Options Description -d <dbname> --db-name <dbname> Specifies the database name to use when generating the Direct Acess source files. -i --interactive Run gaiac in interactive mode. For more information on the available commands, see the Interactive mode commands section below. -g --generate Generates the Gaia headers and database tables for the specified DDL file. If the -d argument does not specify the database name, gaiac uses the default database '()'. -o <path> --output <path> Sets the output directory for all generated files. -h --help Prints help information. -v --version Prints version information. <ddl file name> Specifies the DDL file to process. Interactive mode commands In the interactive mode, the following commands are available: Command Description CREATE DATABASE [if not exists] DATABASE_NAME Creates a database with the specified database name. If the command succeeds, gaiac returns to the prompt. If the command fails, gaiac returns an error message and returns to the prompt. CREATE [if not exists] [DATA_BASE NAME.]TABLE ( <field definitions>) Creates a table with the specified name and fields. If the command succeeds, gaiac returns to the prompt. If the command fails, gaiac returns an error message and returns to the prompt. For more information on table specifications, see the CREATETABLE section below. DROP DATABASE NAME; Removes the database specified by NAME from the catalog. DROP TABLE [DATA_BASE_NAME.]TABLE_NAME; Removes the table specified by TABLE_NAME from the specified database specified by TABLE_NAME. If you do not specify a database, the default database '()' is assumed. \\h Print help information. \\dd [NAME] Lists the tables present in the database specified by NAME. If you do not specify a database, tables in the default database '()' are displayed. \\d[t] NAME Lists the fields and references in the table specified by NAME. \\ld [PATTERN] Lists the databases in the Gaia catalog. Optionally, you can filter the results by specifying a regex pattern. For more information on regex, see ECMAScript syntax on the cplusplus.com website. \\lf [PATTERN] Lists the data fields in the Gaia catalog. Optionally, you can filter the results by specifying a regex pattern. For more information on regex, see ECMAScript syntax on the cplusplus.com website. \\lr [PATTERN] Lists the relationships in the Gaia catalog. Optionally, you can filter the results by specifying a regex pattern. For more information on regex, see ECMAScript syntax on the cplusplus.com website. \\l[t] [PATTERN] Lists the tables in the Gaia catalog. Optionally, you can filter the results by specifying a regex pattern. For more information on regex, see ECMAScript syntax on the cplusplus.com website. \\q Quit Gaiac has three modes of operation: Loading: By default without specifying any mode, gaiac runs in loading mode. In this mode, gaiac reads the specified DDL file and translates them into catalog records without generating the Direct Access heard files. Interactive : (--interactive or -i) provides a command-line interface that you can use to try DDL statements without creating a DDL file. DDL statements entered on the command line are executed and any output is displayed to the console. Generation: (--generate or -g), In this mode, gaiac generates the Direct Access header files based on the specified database(s) to the specified output path Next steps Learn more about the Gaia Data Definition Language"
},
"articles/tools/tool-gaiat.html": {
"href": "articles/tools/tool-gaiat.html",
"title": "Gaia Translation Engine | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about prerelease features of the product. Features might change when the product is released for general availability. Gaia Translation Engine The Gaia Translation Engine (gaiat) generates C++ rule and rule subscription code from declarative Rulesets. Usage Usage: gaiat [options] [ddl_file] Command line arguments Options Description -h Alias for -help -help Display available options (-help-hidden for more) -n=<string> DB instance name -o Alias for -output -output=<string> Output file name -version Display the version of this program"
},
"articles/tutorials/gaia-incubator-example.html": {
"href": "articles/tutorials/gaia-incubator-example.html",
"title": "Gaia incubator example | Gaia Platform Documentation",
"keywords": "NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. Gaia incubator example The following example models an incubator system for chickens and puppies. It simulates temperature sensors and cooling fans. The simulation has two distinct components: A simulator component that models the environment and a Gaia component that controls the incubators' behavior in response to changes. As the simulation runs, you will notice that the temperature in both incubators tends to increase. To counteract the environment getting too hot for the young animals, the Gaia component invokes logic to turn on the fans. Prerequisites For information about the Gaia Platform prerequisites and installing the SDK, see Getting Started with the Gaia Platform . Preparing the demo To copy the incubator demo into your current directory: cp -r /opt/gaia/examples/incubator/ . Navigate to the incubator demo folder: cd incubator If the Gaia database server is not running, start it now. To start the server on a machine that supports systemd: sudo systemctl start gaia Complete setup of the build environment by issuing the following commands: mkdir build\\ cd build\\ cmake ..\\ make The incubator demo The example includes the following files: CMakeLists.txt - Build instructions for setting up the necessary files for the example. gaia.conf - Configuration settings for the database and rules engine that comprise the Gaia Platform. gaia_log.conf - configuration settings for the platform and application loggers that the Gaia Platform uses. incubator.ddl - Describes the schema to create the database. incubator.ruleset - Defines the rules definitions for the example. Main.cpp - The incubator application that drives the simulation. README.md - Information about the example and troubleshooting instructions. Running the demo is the next thing to do to see what it does, then we can explain how it works. Running the incubator It is helpful to Have a couple of terminal windows running to see what happens 'in real time.' First, open two terminal windows. You will run the demo in one and monitor it in the other. In your first terminal window, run the command: ./incubator sim When the demo starts, it displays the following menu: To start the simulation, select b . In the second terminal window, run the command: watch -n .5 ./incubator show This command dumps the contents of the incubators' state and their sensors and fans to the screen. The output will appear similar to the following: The output shows the incubator and components being monitored. For each of the temperature sensors and fan actuators, the output displays a timestamp in the second column and the current temperature or fan actuator speed in the third column. As the simulation runs, the temperature in both incubators tends to increase. To counteract the environment getting too hot for your chickens and puppies, Gaia invokes logic to turn on the fan actuators. Let's look at how this is accomplished. How the incubator demo works The core Gaia files that you need to examine are the incubator.ddl and incubator.ruleset files. First, let's examine the data store. The schema is located in the incubator.ddl and it defines three tables. incubator - Models the incubator. actuator - Models the fans. sensor - Models the temperature sensor. The schema also defines two relationships : incubator_sensors - Defines a one-to-many relationship between the incubator table and the sensor table. incubator_actuators - Defines a one-to-many relationship between the incubator table and the actuator table. In Gaia the fields defined in the data definition file are considered potentially Active. This means that the Gaia Rules engine executes Rules when you refer to the field in the Rule. You have two ways to specify which fields are active: Use the on_update() or on_change() attribute to list the active fields in the Rules. OnUpdate(field1, field2, field3) Prepend an @ sign to the fields that are Active. @field1 = ... The incubator.ruleset file defines the logic that acts on the Active Fields. This file contains several Gaia rules in the Ruleset. The second Rule is defined as follows: // Rule 1: Keep the temperature in range of the incubator limits. on_update(sensor.value) { if (!incubator.is_on) { return; } if (sensor.value < incubator.min_temp || sensor.value > incubator.max_temp) { for (A:actuator) { A.value = adjust_temperature(incubator.min_temp, incubator.max_temp, sensor.value, A.value); A.timestamp = g_timestamp; } } } The Rule uses the on_update() attribute to watch for changes sensor.value field. If the temperature is outside of the acceptable range it calls adjust_temperature to set a new actuator value. The Rule fires whenever the temperature value changes, which means that the fan actuator might increase its speed several times. It can even increase fast enough to drive the temperature of the incubator below the specified minimum value. But this is okay. The else if block in the Ruleset contains the necessary logic to reduce the fan actuator speed if it falls below the minimum temperature. Additionally, since the Gaia Platform understands your schema and how your tables are related, the Rule is reading all the sensors' values in each incubator and setting the value for all the actuators in each incubator. In this example, each incubator is related to a set of sensors and actuators. So far, we've focused on changes to the sensor.value field. But we also have an incubator.max_temp or incubator.min_temp field. What if we wanted to change the temperature range of our incubator? Would Gaia be able to respond to this as well? The answer is yes. In this example, sensor.value, incubator.max_temp, and incubator.min_temp are all Active Fields. // Rule 1: Verify the temperature is kept in range if the // incubator temperature limits change. on_update(incubator.max_temp, incubator.min_temp) on_update(incubator.max_temp, incubator.min_temp) { if (!incubator.is_on) { return; } sensor_loop: for (S:sensor) { if (S.value < min_temp || S.value > max_temp) { for (A:actuator) { A.value = adjust_temperature(min_temp, max_temp, S.value, A.value); A.timestamp = g_timestamp; } break sensor_loop; } } In Rule 1 the for loop iterates over all the sensors in the incubator. The second if block tells Gaia to check whether th min_temp and max_temp fields in the incubator table are outside of the new values. If they are, we adjust the fan actuator values. We do this by assigning a new value to the actuator table, as seen in the if block's body. The simulation environment lets us test the link between the Active Fields in the Ruleset. For this example, you will manage one of the incubators, setting the temperature range to a new value. To set the new value: Start the simulation. To manage the incubators, select m . To manage the puppies incubator, select p . To drive the execution of the Rule described above, set the new max_temp value to one that is less than the current sensor value. For example, if the puppy incubator temperature is reading 92, set the max_temp value to 90. Now, when you monitor the incubators, you will see that Gaia increments the fan actuator values when the temperature exceeds the new maximum temperature. Before submitting the new max_temp, your tables should look like this. After you submit the new max value, both fan actuators associated with the incubator immediately start increasing their speed, like so: This application of the Rule functions on the same principle as in the first example. The difference is that the change that triggers the Rule is caused by our intervention rather than the changes driven by the environment. In the first example, changes in sensor.value caused the Rule to fire and to compare the updated sensor.value against the current value of max_temp. In this example, you changed the value of max_temp which caused the Rule to fire and compare the current value sensor.value against the updated value of max_temp. It is also worth observing that in this case, more than one fan actuator was associated with the incubator and both fan actuators had their speeds increased. The way that we have defined our Gaia data tables means actuators refer back to the incubator. Gaia is aware of this connection and can apply fan actuator increase logic to all the actuators associated with the puppies incubator. There is one more concept to review. So far, we have explored changes that come either from the ambient environment or direct user intervention. But a compelling design concept for writing programs in Gaia is the idea of \"forward chaining.\" This is when the firing of one Rule can result in a change to state that immediately triggers the firing of a subsequent Rule. Rule 4 in the Ruleset file illustrates this functionality: // Rule 4: If the fan is at 70% of its limit and the temperature is still too hot then // set the fan to its maximum speed. on_update(actuator.value) { if (actuator.value == c_fan_speed_limit) { return; } if_loop: if (S:sensor.value > incubator.max_temp) { if (actuator.value > c_fan_threshold * c_fan_speed_limit) { actuator.value = c_fan_speed_limit; actuator.timestamp = g_timestamp; } break if_loop; } } The comment preceding the Rule describes its purpose. If the fan actuators have been ratcheting up to counteract a hot incubator, there comes a point when we do not want to wait for further incremental increases. Instead, we max out the fan actuator's speed. The first if block acts as a simple guard where the second encodes the real logic. There are several variables in the conditional. The primary active variable is the actuator.value field. This means that changes to the fan actuator speed trigger the Rule. You will also notice two other variables from the prior Rule, sensor.value and incubator.max_temp. However, these fields are not listed in the on_upate() attribute and therefore do not cause the Rule to fire. We can now review how the first Rule and the just-introduced Rule will interact. As you recall, the first Rule is triggered by a change in the sensor.value field and results in the modification of the actuator.value field. This change now immediately causes Gaia to check the conditions described in Rule 3. This is forward chaining in action. To see this behavior, return to the simulation controller and allow the incubator to heat up considerably beyond its maximum temperature. To do this, after starting the simulation, select manage incubators from the menu, select an incubator and enter the command to turn off the power. This forces the incubator to stop actuating the fans (allowing the environment to heat up). Wait until the temperature of the incubator exceeds the maximum temperature range by a few degrees. When it does, enter the command to turn the incubator power back on. The associated fan actuator speed values start climbing in increments of 500. When the fan actuator speed reaches 3500, there is a jump to 5000 - a sudden change of 1500. This sudden jump is caused by the firing of Rule 1 modifying the actuator.value (fan actuator speed) which triggers the immediate firing of Rule 3. Use forward chaining to build out complex application behavior."
},
"articles/tutorials/writing-first-gaia-application.html": {
"href": "articles/tutorials/writing-first-gaia-application.html",
"title": "Writing your first Gaia application | Gaia Platform Documentation",
"keywords": "Writing your first Gaia application NOTE The information contained in this document represents information about preview features of the product. Features might change when the product is released for general availability. In this walkthrough, you'll write and run your first Gaia Platform application. The code that you will write is also available under the /opt/gaia/examples/hello folder of the distribution package. If you encounter any errors along the way, you can compare the files that you generated from these instructions against those already provided. The example walks you through most aspects of the Gaia Platform system. You'll learn how to: Define a database schema and compile it with the Gaia Catalog Tool (gaiac). Write a few simple Rules and translate them using the Gaia Translation Engine (gaiat). Write, build, and execute a simple application to fire our Rules by inserting data into the database. Prerequisites For information about the Gaia Platform prerequisites and installing the SDK, see Getting Started with the Gaia Platform . This walkthrough assumes that you are using Clang 10. The Hello application The goal of the application is to generate greetings for input names. To demonstrate the features of the system, the code inserts names into a table, which fires a Rule that generates greetings for those names and inserts them into a second table. The insertions into the second table fire a second Rule that prints the greetings to the console. For this purpose, there are two tables: A names table with a single name column, of string type. A greetings table with a single greeting column, of string type. There are also two Rules: A Rule that fires on insertions into the names table and that will in turn form and insert a greeting into the greetings table. A Rule that fires on insertions into the greetings table and prints the greeting values to the console. To put all of this together, you'll also write a small application that inserts some names into the names table to fire the Rules. Creating a new application folder Create a new folder in which to store the files for the application. mkdir hello_sample cd hello_sample You'll execute all of the commands specified in this document in this folder. Specifying the Hello database schema If you are familiar with SQL syntax, the Gaia Data Definition Language (DDL definition format will be familiar to you. In your source folder, create a hello.ddl text file. Copy and paste the following definitions in it: create database if not exists hello; use hello; create table if not exists names ( name string ); create table if not exists greetings ( greeting string ); The create database and use statements are optional components of the DDL. If you do not include them, the gaia ddl compiler operates against the default database compiling the DDL. The statements define the two tables, names and greetings *, that that application uses. Each table has one database column. You will refer to the database column names in the body of Declarative Rule expressions that you will define later. When your declarative code refers to one of these Fields with a read operation, Gaia fires an Event that schedules the associated Declarative Rules for execution. The next step is to compile the definitions and generate the tables in the Gaia database. To do this, use the Gaia Catalog Tool (gaiac) to creates the datastore and tables to support the app and translate the Gaia DDL files into Gaia headers that you include in the Ruleset and app code files. At the command line, in the folder in which you created the hello.ddl file, run the following command: gaiac hello.ddl -g --db-name hello -o hello The command instructs gaiac to process the hello.ddl file which creates the database and tables. The -g option tells gaiac to generate the Direct Access header and source files. The --db-name specifies which database to use and the -o option specifies the output folder for the generated files. Gaiac generates a gaia_hello.h file that contains definitions necessary to programmatically interact with the tables that are generated based on the definitions. You will see these referred to as Direct Access code. Gaiac generates a second file name hello_generated.h. This is included by the gaia_hello.h file; you will not reference this file directly. Gaiac provides an interactive mode in which you can view information about the catalog. For more information, see Gaia Catalog Tool To verify that the tables were successfully created, run gaiac in an interactive mode: gaiac -i At the prompt, type the following command to list all the database tables: NOTE : Commands in gaiac interactive mode are preceded by a backslash character \"\". \\lt You should see two rows for the names and greetings tables. The other entries are for system catalog tables or other tables that you might have generated with other examples. The entries that you are interested in are listed last and look similar to the following: Database Name ID Type ... ... ... ... hello names 48 1 hello greetings 50 1 Do not worry if the ID values or the Type values look different the important thing is to see the tables listed. To exit the interactive gaiac session, use the following command: exit Specifying the Hello Rules Create a new file and name it hello.ruleset. Copy and paste the following content to it: #include <iostream> #include <string> #include \"gaia_hello.h\" using namespace std; ruleset hello_ruleset { // Rule 1: Whenever a name is inserted, // insert a new greeting into the greetings table. on_insert(names) { // Form the greeting using the name. string new_greeting = \"Hello \" + string(names.name) + \"!\"; // Insert the greeting. gaia::hello::greetings_t::insert_row(new_greeting.c_str()); } // Rule 2: Whenever a greeting is inserted, // output it to the console. on_insert(greetings) { // Output the greeting to the console. cout << endl << greetings.greeting << endl; } } The Ruleset file defines two Rules. The Rules use the on_insert() attribute to watch for insertions to the names and greetings tables. To insert the greeting into the greetings table, you use the gaia::hello::greetings_t::insert_row method. You can find the signature for the method in the gaia_hello.h file that gaiac generated. Finally, the second Rule outputs the greeting to the console. The Rules code looks very much like C++ but, before you can compile it, you must translate it into proper C++ code using the Gaia translator tool - gaiat. To generate C++ code for these Rules, execute the following command: gaiat hello.ruleset -output hello_ruleset.cpp -- -I /usr/lib/clang/10/include/ -I /opt/gaia/include/ -I hello NOTE : The first two include paths of this command might need to be updated if Gaia and clang are installed in a non-standard way or if you're using a version of Clang other than 10. The output of this step is the hello_rules.cpp that contains the C++ version of our Rules. You are now ready to compile these into an application. Writing the Hello application Create a new file and name it hello.cpp. Copy and paste the following code into it: #include <iostream> #include \"gaia/system.hpp\" #include \"gaia_hello.h\" using namespace std; int main() { cout << \"Hello example is running...\" << endl; gaia::system::initialize(); gaia::db::begin_transaction(); gaia::hello::names_t::insert_row(\"Alice\"); gaia::hello::names_t::insert_row(\"Bob\"); gaia::hello::names_t::insert_row(\"Charles\"); gaia::db::commit_transaction(); gaia::system::shutdown(); cout << \"Hello example has shut down.\" << endl; } Let's go over the main steps of this code: gaia::system::initialize() initializes the Gaia system. The insertion of the names needs to be done within a transaction that starts with gaia::db::begin_transaction() and completes with gaia::db::commit_transaction() . The actual insertions use the generated gaia::hello::names_t helper from gaia_hello.h. The application completes its execution by calling gaia::system::shutdown() , which is the counterpart to the gaia::system::initialize() call. To build this code, use the following command: clang++-10 hello.cpp hello_ruleset.cpp hello/gaia_hello.cpp /usr/local/lib/libgaia.so -I /opt/gaia/include -lpthread -o hello.run -I hello If you are using a newer version of the clang compiler or if Gaia is installed in a non-standard location, update the command accordingly. The output is a hello.run executable which represents your Hello application. Executing the Hello application You are now ready to execute the app: ./hello.run You should see output that looks similar to the following: Hello example is running... Hello Bob! Hello Alice! Hello Charles! Hello example has shut down. The order in which the Rules are triggered is not deterministic. Due to this, the output of the program will vary from run to run. Next Steps Learn about Gaia Rulesets Rum the Gaia incubator example"
},
"index.html": {
"href": "index.html",
"title": "About the Gaia Platform | Gaia Platform Documentation",
"keywords": "About the Gaia Platform The information contained in this document represents information about prerelease features of the product. Features might change when the product is released for general availability. Overview Gaia Platform is a software development framework that makes it easier to program autonomous systems at the edge. Gaia empowers programmers to make use of low-code features while still being appropriate for industrial use cases. Combining a high-speed in memory database with Declarative C++ language extensions, Gaia proviDes a performant and intuitive model for development. Model your state in the database, and when things change, your declarative application logic will respond automatically. As a developer, you can focus on what your program needs to do and let Gaia work out how it gets done. With Gaia, you'll write less code that's easier to read and more intuitive to debug and test. You can integrate multiple system components in a common setting with less boilerplate, from machine learning functions to ROS-enabled actuators. And you can run it all without the need for constant cloud connectivity. In a phrase, Gaia Platform is the industrial-strength low-code development environment for apps at the edge. Why Gaia? Writing software is complicated. As you look to develop autonomous systems that need to operate reliably and intelligently out in the real world, you can find that the difficulty has only increased. There's a lot to get working and a lot of moving pieces to integrate. For example, machine learning has come a long way, but it takes more than obstacle detection to build an interesting product. Plus, these systems generate a ton of data we need to deal with, which results in lots of code that's hard to debug and even harder to maintain over its lifetime. Gaia exists to overcome these challenges. The Gaia Platform is data-centric and responsive, like the world of autonomous machines. It is the nexus for integrating all the distributed components comprising your autonomous system and orchestrating their behavior to deliver on your mission's objectives. Are you looking for a way to accelerate the development of a new IoT prototype? Do you have subject matter experts with lots of knowledge and limited coding experience? What about a complex robotics product with an unwieldy state-machine? How can you use Gaia? The Gaia Platform supports numerous application scenarios with a common theme of operating in complex scenarios at the edge. Gaia's database and policies can be used to inform the behavior of an application directly. Write policies to respond to specific scenarios as informed by data (state) in the Gaia database. For example, you're building an Autonomous Guided Vehicle (AGV) to move material around a warehouse. You can use Gaia's database to model inventory and waypoint data so that your AGV can work without a direct connection to the internet. Throughout its mission, your AGV might generate lots of interesting and frankly uninteresting data. Use Gaia's DB to store it for the moment and implement data fusion and filtering logic with Gaia policies. You can write a policy that throws away intermediate navigation data but retains any discoveries about the location of inventory. At the end of the mission, your AGV can sync back only what's critical so that you can save on cloud bandwidth and storage costs. In systems in which pair Machine Learning (ML) and Deep Learning (DL) with perception and action planning methods, the Gaia Platform provides robust rules handling and event messaging to understand the data. What does this mean for Autonomous Systems? Autonomous Systems typically engage in a process of perceiving their environment, understanding an operational context, and acting accordingly. ML/DL is excellent at turning data into meaningful semantics, such as examining an RBG tensor and producing a label like \"kitty!\". To go from \"I see the kitty\" to \"I will pet the kitty\" requires additional layers of software to take the data from the perception engine and contextualize its output to make the decision. This is where Gaia comes in. Gaia allows you to define all the logic that contextualizes these inputs, understand the situation, and translate it into a decision. Based on the decision, Gaia can raise an event that sends an instruction to the robotic arm to pet the kitty. Beyond applications in Autonomous Systems, Gaia provides an Industrial strength transactional store that supports a transactionally safe framework. Whatever happens, you will always have a consistent database from which you can share data and act on it robustly. How it works Gaia is a platform in the sense that users build their applications on top of its functionality. Gaia runs on the Linux operating system and supports C++ (and in the future Python) programming language with declarative functionality. Gaia's in-memory database is installed with the platform and enables seamless integration between database operations and application control code. The Gaia Platform consists of the following elements: A shared in memory database An events engine A Catalog that interfaces with your app, the events engine, and the database And provides the following tools: Gaia Catalog compiler. The catalog compiler creates the datastore and tables that support your application. It also translates Gaia Data Definition Language (DDL) files into the Gaia headers you include in your ruleset and app code files. For more information, see Gaia Data Definition Language . Gaia Translation Engine. The translation engine converts your rulesets into code files that you include in your app. These components and tools interact to create an end-to-end solution. To accomplish this, Gaia addresses the PUA paradigm: Perceive, Understand, and Act. In Gaia, this is expressed as: Perceive - Where inputs come from Understand - Gaia platform Act - Rules engine policies/ integration with devices Perceive Your procedural code gathers the data from the inputs and writes them the Gaia database. Gaia itself is not focused on direct control of the actions you take to control and read devices such as microcontrollers. This includes: Interrupt Processing Device Drivers Fine-grained manipulation of actuators Etc. The Database is Active. This means that it functions as an Event system that monitors the incoming changes to the database and publishes them for subscribed rules. The Gaia platform implements the database as an in memory high-performance data store. For more information about defining your Gaia database, see Gaiac and DDL . Understand The primary focus of rules is the Policy layer of applications. You define rules using easy-to-read and understand declarative code. The declarative code that defines a Rule takes the form of \"If this happens, then do that.\" The rules engine and database work together to facilitate: Adaptive responses and process diversion resolution. For example, handle route diversion when a drone air taxi encounters bad weather. Data-driven decision-making. For example, Is this person allowed to be in that room at this hour. If you find edge cases where you need just a bit more control, you can intermix declarative code (rules) with procedural code. For more information about defining your rules, see Gaia Rulesets . Act Your code acts on the data and decisions produced by your rules. Gaia integrates with other platforms such as ROS2, including lower-level motion planning systems and other features to interact with your hardware. With Gaia, you can send a high-level instruction \"go to this waypoint\" to a ROS2 node that handles the task of navigating to that location. Summary Gaia provides a catalog that binds the database to the Gaia rules engine. Rules are written in declarative code and enable event-driven processing. The declarative code binds the rules to changes in the database without complex control flow logic. Next Steps Get started with the Gaia Platform Write your first Gaia App Learn more about Gaia Rulesets"
}
}