Subsections


The Schema-Oriented Generated C++ API

The generic C++ API allows you to manipulate any object within any database: this is its force. But, as shown in the previous section, object manipulation is sometimes very heavy as the provided methods are too much generic.

To enrich the generic API, one introduces a tool to generate specific C++ code from a specific ODL schema: the generated API is call a schema-oriented API.

The schema-oriented API contains mainly:
  1. a C++ class for each class defined in the ODL schema.
  2. selector and modifier methods in the C++ class for each attribute defined in the ODL class.
  3. user friendly selector and modifier methods for array and collection attributes.
  4. a C++ method mapped on each method defined in the ODL class.
  5. a specific C++ database class used to open a database and check its schema.
  6. some utilities such as down-casting funtions.
The schema-oriented API is designed so that the object manipulation for this schema is the most comfortable as possible.


Generating a Schema-Oriented C++ API

To generate a schema-oriented C++ API, one needs a well formed ODL file describing a schema or a reachable database containing this schema and the eyedbodl tool.
To generate a schema-oriented C++ API, the minimal eyedbodl invocation is as follows:
eyedbodl --gencode=C++ <odlfile>
or
eyedbodl --gencode=C++ --package=<package> -d <database>
For instance, to generate the schema-oriented C++ API for the person.odl schema:
eyedbodl --gencode=C++ person.odl
For a given package.odl ODL file, the generated files are as follows: The eyedbodl tool contains a lot of command line options to control the generated code.

There is one mandatory option:
odlfile|-|-d dbname|-database=dbname : Input ODL file (or - for standard input) or the database name
and some optionnal options:

-package=package 		 : 		 Package name

-output-dir=dirname : Output directory for generated files
-output-file-prefix=prefix : Ouput file prefix (default is the package name)
-class-prefix=prefix : Prefix to be put at the begining of each runtime class
-db-class-prefix=prefix : Prefix to be put at the begining of each database class
-attr-style=implicit : Attribute methods have the attribute name
-attr-style=explicit : Attribute methods have the attribute name prefixed by get/set (default)
-schema-name=schname : Schema name (default is package)
-export : Export class instances in the .h file
-dynamic-attr : Uses a dynamic fetch for attributes in the get and set methods
-down-casting=yes : Generates the down casting methods (the default)
-down-casting=no : Does not generate the down casting methods
-attr-cache=yes : Use a second level cache for attribute value
-attr-cache=no : Does not use a second level cache for attribute value (the default)
-namespace=namespace : Define classes with the namespace namespace
-c-suffix=suffix : Use suffix as the C file suffix
-h-suffix=suffix : Use suffix as the H file suffix
-gen-class-stubs : Generates a file class_stubs.h for each class
-class-enums=yes : Generates enums within a class
-class-enums=no : Do not generate enums within a class (default)
-gencode-error-policy=status : Status oriented error policy (the default)
-gencode-error-policy=exception : Exception oriented error policy
-rootclass=rootclass : Use rootclass name for the root class instead of the package name
-no-rootclass : Does not use any root class
For instance to generate a schema-oriented C++ API in the directory tmp, prefixing the runtime classes with pp, suffixing C++ files with .cpp, we invoke eyedbodl as follows:
eyedbodl --gencode C++ --output-dir=tmp --class-prefix=pp \
         --c-suffix=.cpp person.odl


The Generated Code

Seven files are generated:
  1. the header C++ file: package.h (for instance person.h)
  2. the core C++ file: package.cc (for instance person.cc)
  3. files for frontend and backend user method support:
    1. stubs: packagestubsfe.h and packagestubsbe.h
    2. skeleton: packagemthfe-skel.h and packagemthbe-skel.h
    3. a template Makefile: Makefile.package
    (for instance Makefile.person)
The use of the generated files for the user methods are introduced in the chapter Methods and Triggers.

The header file contains C++ class declarations and function prototypes.
The following classes are generated:
  1. the package class whose name is the package name and which contains a static init method, a static release method and two methods for schema update within a database, for instance:
    class person {
     public:
      static void init();
      static void release();
      static eyedb::Status updateSchema(eyedb::Database *db);
      static eyedb::Status updateSchema(eyedb::Schema *m);
    };
    
    1. the person::init() method must be called before any use of the schema-oriented API.
    2. the person::release() should be called after any use of this API, but this call is not mandatory as this method only release allocated runtime memory.
    3. the person::updateSchema() methods are not generally called directly by client code.
  2. the database class whose name is packageDatabase inherited from the generic eyedb::Database class.
    This class overloads two inherited methods: the open and the loadObject_realize methods.
    The overloaded open method has two purposes: The loadObject_realize method has one purpose: Note that to use the generated schema-oriented API it is not mandatory to use the generated database class: you can use the genetic eyedb::Database class; there is a lot of cases where you will get no trouble. But to avoid any potential trouble, it is strongly recommended to use the generated database class.
  3. a root class which is the superclass of all generated classes, except the package and the database classes.
    This class is used to facilitate the down casting process.
    If the command line option -no-rootclass is specified, the root class is not generated.
    Unless its name is given using the command line option -rootclass name, its name is Root.
  4. for each ODL class, a C++ class is generated with the same name possibly prefixed by a string if specified by the command line option -class-prefix. This class is inherited from the root class.

    The generated class contains the following method families:
    1. constructors.
    2. down casting methods.
    3. selector attribute methods.
    4. modifier attribute methods.
    5. methods mapped from ODL backend or frontend methods.
    6. client stubs.
    7. the destructor.


Constructors and Copy Operator

For each C++ class, two constructors and the assignment operator are generated:
  Person(eyedb::Database * = 0);
  Person(const Person& x);

  Person& operator=(const Person& x);


Down Casting Methods and Functions

Unless the command line option -down-casting no has been used, down casting methods and functions have been generated.
For instance, the following methods have been generated for the Person class:
class Person : public Root {
  // ...
  virtual Person *asPerson() {return this;}
  virtual const Person *asPerson() const {return this;}
  virtual Employee *asEmployee() {return (Employee *)0;}
  virtual const Employee *asEmployee() const {return (const Employee *)0;}
  // ...
};
These methods are very useful to process safe down casting. The down casting may be used in several cases. For instance, if you instantiate an Employee object as follows:
  extern void display(Person *);

  Employee *empl = new Employee(&db);
  display(empl);
the display function expects a Person instance: when calling it with an Employee instance, we do not make any mistake as the Employee class inherits from the Person class.
Assume now, that the display function displays the name and the age of the Person instance and its salary if the instance is an employee. Using the down casting method Person::asEmployee(), one can do as follows:
void display(Person *p)
{
  cout << "name : " << p->getName() << endl;
  cout << "age : " << p->getAge() << endl;
  if (p->asEmployee())
    cout << "salary : " << p->asEmployee()->getSalary() << endl;
Note that the call to this down casting method cost nearly nothing. Without the help of the down casting method, the previous code becomes:
void display(Person *p)
{
  cout << "name : " << p->getName() << endl;
  cout << "age : " << p->getAge() << endl;
  if (!strcmp(p->getClass()->getName(), "Employee"))
    cout << "salary : " << ((Employee *)p)->getSalary() << endl;
which is rather less efficient and less elegant.

There is another case to use down casting methods and functions is when loading a database object.
When loading a database object (for instance a Person database object) using the eyedb::Database::loadObject, we get a generic eyedb::Object instance, not a Person instance nor a Employee instance.
Nevertheless, in the case of a Person database object has been loaded, a Person persistent runtime object has been correctly constructed by the generated API.
So, it is legitimate to down cast the loaded eyedb::Object instance to a Person instance as follows:
  eyedb::OQL q(&db, "select Person.age < %d", given_age);

  eyedb::ObjectArray obj_arr(eyedb::True);
  q.execute(obj_arr);
  for (int i = 0; i < obj_arr.getCount(); i++)
   {
     Person *p = (Person *)obj_arr[i];
     cout << "name: " << p->getName() << endl;
   }
The cast:
     Person *p = (Person *)obj_arr[i];
is legal according to the context but is not safe because neither static (i.e. compiler level) check nor runtime check is performed.
Safe down casting functions are generated by eyedbodl as follows:
inline Person *Person_c(eyedb::Object *o)
{
  Root *x = personDatabase::asRoot(o);
  if (!x) return (Person *)0;
  return x->asPerson();
}
This function allows you to perform compiler and runtime check as follows:
  for (int i = 0; i < obj_arr.getCount(); i++)
   {
     Person *p = Person_c(obj_arr[i]);
     if (p) 
       cout << "name: " << p->getName() << endl;
   }
in the case of the loaded object is not a real Person instance, the Person_c function returns a null pointer.

It is strongly recommended to make use of these safe down casting methods and functions instead of performing manual down casting.


Selector Methods

For each attribute in the ODL class, eyedbodl generates one or more selector methods.
The number and the form of the selector methods depends on the type of the attribute.
An attribute type is a combination of:
  1. a primitive type which can take the form of a:
    1. basic type: for instance int32, char or double.
    2. system type: for instance class, object, image.
    3. user type: for instance Person, Employee, set<Car *>.
    4. user enum: for instance CivilState.
  2. the literal or object property:
    1. the literal property means that the attribute value has no identifier (i.e. OID).
    2. the object property means that the attribute value has an identifier.
  3. an optional array modifier:
    1. multi-dimensionnal and variable size array are supported.
For instance, the attribute:
  attribute Address addr;
can be described as {primitive type = Address, property = literal, array = nil}

The form of the selector methods are designed according to the following attribute type family:

		1. literal basic or user enum type 		: int32 age, CivilState cstate.

2. literal string : string<32> town, string name,string country.
3. literal user type : Address addr
4. object basic, user or system type : Person *spouse
5. object collection type : array<Person *> children, set<Car *» cars.
All those type families support in an orthogonal way an multi-dimenstion array modifier.


Literal Basic or User Enum Type

The selector method is under the form:
<attribute primitive type> get<attribute name>(eyedb::Bool *isnull = 0,
                                               eyedb::Status *status = 0) const
for instance for the age attribute:
  eyedb::_int32 getAge(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
Every selector method has the two following optional arguments:
  1. isnull : a pointer to a eyedb::Bool value.
    If this pointer is not null, the selector method assigns it to eyedb::False if the attribute value is not null, otherwise it assigns it to eyedb::True.
  2. status : a pointer to a eyedb::Status value.
    If this pointer is not null, the selector method assigns to eyedb::Success is the operation is successul, otherwise is assigns to the error status. Note that if you are using the exception error policy (the recommended one), this argument is not useful. If you have generated the schema-oriented C++ API using the -error-policy exception option, the status argument will not be generated.


Literal String

The selector methods are under the form:
const char *get<attribute name>(eyedb::Bool *isnull = 0,
                                eyedb::Status *status = 0) const
char get<attribute name>(unsigned int a0,
                         eyedb::Bool *isnull = 0,
                         eyedb::Status *status = 0) const
for instance for the name attribute:
  const char *getName(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
  char getName(unsigned int a0, eyedb::Bool *isnull = 0, eyedb::Status *status = 0)  const;
The first selector method is to get the full string value of the attribute while the second one is to get a specific character within this string value. The argument a0 is the number of the character.


Literal User Type

The selector methods are under the form:
  <attribute primitive type>* get<attribute name>(eyedb::Bool *isnull = 0,
                                                  eyedb::Status *status = 0)
  const <attribute primitive type>* get<attribute name>(eyedb::Bool *isnull = 0,
                                                        eyedb::Status *status = 0) const
for instance for the addr attribute:
  Address *getAddr(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) ;
  const Address *getAddr(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
Note than the returned value cannot be a null pointer as this is literal attribute fully included in the instance.


Object Basic, User or System Type

The selector methods are under the form:
  <attribute primitive type>* get<attribute name>(eyedb::Bool *isnull = 0,
                                                  eyedb::Status *status = 0)
  const <attribute primitive type>* get<attribute name>(eyedb::Bool *isnull = 0,
                                                        eyedb::Status *status = 0) const
for instance for the spouse attribute:
  Person *getSpouse(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) ;
  const Person *getSpouse(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
  eyedb::Oid getSpouseOid(eyedb::Status *status = 0);
Note that:
  1. the returned value can be a null pointer as this a is an object attribute with its own life.
  2. for this same reason, there is a method to get the identifier of this object without loading it.
  3. this selector method automatically loads the related object attribute when called.


Object Collection Type

As introduced in previous chapter, there are two main types of collections: ordered (or indexed) collections - array and list - and not ordered collections - set and bag. The generated methods for these two main types are similar but a little bit different.
For the not ordered collections, the selector method are as follows:
  <collection type>* get<attribute name>Coll(eyedb::Bool *isnull = 0,
                                             eyedb::Status *status = 0) ;
  unsigned int get<attribute name>Count(eyedb::Bool *isnull = 0,
                                        eyedb::Status *status = 0) const;
  const <collection type>* get<attribute name>Coll(eyedb::Bool *isnull = 0,
                                                   eyedb::Status *status = 0) const;
  eyedb::Oid get<attribute name>Oid(eyedb::Status *status = 0);
  const <collection object type>* get<attribute name>At(unsigned int ind,
                                                        eyedb::Bool *isnull = 0,
                                                        eyedb::Status *status = 0) const;
  <collection object type>* get<attribute name>At(unsigned int ind,
                                                  eyedb::Bool *isnull = 0,
                                                  eyedb::Status *status = 0);
  eyedb::Oid get<attribute name>OidAt(unsigned int ind,
                                      eyedb::Status *status = 0) const;
where <collection type> can be:
  1. eyedb::CollSet for a collection set
  2. eyedb::CollBag for a collection bag
and where <collection object type> is the type which is composing the collection.

Note that if the collection is not a literal but an object, the following extra method returning the collection oid is generated:
  eyedb::Oid get<attribute name>Oid(eyedb::Status *status = 0);
For the cars attribute the following code is generated:
  eyedb::CollSet *getCarsColl(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) ;
  unsigned int getCarsCount(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
  const eyedb::CollSet *getCarsColl(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
  const Car *getCarsAt(unsigned int ind, eyedb::Bool *isnull = 0,
                       eyedb::Status *status = 0) const;
  Car *getCarsAt(unsigned int ind, eyedb::Bool *isnull = 0, eyedb::Status *status = 0);
  eyedb::Oid getCarsOidAt(unsigned int ind, eyedb::Status *status = 0) const;
Let have a look to each method:
  1. eyedb::CollSet *getCarsColl(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) ;
    const eyedb::CollSet *getCarsColl(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
    
    returns the collection object (const and not const methods).
  2. unsigned int getCarsCount(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
    
    returns the collection item count.
  3. const Car *getCarsAt(unsigned int ind, eyedb::Bool *isnull = 0,
                         eyedb::Status *status = 0) const;
    Car *getCarsAt(unsigned int ind, eyedb::Bool *isnull = 0, eyedb::Status *status = 0);
    
    returns the #ind element in the collection. As the collection is not ordered, the index of the element to get depends on the load ordering and is not specified. These array-oriented methods are generated for user convenience because it is somewhat easier to scan an array that to scan an unordered set.
  4. eyedb::Oid getCarsOidAt(unsigned int ind, eyedb::Status *status = 0) const;
    
    returns the #ind oid in the collection. The remark about the index of the element is the same as above.
For the ordered collections, the selector method are as follows:
  <collection type>* get<attribute name>Coll(eyedb::Bool *isnull = 0,
                                             eyedb::Status *status = 0) ;
  unsigned int get<attribute name>Count(eyedb::Bool *isnull = 0,
                                        eyedb::Status *status = 0) const;
  const <collection type>* get<attribute name>Coll(eyedb::Bool *isnull = 0,
                                                   eyedb::Status *status = 0) const;
  eyedb::Oid get<attribute name>Oid(eyedb::Status *status = 0);
  const <collection object type>* retrieve<attribute name>At(unsigned int ind,
                                                             eyedb::Bool *isnull = 0,
                                                             eyedb::Status *status = 0) const;
  <collection object type>* retrieve<attribute name>At(unsigned int ind,
                                                       eyedb::Bool *isnull = 0,
                                                       eyedb::Status *status = 0);
  eyedb::Oid retrieve<attribute name>OidAt(unsigned int ind,
                                           eyedb::Status *status = 0) const;
where <collection type> can be:
  1. eyedb::CollArray for a collection array
  2. eyedb::CollList for a collection list
    Note that the collection list are currently not implemented in EYEDB .
and where <collection object type> is the type which is composing the collection.

Note that if the collection is not a literal but an object, the following extra method returning the collection oid is generated:
  eyedb::Oid get<attribute name>Oid(eyedb::Status *status = 0);
For the children attribute the following code is generated:
  eyedb::CollArray *getChildrenColl(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) ;
  unsigned int getChildrenCount(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
  const eyedb::CollArray *getChildrenColl(eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
  const Person *retrieveChildrenAt(unsigned int ind, eyedb::Bool *isnull = 0,
                                   eyedb::Status *status = 0) const;
  Person *retrieveChildrenAt(unsigned int ind, eyedb::Bool *isnull = 0,
                             eyedb::Status *status = 0);
  eyedb::Oid retrievedChildrenOidAt(unsigned int ind, eyedb::Status *status = 0) const;
Only the last three method templates differ from the corresponding Car method templates:
  1. const Person *retrievedChildrenAt(unsigned int ind, eyedb::Bool *isnull = 0,
                                      eyedb::Status *status = 0) const;
    Person *retrievedChildrenAt(unsigned int ind, eyedb::Bool *isnull = 0,
                                eyedb::Status *status = 0);
    
    returns the #ind element in the collection. As this collection is ordered, the index of the element to get is fully pertinent.
  2. eyedb::Oid retrievedChildrenOidAt(unsigned int ind, eyedb::Status *status = 0) const;
    
    returns the #ind oid in the collection. As this collection is ordered, the index of the element to get is fully pertinent.


Array Modifier

When an array modifier is present for an attribute, all the previous selector methods change in the same way: for each dimension in the array, an index argument is added at the begining of the selector method.
For instance, for an attribute int x[23][12], the selector methods becomes:
  eyedb::_int32 getX(unsigned int a0, unsigned int a1,
                     eyedb::Bool *isnull = 0, eyedb::Status *status = 0) const;
A call to getX(1, 3) returns the attribute value x[1][3].
If the left dimension is variable, for instance int x[][12], the following extra method is generated:
  unsigned int getXCount(eyedb::Status * = 0) const;
For instance, for the other_addrs literal user type attribute, the following code is generated:
  Address *getOtherAddrs(unsigned int a0, eyedb::Bool *isnull = 0, eyedb::Status * = 0) ;
  const Address *getOtherAddrs(unsigned int a0, eyedb::Bool *isnull = 0,
                               eyedb::Status * = 0) const;
  unsigned int getOtherAddrsCount(eyedb::Status * = 0) const;


Modidier Methods

The modifier methods are very similar to the selector methods. Their forms and their number depends on the same attribute type characteristics as the modifier methods.


Literal Basic or User Enum Type

The modifier method is under the form:
eyedb::Status set<attribute name>(<attribute primitive type>);
for instance for the age attribute:
  eyedb::Status setAge(eyedb::_int32);


Literal String

The modifier methods are under the form:
  eyedb::Status set<attribute name>(const char *);
  eyedb::Status set<attribute name>(unsigned int a0, char);
for instance for the name attribute:
  eyedb::Status setName(const char *);
  eyedb::Status setName(unsigned int a0, char);


Literal User Type

The modifier methods are under the form:
eyedb::Status set<attribute name>(<attribute primitive type>*);
for instance for the addr attribute:
  eyedb::Status setAddr(Address*);


Object Basic, User or System Type

The modifier methods are under the form:
eyedb::Status set<attribute name>(<attribute primitive type>*);
eyedb::Status set<attribute name>Oid(const eyedb::Oid &);
for instance for the spouse attribute:
  eyedb::Status setSpouse(Person*);
  eyedb::Status setSpouseOid(const eyedb::Oid &);


Object Collection Type

For unordered collection types, the modifier methods are under the form:
  eyedb::Status set<attribute name>Coll(<collection type>*);
  eyedb::Status set<attribute name>Oid(const eyedb::Oid &);
  eyedb::Status addTo<attribute name>Coll(<collection object type>*,
                                          unsigned int magorder = 0);
  eyedb::Status rmvFrom<attribute name>Coll(<collection object type>*);
  eyedb::Status addTo<attribute name>Coll(const eyedb::Oid &,
                                          unsigned int magorder = 0);
  eyedb::Status rmvFrom<attribute name>Coll(const eyedb::Oid &);
where <collection type> can be:
  1. eyedb::CollSet for a collection set
  2. eyedb::CollBag for a collection bag
and where <collection object type> is the type which composing the collection.

Note that if the collection is not a literal but an object, the following extra method setting the collection oid is generated:
  eyedb::Status set<attribute name>Oid(const eyedb::Oid &);
For the cars attribute, the following code is generated:
  eyedb::Status setCarsColl(eyedb::CollSet*);
  eyedb::Status addToCarsColl(Car*, unsigned int magorder = 0);
  eyedb::Status addToCarsColl(const eyedb::Oid &, unsigned int magorder = 0);
  eyedb::Status rmvFromCarsColl(Car*);
  eyedb::Status rmvFromCarsColl(const eyedb::Oid &);
Let have a look to each method:
  1. eyedb::Status setCarsColl(eyedb::CollSet *coll);
    
    sets the cars attribute collection to the input argument coll.
  2. eyedb::Status addToCarsColl(Car *car, unsigned int magorder = 0);
    
    adds the car instance to the collection attribute cars. If the collection is not yet created, this method call will create one using the magorder argument for its magnitude order value.
  3. eyedb::Status addToCarsColl(const eyedb::Oid &car_oid, unsigned int magorder = 0);
    
    adds the instance of Car whose oid is car_oid to the collection attribute cars. If the collection is not yet created, this method call will create one using the magorder argument for its magnitude order value.
  4. eyedb::Status rmvFromCarsColl(Car *car);
    
    removes the car instance from the collection attribute cars. If the instance is not found, an error is raised.
  5. eyedb::Status rmvFromCarsColl(const eyedb::Oid &car_oid);
    
    removes the instance of Car whose oid is car_oid from the collection attribute cars. If the instance is not found, an error is raised.
For ordered collection types, the modifier methods are under the form:
  eyedb::Status set<attribute name>Coll(<collection type>*);
  eyedb::Status set<attribute name>Oid(const eyedb::Oid &);
  eyedb::Status setIn<attribute name>CollAt(int where, <collection object type>*,
                                            unsigned int magorder = 0);
  eyedb::Status setIn<attribute name>CollAt(int where, const eyedb::Oid &,
                                            unsigned int magorder = 0);
  eyedb::Status unsetIn<attribute name>CollAt(int where);
where <collection type> can be:
  1. eyedb::CollArray for a collection array
  2. eyedb::CollList for a collection list
    Note that the collection list are currently not implemented in EYEDB .
and where <collection object type> is the type which composing the collection.

Note that if the collection is not a literal but an object, the following extra method setting the collection oid is generated:
  eyedb::Status set<attribute name>Oid(const eyedb::Oid &);
For the children attribute, the following code is generated:
  eyedb::Status setChildrenColl(eyedb::CollArray*);
  eyedb::Status setChildrenOid(const eyedb::Oid &);
  eyedb::Status setInChildrenCollAt(int where, Person*, unsigned int magorder = 0);
  eyedb::Status unsetInChildrenCollAt(int where);
  eyedb::Status setInChildrenCollAt(int where, const eyedb::Oid &,
                                    unsigned int magorder = 0);
Let have a look to each method:
  1. eyedb::Status setChildrenColl(eyedb::CollSet *coll);
    
    sets the children attribute collection to the input argument coll.
  2. eyedb::Status setInChildrenCollAt(int where, Person *person,
                                      unsigned int magorder = 0);
    
    adds the person instance to the collection attribute children at position where. If the collection is not yet created, this method call will create one using the magorder argument for its magnitude order value.
  3. eyedb::Status setInChildrenCollAt(int where, const eyedb::Oid &person_oid,
                                      unsigned int magorder = 0);
    
    adds the instance of Person whose oid is person_oid to the collection attribute children at position where.. If the collection is not yet created, this method call will create one using the magorder argument for its magnitude order value.
  4. eyedb::Status unsetInChildrenCollAt(int where);
    
    removes the instance found at position where from the collection attribute children.


Array Modifier

When an array modifier is present for an attribute, all the previous modifier methods change in the same way: for each dimension in the array, an index argument is added at the begining of the selector method.
For instance, for an attribute int x[32][64], the modifier methods becomes:
  eyedb::Status setX(unsigned int a0, unsigned int a1, eyedb::_int32);
A call to setX(2, 24) sets the attribute value x[2][24].

For instance, for the other_addrs literal user type attribute, the following code is generated:
  eyedb::Status setOtherAddrs(unsigned int a0, Address *);
  eyedb::Status setOtherAddrsCount(unsigned int count);


Methods mapped from ODL methods

For each ODL class method, there is a generated C++ method with the same name and the corresponding type.
The generated methods in our example is as follows:
  virtual eyedb::Status change_address(const char * street, const char * town,
                                       char * &oldstreet, char * &oldtown,
                                       eyedb::_int32 &retarg);

  static eyedb::Status getPersonCount(eyedb::Database *db, eyedb::_int32 &retarg);


Initialization

The minimal EYEDB C++ program using a generated schema-oriented API is as follows (using our example):
#include "person.h"

int
main(int argc, char *argv[])
{
  eyedb::init(argc, argv);
  person::init();
  // ...
  person::release();
  eyedb::release();
  return 0;
}
A few remarks about this code:
  1. the file person.h contains the whole generated C++ API and includes the generic EYEDB API.
  2. the EYEDB C++ layer must be initialized using one of the static method init method of the class EyeDB.
  3. the generated C++ layer must be initialized using the static method init of the class package.
  4. the last statements person::release() and eyedb::release() allow you to release all the allocated resources and to close opened databases and connections.
    Note that this statement is optionnal as all allocated resources, opened databases and connections will be automatically released or closed in the exit() function.


Database Opening

As shown in a previous section, it is recommended to use the generated C++ database class to open a database with the template schema.
For instance:
  eyedb::Connection conn;
  conn.open();

  const char *dbname = argv[1];

  person::Database db(dbname);
  db.open(&conn, eyedb::Database::DBRW);

EyeDB manual