Library for initializing database tables

Every time an app instance is started it needs to check if the database already contains the desired tables and otherwise create them. After software updates it might also need to add new columns to existing tables. This library provides a small collection of tasks that facilitate that job.

File information

Filecommon/lib/tasks_postgresql.htm

Classes TaskPostgreSQLInitTable
TaskPostgreSQLInitEnum

Examples Initializing a database using multiple sequential tasks

Classes

TaskPostgreSQLInitTable

A task that creates a single table including columns, constraints and indices, if not existing. Additional columns, constraints and indices are added if they don't exist.

class TaskPostgreSQLInitTable : public ITask, public UDatabase {
    ...
public:
    TaskPostgreSQLInitTable(class IDatabase * database, const char * tableName);
    virtual ~TaskPostgreSQLInitTable();
    void AddColumn(const char * name, const char * type);
    void AddConstraint(const char * name, const char * value);
    void AddIndex(const char * name, const char * value, bool unique);
    void Start(class UTask * user) override;
};

TaskPostgreSQLInitTable

Contructor used to initialize the class.

Parameters

class IDatabase * database The IDatabase object representing the connection to the database.
const char * tableName The name of the table.
The CREATE statement puts the tableName inside double quotes.
Pay attention about the casing and chars inside the tableName. If you e.g. use uppercase letters or spaces within the table name, you must later double quote the table name in your queries yourself too!

AddColumn

Specifies a column for the database table.

Parameters

const char * name The name of the column.
const char * type The type of the column, e.g. "VARCHAR(32) UNIQUE NOT NULL".

AddConstraint

Specifies the constraint of a column.

Parameters

const char * name The name of the column.
const char * value The constraint of the column, e.g. "UNIQUE (domain_id, name)".

AddIndex

Adds an index to the table. Indices can include a single column or multiple columns.

Parameters

const char * name The name of the index.
const char * value A comma separated list of column names, e.g. "domain_id, name".
bool unique Tells if the data in the specified columns is unique.

Start

Starts the task of checking / creating the table.

Parameters

class UTask * user The UTask object that shall receive the TaskComplete or TaskFailed callback after completion.

TaskPostgreSQLInitEnum

A task that creates an enum in the database, if it does not already exist.

class TaskPostgreSQLInitEnum : public ITask, public UDatabase {
    ...
public:
    TaskPostgreSQLInitEnum(IDatabase * const database, const char * enumName);
    virtual ~TaskPostgreSQLInitEnum();
    void AddValue(const char * name);
    void Start(class UTask * user) override;
};

TaskPostgreSQLInitEnum

Contructor used to initialize the class.

Parameters

class IDatabase * database The IDatabase object representing the connection to the database.
const char * enumName The name of the enum.

AddValue

Adds a single value to the enum.

Parameters

const char * name The value to be added, e.g. "DEMO_TYPE_1"

Start

Starts the task of checking / creating the enum.

Parameters

class UTask * user The UTask object that shall receive the TaskComplete or TaskFailed callback after completion.

Code Examples

Initializing a database using multiple sequential tasks


#include "platform/platform.h"
#include "common/interface/database.h"
#include "common/interface/task.h"
#include "common/lib/tasks_postgresql.h"
#include "sysadmin_tables.h"

TaskDatabaseInit::TaskDatabaseInit(IDatabase * database) :
initEnum(database, "demo_type"),
initDomains(database, "domains"),
initLocations(database, "locations"),
{
    // enums
    initEnum.AddValue("DEMO_TYPE_1");
    initEnum.AddValue("DEMO_TYPE_2");
    initEnum.AddValue("DEMO_TYPE_3");
    // domains
    initDomains.AddColumn("id", "BIGSERIAL PRIMARY KEY NOT NULL");
    initDomains.AddColumn("name", "VARCHAR(32) UNIQUE NOT NULL");
    initDomains.AddColum("enum_demo", "demo_type"); // Type of the field = name of the enum
    initDomains.AddIndex("domains_index_name", "name", false);
    // locations
    initLocations.AddColumn("id", "BIGSERIAL PRIMARY KEY NOT NULL");
    initLocations.AddColumn("domain_id", "BIGINT REFERENCES domains(id)");
    initLocations.AddColumn("name", "VARCHAR(32) NOT NULL");
    initLocations.AddConstraint("locations_unique_name", "UNIQUE (domain_id, name)");
    initLocations.AddIndex("locations_index_name", "domain_id, name", true);  // index on several columns
}

TaskDatabaseInit::~TaskDatabaseInit()
{
}

void TaskDatabaseInit::Start(class UTask * user)
{
    this->user = user;
    initEnums.Start(this);
}

void TaskDatabaseInit::TaskComplete(class ITask * const task)
{
    if (task == &initEnum) initDomains.Start(this);
    else if (task == &initDomains) initLocations.Start(this);
    else if (task == &initLocations) user->TaskComplete(this);
    else ASSERT(false, "TaskDatabaseInit::TaskComplete");
}

void TaskDatabaseInit::TaskFailed(class ITask * const task)
{
    user->TaskFailed(this);
}