Skip to content
Trefilov Dmitrij edited this page Jan 31, 2016 · 1 revision

##Table declaration Let's see the code sample of how you are declaring the schema of an example database.

class City : public Object
{
public:
    int             id;
    String          name;

    META_INFO_DECLARE(City)
};

STRUCT_INFO_BEGIN(City)
    FIELD_INFO(City, id)
    FIELD_INFO(City, name, "Moscow")
STRUCT_INFO_END(City)

REFLECTIBLE_F(City)
META_INFO(City)

DECLARE_STORABLE(City,
                 PRIMARY_KEY(COL(City::id)),
                 UNIQUE_INDEX(COL(City::id))
                 )

class Person : public Object
{
public:
    int             id;
    String          name;
    Nullable<int>   age;
    Nullable<double> cat_weight;
    int             cityId;

    META_INFO_DECLARE(Person)
};

STRUCT_INFO_BEGIN(Person)
    FIELD_INFO(Person, id)
    FIELD_INFO(Person, name)
    FIELD_INFO(Person, age)
    FIELD_INFO(Person, cat_weight)
    FIELD_INFO(Person, cityId)
STRUCT_INFO_END(Person)

REFLECTIBLE_F(Person)
META_INFO(Person)

DECLARE_STORABLE(Person,
                 PRIMARY_KEY(COL(Person::id)),
                 REFERENCES(COL(Person::cityId), COL(City::id)),
                 UNIQUE_INDEX(COL(Person::id)),
                 INDEX(COL(Person::cityId)),
                 CHECK(COL(Person::age), COL(Person::age) < 120)    // people do not live so much
                 )

Here we have two tables: City and Person. First of all you are declaring class derived from Object with it's metadata (see page). This data is used for accessing object fields at run-time and binding them to the tables in relational database. With macro DECLARE_STORABLE(Table) we are instantiating wrapper template class Storable<Table> and providing table constraint definitions. Next we may use this information to create database schema

SqlTransaction transaction;
Storable<City>::createSchema(transaction);
Storable<Person>::createSchema(transaction);
transaction.commit();

This will execute the following SQL code (in sqlite3 syntax)

CREATE TABLE IF NOT EXISTS City(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL DEFAULT 'Moscow')
CREATE UNIQUE INDEX IF NOT EXISTS idx_City_id ON City(id)
CREATE TABLE IF NOT EXISTS Person(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL DEFAULT 'noname', age INTEGER CHECK (Person.age < 120), cat_weight REAL, cityId INTEGER NOT NULL REFERENCES City(id))
CREATE UNIQUE INDEX IF NOT EXISTS idx_Person_id ON Person(id)
CREATE INDEX IF NOT EXISTS idx_Person_cityId ON Person(cityId)

##Object manipulations ###Selections

try
{
    SqlTransaction transaction;
    Storable<Person> person;
    SqlResultSet resultSet = person.select().innerJoin<City>().where((COL(Person::age).isNull() ||
                                            COL(Person::age) + 2.5  * COL(Person::cat_weight) > 250) &&
                                            COL(Person::cityId) == COL(City::id) &&
                                            !COL(Person::name).like("invalid_%") &&
                                            COL(City::name) == String("Bangkok")).
                                            limit(10).exec(transaction);

    for (auto rowId : resultSet)
    {
        std::cout << person.name << std::endl;
    }
    transaction.commit();
}
catch (const std::exception& ex)
{
}

This code will build and execute following statement

SELECT Person.id, Person.name, Person.age, Person.cat_weight, Person.cityId FROM Person INNER JOIN City ON (((Person.age IS NULL OR (Person.age + (2.5 * Person.cat_weight)) > 250) AND Person.cityId = City.id) AND NOT Person.name LIKE 'invalid_%') AND City.name = 'Bangkok' LIMIT 10

... after which will print out names of all persons. Here SqlResultSet is a forward-iterable collection of rows. Each time the iterator is advanced to the next row, the result is written to the storable object.

###Insertions Insertions are used for persisting of objects. The sample code is pretty strait forward.

try
{
    SqlTransaction transaction;
    Storable<City> city;
    auto resultSet = city.select().where(COL(City::name) == String("Moscow"))
            .exec(transaction);
    auto it = resultSet.begin();
    if (it != resultSet.end())
    {
        Storable<Person> person;
        person.init();
        person.id = 0;
        person.age.reset();
        person.cat_weight.reset();
        person.cityId = city.id;
        person.name = "Pupkin";
        person.insertOne(transaction);
    }

    transaction.commit();
}
catch (const std::exception& ex)
{
    throw;
}

There's no need in manual manipulations with SqlStatementSelect, you are simply initializing all fields of the object and invoking insertOne() on it. After inserting, the auto-generated primary key (if exists) is filled with it's correct value.

###Updates It is possible to perform updates in two different ways. By manual specification of SqlStatementUpdate:

try
{
    SqlTransaction transaction;
    Storable<Person> person;
    person.update().ref<City>().set(COL(Person::age) = null, COL(Person::cat_weight) = null)
            .where(COL(Person::cityId) == COL(City::id) && COL(City::name) == String("Moscow") &&
                   (COL(Person::age) == null || COL(Person::cat_weight) == null)).exec(transaction);
    transaction.commit();
}
catch (const std::exception& ex)
{
    throw;
}

By persisting changes of object previously selected from the database by calling updateOne():

person.updateOne(transaction);

###Deletions Deletions are performed similar to updates. By specification of SqlStatementDelete:

try
{
    SqlTransaction transaction;
    Storable<Person> person;
    int numRows = person.remove().ref<City>().where(COL(City::id) == COL(Person::cityId) &&
                                                    COL(City::name) == String("Moscow") &&
                                                    COL(Person::name).like("invalid_%")).exec(transaction);
}
catch (const std::exception& ex)
{
    throw;
}

By calling removeOne():

person.removeOne(transaction)

##Connectors Metacpp currently supports PostgreSQL, MySQL and Sqlite3 DBMSes.

Clone this wiki locally