2.2. GNUe Class Files

2.2.1. MODULES and CLASSES

A business object is defined using classes. Each class belongs to a module. If "MODULE module_name" is not specified then the class belongs to the "global" module. (e.g classes outside of a formal MODULE specification are assumed to be in the "MODULE global".) The basic format for this definition is:


  MODULE module_name
  {
    CLASS class_name
    {
      # class body goes here.
    };
  };

Where:
    module_name - the name of the module (or name space).
    class_name - the name of the class (or business object).

To reference a class in a different module or from a different class in the same module you must use the fully qualified name syntax:


    module_name::class_name

In each class GEAS automatically includes a unique 128 bit object identifier called objectid, which is stored as a char<32>. So in the previous example, the first field is module_name::class_name.objectid.

2.2.2. EXTEND

A class may be extended by using the EXTEND keyword. EXTEND allows a module to add to the definition of an existing class. The syntax is exactly like a class definition:

    EXTEND fully_qualified_class_name
    {

    };

For example an existing class item might be defined in the base module as:


    MODULE base
    {
      CLASS item
      {
        char   description<35>;
      };
    };

And in the supply chain module we might want to add stock information ot it. So we would define:


  EXTEND base::item
  {
    int   quantity_on_hand;
  };
    

Note that the extend defintion exists outside of any module definition even if it is defined inside a module definition. This produces the same results as if it had been originally defined as:


    MODULE base
    {
      CLASS item {
        char   description<35>;
        int   quantity_on_hand;
      };
    };

This should not be confused with inheritance which produces two tables when processed by geas.

2.2.3. Fields

Within a class fields and methods may be defined. A field is defined with the following format:


Syntax:
    type  field_name<size> = default_value NOT NULL;

Where:

Example:


    MODULE example
    {
      CLASS first
      {
        CHAR    street1<25>;
        CHAR    street2<25>;
        CHAR    city<15>;
        CHAR    county<15>;
        CHAR    state_code<8>;
        CHAR    country_code<8>;
        CHAR    postal_code<10>;
        TEXT    my_notes;
        FLOAT   latitude;
        FLOAT   longitude;
        INT     some_int32_number;
        INT16   some_small_number;
        INT32   same_as_int;
        INT64   some_large_number;
        BOOLEAN a_boolean;
        BOOL    another_boolean;
        DATE    today;
        TIME    now;
      };
    };

Note: TEXT and CHAR fields should not be confused with SQL field types. They are GEAS field types and are mapped to the best type depending on the back end database. (For PostgreSQL they are both VARCHAR).

Note: Field names may not start with "sys_". These field names are reserved for use by GEAS. For example, GEAS will automatically insert the fields sys_id, sys_cre_user, sys_cre_time, sys_mod_user, and sys_mod_time for object uuid, user name that created object, date/time object created, user name that last modified object, and date/time object last modified respectively.

TEXT - fields do not have a size attribute. They take up the amount of space actually required. That may be 1000 in one record and 100 in the next record for the same field. TEXT fields can not be searched.

CHAR - fields have a maximum size attribute and default to a length of 1 if not specified. Any trailing space (ASCII 32) characters are removed.

INT - Integer number currently implemented in 32 bits.

INT16 - Integer number currently implemented in 16 bits.

INT32 - Integer number currently implemented in 32 bits.

INT64 - Integer number currently implemented in 64 bits.

DATE - Date formatted for the underlying SQL database.

TIME - Time formatted for the underlying SQL database.

BOOL - Boolean 1 or 0. Implemented as SQL boolean value in PostGreSQL and char<1> is MySQL.

BOOLEAN - Alias for BOOL.

DATETIME- Is formatted for both date and time as provided for in the SQL database.

2.2.4. TYPE (Complex Fields)

The TYPE syntax allows the creation of complex types. Complex types can be used in CLASS definitions as shorthand. The syntax essentially the same as CLASS and is:


Syntax:

    TYPE type_name
    {

    };

Example:

    TYPE money
    {
        int  amount;
        char currency<3>;
    };

This allows the following to work:

    CLASS item
    {
        money   cost;
        char    desc<25>;
    };

This creates the fields item::cost.amount and item::cost.currency. And is roughly the same as doing:


    CLASS item
    {
      int     cost_amount;
      char    cost_currency<25>;
      char    desc<25>;
    };


2.2.5. TYPE (Typedef) (NOT IMPLEMENTED YET)

The TYPE syntax also allows the specification of general types. The syntax is:


Syntax:
    TYPE new_type = base_type<size>;  (NOT IMPLEMENTED YET)

Where:
    new_type - is the name of the new type.
    
    base_type - is a previously existing type.
    
    size - is the size of the type if necessary.
    
Example:

    TYPE product_code = char<25>;

This defines a new type called product_code that can be used in class definitions.


    MODULE inventory
    {
      TYPE product_code = char<25>;
      TYPE product_class = char<8>;
    
      CLASS product
      {
        inventory::product_code  product_id;
        inventory::product_class class;
        char                     description<100>;
      };
    
      CLASS product_classification
      {
        inventory::product_class class;
        char                     description<20>;
      };
    };

In this example product.class is defined as a char<8> and product.product_id is defined as a char<15>;

As you can see using TYPE you only have to define the size of a field once and dont have to worry about a mistake in another definition causing a related field to be a different size.

To reference types from another module use the fully qualified name. For example:

    inventory::product_code

2.2.6. Comments

Comments start with the "#" character and continue to the end of the line.

For example:

    char   phone_code<4>;    # for validating phone country code

2.2.7. Include

The include statement is used to reference classes defined outside of the current file. The include path is relative to the current file. If the file has already been included the scanner will not include it a second time.

For example:

    include "../../../base/location/classes/address.gcd"

You may not have more than one file with the same name. Paths do not make files unique to GEAS. Therefore you may not have the following:

    include "../../../base/location/classes/address.gcd"
    include "../../../supply-chain/vendor/classes/address.gcd"

The second file will never ever get processed.

2.2.8. ORDER BY

Classes can have an 'order by' section, that causes all queries to be sorted on a given field. (er, should have been multiple fields - call that a TODO)

Syntax:

   ORDER BY  [DESC];

Examples:

class hello
{
    int32 field;
    ORDER BY field;
};

class there
{
    int32 field;
    ORDER BY field DESC;
};

(with the query API - ie, the classes defined in query.idl - the 'DESC' option reverses the sort order.)

2.2.9. LOOKUP

NoteUse of LOOKUP, REFERENCE, and LIST
 

We are not really happy with the LOOKUP, REFERENCE and LIST keywords. They make it possible to link tables together with a field that is not the primary key, even with a field that is not guaranteed to have an unique value.

What we would rather like it if geas made it possible to define any field of an object explicitely as the primary key of the table, and that all references would use _that_ field for the foreign key. Only if no field was explicitely defined as primary key, geas would create the implicite objectid. But that's way ahead.

Meanwhile we expect that the usage of the LOOKUP, REFERENCE and LIST syntax will be depreciated.

Apart from that, we will in most cases use the objectid as the primary key; we have discussed that in detail some time ago and widely agreed on not having user-visible primary keys.

The lookup type is used to lookup a field from another class. A LOOKUP can be defined where a field is defined in the class definition.

Syntax:

    LOOKUP new_fld_name : src_class(src_fld).src_data = comp_field;

Where:
    new_fld_name - is the new field name for reference in the class. It
         does not result in a table column in the database.
    
    src_class - is the name of the source class used to find the lookup
         data.  If this class is in a different module then is requires
         a fully qualified name.
    
    src_data - is the data that is copied into the new_fld_name.
    
    comp_field - is the field from the current class that is matched.
    
Therefore:
       if src_class.src_fld equal comp_field then
           src_class.src_data is copied into new_fld_name

2.2.10. REFERENCE

NoteUse of LOOKUP, REFERENCE, and LIST
 

We are not really happy with the LOOKUP, REFERENCE and LIST keywords. They make it possible to link tables together with a field that is not the primary key, even with a field that is not guaranteed to have an unique value.

What we would rather like it if geas made it possible to define any field of an object explicitely as the primary key of the table, and that all references would use _that_ field for the foreign key. Only if no field was explicitely defined as primary key, geas would create the implicite objectid. But that's way ahead.

Meanwhile we expect that the usage of the LOOKUP, REFERENCE and LIST syntax will be depreciated.

Apart from that, we will in most cases use the objectid as the primary key; we have discussed that in detail some time ago and widely agreed on not having user-visible primary keys.

The explicit reference type is used to get a complete instance of a class object. A REFERENCE can be defined where a field is in the class definition. Its syntax is nearly the same as LOOKUP.

    REFERENCE new_fld_name : src_class(src_field) = comp_field;

Where:


    new_fld_name - is the new field name for reference in the class. It
         does not result in a table column in the database.
    
    src_class - is the fully qualified name of the source class used to 
         find the lookup data.
         
    src_field - is the field in the src_class used for comparison.
    
    comp_field - is the field from the current class that is matched.

Therefore:

The new_fld_name is a reference to an object instance where src_fld and comp_field match.

In the following example, order2 represents an explicit REFERENCE and order1 represents an implicit REFERENCE. Each field references the specific instance of the order:master object from the order::detail object. In the case of the implicit REFERENCE (order1) the reference is make by using the objectid of order::master. In the case of the explicit REFERENCE (order2) the field order_number is used to relate the objects.

MODULE order
{
  class master
  {
    int     order_number;
    char    stuff<20>;
    int     more_stuff;
    char    the_last_stuff<20>; 
  };

class detail
  {
    int       order_number;
    REFERENCE        order2 : order::master(order_number) = this.order_number;
    order::master [] order1;
    int       detail_stuff;
    char      last_detail_stuff;
  };
};

REFERENCE is used to implement many to one relationships. A short hand way to create a REFERENCE is to use the following syntax:


    src_module::src_class *new_fld_name;
    

This is a shortcut for:


    REFERENCE new_fld_name : src_module::src_class(id) = other_new_fld_name;
    

Where id and other_new_fld_name are fields that are used and maintained automatically by geas.

To make this work in theory, you're supposed to programmatically use container.setReference(fieldname,object) and container.getReference(fieldname) from the client code and let GEAS handle the reference automatically.

2.2.11. LIST

NoteUse of LOOKUP, REFERENCE, and LIST
 

We are not really happy with the LOOKUP, REFERENCE and LIST keywords. They make it possible to link tables together with a field that is not the primary key, even with a field that is not guaranteed to have an unique value.

What we would rather like it if geas made it possible to define any field of an object explicitely as the primary key of the table, and that all references would use _that_ field for the foreign key. Only if no field was explicitely defined as primary key, geas would create the implicite objectid. But that's way ahead.

Meanwhile we expect that the usage of the LOOKUP, REFERENCE and LIST syntax will be depreciated.

Apart from that, we will in most cases use the objectid as the primary key; we have discussed that in detail some time ago and widely agreed on not having user-visible primary keys.

The LIST type is used to get multiple instances of a class object. A LIST can be defined where a field is defined in the class definition. Its syntax is nearly the same as LOOKUP.


    LIST new_fld_name : src_class(src_field) = comp_field;

Where:
    new_fld_name - is the new field name for reference in the class. It
         does not result in a table column in the database.
    
    src_class - is the name of the source class used to find the lookup
         data.  If this class is in a different module then is requires
         a fully qualified name.
    
    src_field - is the field in the src_class used for comparison.

    comp_field - is the field from the current class that is matched.

Therefore:
    The new_fld_name is a reference to an object instance where src_fld and
    comp_field match.

List is typically used to create one to many relationships (master-detail). Many to many relationships require an intermediate class. A short hand way to create a LIST is to use the following syntax:

	
    src_class [] new_fld_name;

This is a shortcut for:


    LIST new_fld_name : src_module::src_class(id) = other_new_fld_name;
    

Where id and other_new_fld_name are fields that are used and maintained automatically by geas.

To make this work in theory, you're supposed to programmatically use container.setReference(fieldname,object) and container.getReference(fieldname) from the client code and let GEAS handle the reference automatically.

In the following example, detail1 represents an explicit LIST and detail2 represents an implicit LIST. Each field references the specific instances of the order:detail objects from the order::master object. In the case of the implicit LIST reference (detail2) the reference is make by using the objectid's of order::detail. In the case of the explicit LIST reference (detail1) the field order_number is used to relate the objects.

MODULE order
{
  class master
  {
    int               order_number;
    LIST              detail1 : order::detail(order_number) = this.order_number;
    order::detail  [] detail2;
  }; 

class detail
  {
    int       order_number;
    int       detail_stuff;
    char      last_detail_stuff;
  };
};

2.2.12. METHOD

Methods allow a call to C or Python code. A method can be defined where a field is defined in the class definition. Its syntax is:


    return_type method_name(arg_type arg_name);
    

Where:


    return_type - the type (CHAR, INT, FLOAT) of the returned value, 
        if any.  The only type currently working is CHAR.
    method_name - the method name.
    arg_type - the type of the argument.  See caveat below.
    arg_name - the argument name.
    

Caveat - the only type passed to C or Python is string type. So your method code will have to do conversions as necessary.

Example:


    class test
    {
      char callme( int a , int b );
    };

Python Example


    import string

    def test_callme(obj,a,b,server):
        print "callme called"
        print "this.name = " + obj.getField("name")
        return obj.getField("name")


C Example:


    #include <glib.h>
    #include <gmodule.h>
    #include <stdio.h>
    #include "../../../src/geas.h"
    #include "../../../src/exceptions.h"

    G_MODULE_EXPORT char *
    test_callme( GEAS_DataObject obj , GEAS_Arguments *args ,
                 GEAS_Connection server , CORBA_Environment *ev )
    {
       /* concatenate arguments using g_strdup_printf */
       CORBA_char *retval;
       char *tmp = g_strdup_printf( "%s:%s" , args->_buffer[0] , args->_buffer[1] );

       retval = CORBA_string_dup( tmp ); // must use CORBA_string_dup for return vlaues
       g_free( tmp ); 

       return( retval );
    }

2.2.13. Inheritance

Classes can inherit from parent classes. The syntax is:


    CLASS class_name : parent1_class, parent2_class
    {

    };

CLASS example:


    CLASS item
    {
      char  desc<25>;
    };
    
    CLASS stock_item
    {
      int quantity_on_hand;
    };
    
    CLASS sales_item : item, stock_item
    {
      float  price;
    };

TYPE example


    TYPE item
    {
      char  desc<25>;
    };
    
    TYPE stock_item
    {
      int quantity_on_hand;
    };
    
    TYPE sales_item : item, stock_item
    {
      float  price;
    };

Where:

    item - is a parent of sales_item.
    
    stock_item - is a parent of sales_item.

Inheritance works for both CLASS or TYPE, but you can not mix them.

The field sales_item.desc is the description inherited from class item and sales_item.quantity_on_hand is inherited from class stock_item. Of course you can still refer directly to the parent class as item.desc or stock_item.quantity_on_hand.

If a field name is used more than once in parent and child classes then geas will die a slow and terrible death. (Hopefully this will be fixed soon.)