Recently at ST Electronics I was asked to help the C++ client application development team for the Future School Project. At a late stage in development they needed a database, and a data layer, and quickly.
The data layer should support an ADO data source like MS Access now, and potentially an embedded database like SQLite later.
When approached, given the time and budget constraints, I wanted to provide something which made it easy for developers to use, yet was flexible enough they could plug in support for other databases later. This flexibility was important because it meant I could concentrate on addressing their immediate needs (MS Access) without investing time in what they may or may not need later (SQLite ) – obeying the YAGNI principle via the GRASP Protected Variation pattern.
Being an advocate of declarative programming, convention over configuration, and code generation I was looking for a simple mechanism that allowed the developers to declare what they wanted.
In C# I would typically solve this problem via attributes and reflection but in C++ the runtime type information is limited. C++ Template meta-programming is something I have only just begun investigating, so that wasn’t an option for me. In the end I settled for good old fashioned Macros – I know, most developers have relegated them to the sidelines along with the goto statement…
In this scenario, macros fitted like a glove.
Along with CRUD operations, I provided support for queries and other extensions via this mechanism. Here is a simple example of declaring entity information using this macro based DSL:
class AvatarInventoryItem:public ClientDatabase::DataEntity{
public:
__int(Id)
__int(ObjectId)
__int(ActionId)
__bool(IsActive)
__float(XPosition)
__float(YPosition)
__float(ZPosition)
__float(XRotation)
__float(YRotation)
__float(ZRotation)
__int(UserId)
__datetime(LastChangeTime)
__table(AvatarInventory)
__key(Id,int,true)
};
class AvatarInventory:public ClientDatabase::Table<AvatarInventoryItem>{
public:
__selectall(AvatarInventory)
};
Here is an example of reading data from the table:
auto_ptr<AvatarInventory> inventory(AvatarInventory::SelectAll());
while(inventory->HasData()){
auto_ptr<AvatarInventoryItem> item(inventory->PopBack());
cout << ” Id:” << item->GetId() << endl;
}
Another example, using a different class, saving data:
Application * application=new Application();
application->SetName(L”Test Application”);
application->SetOfflineAccess(true);
application->Save();
The factory and dataservice interface provided the indirection I needed to support other databases:
IDataService * service=DataServiceFactory::Create("access","C:\\data\\MsAccess.mdb");
Database.Initialize(service);
All in all, I’m pretty happy with, yes you guessed it, macros – perhaps I need to revisit the goto statement now, after all most conditions compile down to a jump statement


