_Relational C++ Objects_
by Eric Kass


Example 1:
DBObject* GetFirst(char *SQLFrom, char *SQLWhere=NULL);
DBObject* GetFirst(CLASSID ClassID, char *SQLWhere=NULL);
DBObject* GetNext();

Example 2:
AddObject(DBObject *Object
RemoveObject(DBObject *Object)
GetFirst()
GetNext()


Listing One
class PersonInterface : public DBInterface
    {
    char Name[50];
    DATE Birthday;
    }
class Person : public DBObject
    {
    Person() {AddInterface(PersonInterface);}
    }
class StudentInterface : public DBInterface
    {
    char Major[50];
    }
class Student : public Person
    {
    Student () {AddInterface(StudentInterface);}
    }
class BookInterface : public DBInterface
    {
    char Title;
    INSTID Author;
    char Publisher[50];
    }
class Book : public DBObject
    {
    Book() {AddInterface(BookInterface);}
    }

Listing Two
DBObjectQuery Query(ODB);
student = Query.GetFirst(Student, " Birthday < 1972");
while (student)
    {
    Iperson = studentrGetInterface(Person);
    cout << IpersonrGetName();
    student = Query.GetNext();
    }
    
Listing Three
DBObjectQuery Query(ODB);
From = "Persons JOIN Books ON Persons.ID = Books.Author";
Where = "Books.Publisher = 'Random House'";
current = Query.GetFirst(From,Where);
while (current)
    {
    Iperson = currentrGetInterface(Person);
    cout << "Author: " << IpersonrGetName();
    current = Query.GetNext();
    }

Listing Four
struct InterfaceRecord : public LinkList<InterfaceRecord>
    {
    flag Loaded;
    CLASSID ClassID;
    flag NewInterface;
    DBInterface *Interface;
    };
bool DBObject::Save()
    {
    bool Status = true;
    InterfaceRecord *Record;
    ODB.BeginTransaction();
    try {
        Record = Interfaces.GetFirst();
        while (Record && Status)        // Save each interface.
            {
            Status = SaveInterface(Record);
            Record = Interfaces.GetNext(Record);
            }
        }
    catch (...)
        {
        Status = false;
        }
    if (Status) ODB.Commit();
    else ODB.Rollback();
    return Status;
    }
bool DBObject::SaveInterface(InterfaceRecord *Record)
    {
    bool Status = true;
    DBInterface *Interface = Record->Interface;
    if (Interface && Record->Loaded)
        {
        Status = Interface->Update();   // Save preexisting interface.
        }
    else    {
        if (!Interface)                 // Need to access interface.
            {
            CLASSID ClassID = Record->ClassID;
            Interface = ODB.CreateInterface(ClassID,InstID);
            Record->Interface = Interface;
            }
        if (Record->NewInterface)   // Create new interfaces.
            {
            Status = Interface->Create();
            Record->NewInterface = false;
            Record->Loaded = true;
            }
        }
    return Status;
    }

Listing Five
DBInterface* DBObject::GetInterface(CLASSID ClassID) 
    {
    InterfaceRecord *Record;
    Record = SearchInterfaceCache(ClassID);
    if (!Record)                        // Not in cache.
        {
        LoadInterfaceList();
        Record = SearchInterfaceCache(ClassID);
        if (!Record) return NULL;           // Not a member.
        }
    if (!Record->Interface)             // No instance exists...
        {
        Record->Interface = ODB.CreateInterface(ClassID,InstID);
        Record->Interface->Init();
        }
    if (!Record->Loaded && !Record->NewInterface)
        {
        Record->Interface->Load()       // Load data from DB.
        Record->Loaded = true;
        }
    return Record->Interface;
    }


Listing Six
BINDING(Class, Member, Type, Index)
   Class = Name of the interface.
    Member = Name of the class member.
    Type = String, Date, Double, Long
    Index = Controls whether an index is created on the field.

Listing Seven 
ComputeOffset(Class,Member) 
    ((long)(&((Class *)0)->Member) +
         (long)(&((DBInterface *)0)->_Locator) - 
               (long)(&((Class *)0)->_Locator))


Listing Eight
class IAnimal : public DBInterface
    {
    private:
        DWORD _Sz;
        char Name[30];
        unsigned long Age;
    public:
        INIT_INTERFACE(IAnimal);
        void SetData(Name,Age);
        char* GetName();
        unsigned long GetAge();
    };
BEGIN_BINDING_TABLE(IAnimal,2);
    VAR_BINDING(IAnimal,Name,FT_String,30,_Sz,true);
    BINDING(IAnimal,Age,FT_Long,false);
END_BINDING_TABLE;

Listing Nine
Scheduler(ObjectDatabase &ODB);
flag AddReservation(Equipment &Item, Schedule &Reservation);
flag RemoveReservation(Equipment &Item, DATETIME &StartTime);
flag RemoveReservation(Equipment &Item, Schedule &Reservation);
Equipment* QueryAll(CLASSID EQtype, DATETIME *Start, DATETIME *End,
            User *ByWhom=NULL, Location *Place=NULL);
Equipment* QueryAvailable(CLASSID EQtype, DATETIME &Start, DATETIME &End);
Equipment* QueryNext();

Listing Ten
SELECT Equipment.ID FROM 
(IEquipment INNER JOIN IScheduleSet ON IEquipment.ID = 
IScheduleSet.Owner) INNER JOIN ISchedule ON 
IScheduleSet.Member = ISchedule.ID WHERE 
(ISchedule.StartTime >= 12/9/1996) AND 
(ISchedule.EndTime <= 12/9/1996 0:0) AND 
(ISchedule.Who = 752) AND 
(ISchedule.Place = 4) AND 
(IEquipment.Type = 2004)

Listing Eleven
flag Equipment::IsAvailable(DATETIME &Start, DATETIME &End)
    {
    char DateQuery[100];
    IScheduleSet *Schedules;
    ReservedString(DateQuery,Start,End);
    Schedules = (IScheduleSet *)GetInterface(ScheduleSetID);
    if (!Schedules) return false;
    DBObject *Item = Schedules->GetFirst(ScheduleID,DateQuery);
    if (Item) delete Item;
    return Item == NULL;        // True if no Reservation.
    }


Listing Twelve
// Object Database Test

#include <stdio.h>
#include <conio.h>
#include <sqlobj.h>

#define PersonID 1001
#define ChildSetID 1002

class Person : public DBObject
    {
    public:
        Person(ObjectDatabase &ODB) : DBObject(ODB)
            {
            AddInterface(PersonID);
            AddInterface(ChildSetID);
            }
    };
class Children : public DBSetInterface
    {
    public:
        INIT_SETINTERFACE(Children);
        flag AddPerson(Person *p) {return AddObject(p);}
        flag RemovePerson(Person *p) {return RemoveObject(p);}
    };
class PersonInterface : public DBInterface
    {
    private:
        char Name[30];
        DWORD _NameSize;
        unsigned long Age;
    public:
        INIT_INTERFACE(PersonInterface);
        void SetData(char *name, long age)
            {
            strcpy(Name,name);
            Age = age;
            }
        char* GetName() {return Name;}
        unsigned long GetAge() {return Age;}
    };
BEGIN_BINDING_TABLE(PersonInterface,2);
    VAR_BINDING(PersonInterface,Name,FT_String,30,_NameSize,true);
    BINDING(PersonInterface,Age,FT_Long,false);
END_BINDING_TABLE;

char *Names[] = {"Beth","Debbie","Bob","Mary","John","Laura",NULL};
long Ages[] = {43,13,12,21,6,10,0};

void ComplexQuery(ObjectDatabase &ODB, char *ChildName)
    {
    DBObject *Current;      // Prints the parents of a Child.
    char *From, Where[100];
    PersonInterface *IPerson;
    DBObjectQuery Query(ODB);
    From = "(PersonInterface AS Parent "
           "INNER JOIN Children ON Parent.ID = Children.Owner) INNER JOIN "
           "PersonInterface AS Child ON Children.Member = Child.ID ";
    sprintf(Where,"Child.Name = '%s'",ChildName);
    Current = Query.GetFirst(From,Where);
    while (Current)
        {
        IPerson = (PersonInterface *)Current->GetInterface(PersonID);
        printf("Parent: %s\n",IPerson->GetName());
        delete Current;
        Current = Query.GetNext();
        }
    return;
    }
void View(ObjectDatabase &ODB)          // Prints the names of Beth's
    {                                   // children who are older than 12.
    DBObject *Parent;
    Children *IChildren;
    PersonInterface *IPerson;
    DBObjectQuery Query(ODB);
    Parent = Query.GetFirst(PersonID,"Name='Beth'");
    IPerson = (PersonInterface *)Parent->GetInterface(PersonID);
    IChildren = (Children *)Parent->GetInterface(ChildSetID);
    printf("Name: %s\n",IPerson->GetName());
    printf("Age: %lu\n",IPerson->GetAge());
    DBObject *Child = IChildren->GetFirst(PersonID,"Age >= 12");
    while (Child)
          {
          IPerson = (PersonInterface *)Child->GetInterface(PersonID);
          printf("Child: %s (%lu)\n",IPerson->GetName(),IPerson->GetAge());
          delete Child;
          Child = IChildren->GetNext();
          }
    delete Parent;
    return;
    }
void Make(ObjectDatabase &ODB)          // Adds users to the database
    {                                   // making the first the parent
    Person Parent(ODB);                 // of all the others.
    Children *IChildren;
    PersonInterface *IPerson;
    IPerson = (PersonInterface *)Parent.GetInterface(PersonID);
    IChildren = (Children *)Parent.GetInterface(ChildSetID);
    IPerson->SetData(Names[0],Ages[0]);
    Parent.Save();
    for (int i=1; Names[i]; i++)
        {
        Person Child(ODB);
        IPerson = (PersonInterface *)Child.GetInterface(PersonID);
        IPerson->SetData(Names[i],Ages[i]);
        IChildren->AddPerson(&Child);
        Child.Save();
        }
    Parent.Save();
    return;
    }
main()
    {
    ObjectDatabase ODB("Persons","","");
    ODB.Connect();
    REGISTER_INTERFACE(ODB,PersonInterface,PersonID);
    REGISTER_SETINTERFACE(ODB,Children,ChildSetID);
    Make(ODB);
    View(ODB);
    ComplexQuery(ODB,"John");
    ODB.Disconnect();
    getch();
    return 0;
    }

Listing Thirteen
// Reservation System 
#include <assert.h>
#include <stdio.h>
#include <conio.h>
#include <sqlobj.h>

#pragma hdrstop
#include <schedule.h>
void PrintSchedule(Equipment &Item)
    {
    IScheduleSet *Reservations;
    Reservations = (IScheduleSet *)Item.GetInterface(ScheduleSetID);
    if (!Reservations) return;
    Schedule *Reservation = (Schedule *)Reservations->GetFirst();
    while (Reservation)
          {
          ISchedule *iReservation;
          iReservation = (ISchedule*)Reservation->GetInterface(ScheduleID);
          if (iReservation)
            {
            char Start[100], End[100];
            DateToString(Start,iReservation->GetStartDate());
            DateToString(End,iReservation->GetEndDate());
            printf("     Reserved: %s TO %s\n",Start,End);
            }
          delete Reservation;
          Reservation = (Schedule *)Reservations->GetNext();
          }
    return;
    }
void PrintEquipment(ObjectDatabase &ODB)
    {
    Scheduler Reservations(ODB);
    Equipment *equipment = Reservations.QueryAll(EquipmentID);
    while (equipment)
        {
        IEquipment *iEquipment;
        iEquipment = (IEquipment*)equipment->GetInterface(EquipmentID);
        if (iEquipment)
            {
            printf("Item: %s\n",iEquipment->GetDescription());
            PrintSchedule(*equipment);
            }
        delete equipment;
        equipment = Reservations.QueryNext();
        }
    return;
    }
void PrintUsers(ObjectDatabase &ODB)
    {
    DBObjectQuery Query(ODB);
    User *user = (User *)Query.GetFirst(UserID);
    while (user)
        {
        Users *iUser;
        iUser = (Users *)user->GetInterface(UserID);
        if (iUser) printf("User: %s\n",iUser->GetName());
        delete user;
        user = (User *)Query.GetNext();
        }
    return;
    }
void Test(ObjectDatabase &ODB)
    {
    Scheduler Reservations(ODB);
    Equipment Sony(ODB,"Sony Monitor");
    Sony.Save();
    Computer IBM(ODB,"IBM Computer");
    Schedule Reservation(ODB,NULL,NULL,"1/2/1996","2/3/1997");
    Reservations.AddReservation(IBM,Reservation);
    Reservations.RemoveReservation(IBM,"1/2/1996");
    Reservation.Save(); 
    IBM.Save();
    PrintEquipment(ODB);    
    return;
    }
main()
    {
    ObjectDatabase ReservationODB("Reservations","","");
    flag Status = ReservationODB.Connect();
    if (!Status)
        {
        printf("\nCan't Connect To Database\n");
        getch();
        }
    RegisterInterfaces(ReservationODB);
    Test(ReservationODB);
    getch();
    ReservationODB.Disconnect();
    return 0;
    }


