mRFC 0016: MgdSchema API
- Functionality
- Data model
- Object creation
- Object retrieval
- MidgardObject *midgard_object_find(GType type, guint id)
- MidgardObject **midgard_object_find_matching(GType type, MidgardQueryBuilder *builder, guint *nobjects)
- Query builder
- Object modification
- gint midgard_object_update(MidgardObject *object)
- gint midgard_object_update_matching(MidgardObject *object, MidgardQueryBuilder *builder)
- Object removal
- gint midgard_object_delete(GType type, guint id)
- gint midgard_object_delete_matching(GType type, MidgardQueryBuilder *builder)
- Parameters
- Attachments
- Metadata
- Sitegroups
- Localization
- Access control
- Data type inspection
This document specifies the client API of the MgdSchema layer. MgdSchema is an abstraction layer for the Midgard datase, and the client API allows Midgard applications and language bindings to access the database using standard interfaces and a standard object model.
The MgdSchema implementation and configuration is specified in the mRFC 0012 document.
The MgdSchema API depends on the GObject library to provide the standard object model.
Functionality
The MgdSchema client API covers the following functionality:
- Object creation
- Object retrieval
- Object modification
- Object removal
- Access control
- Data type inspection
All data inside the Midgard database is accessible using MgdSchema, and no other mechanism should be used to access the database under normal conditions. MgdSchema defines how to create new objects, how to query and retrieve existing objects, and how to modify and remove them. In addition to a generic query by example -mechanism, MgdSchema also provides generic tree and link abstractions for object retrieval.
The MgdSchema API makes the underlying data model visible by providing a type inspection mechanism that can be used to query the available data types and their properties. This makes it possible to write language bindings that can automatically adapt to new Midgard data types.
Data model
All data managed by MgdSchema is stored in the Midgard database and
structured according to the MgdSchema configuration. MgdSchema provides
a GObject-based object abstraction of this data to the clients. A central
part of this abstraction is the MidgardObject base class that
provides the common functionality of all MgdSchema objects.

During initialization MgdSchema will dynamically generate a
MidgardObject subclass for each configured data type.
These subclasses override the generic MidgardObject
functionality to match the structure of the underlying database.
Clients can then use these subclasses and subclass instances to access
the various data types.
TODO parameters, attachments, metadata, sitegroups, localization, access control
Object creation
The configured MidgardObject subclasses can be instantiated using normal GObject conventions, as shown in the example below.
GType type = ...; /* MidgardObject subclass */
MidgardObject *object = MIDGARD_OBJECT(g_object_new(type, NULL));
Instantiated objects are not associated with any records in the database,
and their properties are set to null values. Such instances are called
template objects, because they can be used as templates for
creating or modifying real records in the database. This is achieved
by first setting the properties of the template object, and then calling
the create() method, as shown below.
g_object_set(object,
"title", "Example title",
"content", "Example content",
NULL);
gint id = midgard_object_create(object);
if (id < 0) {
/* error handling */
}
The create() method uses the properties set in the template object
to create a new record in the table identified by the type of the template object.
See below a more detailed description of the method.
gint midgard_object_create(MidgardObject *object)
Creates a record in the Midgard database. The record table is determined from the type of the given template object, and the fields of the new record are set to the properties of the template object. Default values are used for fields whose properties have not been set. Metadata field values are filled in automatically, and the corresponding object properties are simply ignored.
Returns the id of the created record if it was successfully created. Otherwise
returns -1, and sets the Midgard errno and
errstr variables.
The given template object is not modified by this method.
Arguments:
object: the template object
Return value:
- local id of the created object, or
-1on failure
Object retrieval
There are two mechanism in MgdSchema for retrieving data objects from the Midgard database. The first one allows a client to retrieve objects simply by type and id, while the second permits more complex queries.
Each Midgard object type contains a local id number that is unique for each
record within that type. The find() class method can be used
to retrieve an identified object of a selected type.
GType type = ...; /* MidgardObject subclass */
guint id = ...; /* ID of the selected object */
MidgardObject *object = midgard_object_find(type, id);
if (!object) {
/* error handling */
}
The other retrieval mechanism allows clients to retrieve more than one
object at a time and to use more complex queries to identify the retrieved
objects. The find_matching() class method uses a separate query
builder object generated by the get_query_builder() class
method to specify the query used to identify the retrieved objects.
GType type = ...; /* MidgardObject subclass */
GValue value = ...; /* Some date value for the query */
MidgardQueryBuilder *builder = midgard_object_get_query_builder(type);
midgard_query_builder_add_criteria(builder, "created", ">=", value);
guint nobjects = 0;
MidgardObject **objects =
midgard_object_find_matching(type, builder, &nobjects);
if (!objects) {
/* error handling */
}
See below for the detailed retrieval method signatures. The query builder functionality is described in the next section.
MidgardObject *midgard_object_find(GType type, guint id)
Retrieves the identified object from the Midgard database. The given type and local id number are used to select the database table and row to be returned.
If the identified record is found, it is wrapped into an instance
of the given MidgardObject subclass and returned to the
caller. If the record is not found or if a failure occurs, then a
NULL pointer is returned to the caller. The caller
can use the Midgard errno and errstr
values to determine the cause of a NULL return value.
Arguments:
type: record type (MidgardObjectsubclass)id: the local id of the record
Return value:
- retrieved object, or
NULLon failure or if the record was not found
MidgardObject **midgard_object_find_matching(GType type, MidgardQueryBuilder *builder, guint *nobjects)
Retrieves objects from the Midgard database. The retrieved objects are selected using the given record type and the query built by the given query builder.
The retrived objects are returned as an array of pointers and the
number of objects is stored in the given location.
A NULL pointer is returned on failures. The caller can
then check the Midgard errno and errstr values
to determine the cause of the failure.
Arguments:
type: record type (MidgardObjectsubclass)builder: query buildernobjects: location for the number of retrieved objects
Return value:
- array of retrieved objects, or
NULLon failure
Query builder
TODO
GType type = ...; /* MidgardObject subclass */
MidgardQueryBuilder *builder = midgard_object_get_query_builder(type);
midgard_query_builder_add_criteria(builder, "created", ">=", value);
...
Object modification
MgdSchema provides mechanisms to modify the contents of a single object that was earlier retrieved from the Midgard database or to do batch updates defined by a template object and a query builder.
A single object can be modified by setting some of its properties and
invoking the update() method, as shown below.
MidgardObject *object = ...; /* Retrieved MidgardObject */
g_object_set(object,
"title", "Updated title",
NULL);
gint rv = midgard_object_update(object);
if (rv < 0) {
/* error handling */
}
A batch update can be performed by instantiating and filling in
a template object, building a query, and invoking the
update_matching() method on the template object.
GType type = ...; /* MidgardObject subclass */
MidgardObject *object = MIDGARD_OBJECT(g_object_new(type, NULL));
g_object_set(object,
"title", "Updated title",
NULL);
MidgardQueryBuilder *builder = ...; /* Query to select records to update */
gint rv = midgard_object_update_matching(object, builder);
if (rv < 0) {
/* error handling */
}
See below for the detailed update method signatures.
gint midgard_object_update(MidgardObject *object)
Updates a record in the Midgard database. The record is identified using the type and local id of the given object. The object properties that have changed since the object was retrieved are written to the corresponding fields of the database record. Possible metadata updates are generated automatically.
- Returns
1if the record was successfully updated. - Returns
0if the record was not found in the database. - Returns
-1if a failure occurred. The caller can use the Midgard errno and errstr values to determine the cause of a failure.
Arguments:
object: the object to be updated
Return value:
1if successfull,0if record was not found, or-1on failure
gint midgard_object_update_matching(MidgardObject *object, MidgardQueryBuilder *builder)
Updates records in the Midgard database. The updated records are selected using the type of the given template object and the query built by the given query builder. The properties that have been set in the template object are written to the corresponding fields of the selected database records. Possible metadata updates are generated automatically.
Returns the number of updated records, or -1 if a failure occurred.
The caller can use the Midgard errno and errstr
values to determine the cause of a failure.
Arguments:
object: templage objectbuilder: query builder
Return value:
- number of updated records, or
-1on failure
Object removal
Just like for object retrieval and modification, MgdSchema provides
two mechanisms for removing objects from the database. The class methods
delete() and delete_matching() remove objects
of the selected type either by the local id or a more general query.
A single object can be removed using the delete() class method.
GType type = ...; /* MidgardObject subtype */
guint id = ...; /* ID of the record to be removed */
gint rv = midgard_object_delete(type, id);
if (rv < 0) {
/* Error handling */
}
More than one object can be removed simultaneously by using the
delete_matching() class method and a query builder.
GType type = ...; /* MidgardObject subtype */
MidgardQueryBuilder *builder = ...; /* Query to select records to remove */
gint rv = midgard_object_delete_matching(type, builder);
if (rv < 0) {
/* error handling */
}
See below for the detailed delete method signatures.
gint midgard_object_delete(GType type, guint id)
Removes the identified record from the Midgard database. The given type and local id number are used to select the database table and row to be removed.
- Returns
1if a record was successfully removed. - Returns
0if the identified record does not exist. - Returns
-1if a failure occurred. The caller can use the Midgarderrnoanderrstrvalues to determine the cause of a failure.
Arguments:
type: record type (MidgardObjectsubclass)id: the local id of the record
Return value:
1if successful,0if record was not found,-1on failure
gint midgard_object_delete_matching(GType type, MidgardQueryBuilder *builder)
Removes records from the Midgard database. The removed records are selected by the given type and the query built by the given query builder.
Returns the number of removed records. Returns -1 if a
failure occurred. The caller can use the Midgard
errno and errstr values to determine
the cause of a failure.
Arguments:
type: record type (MidgardObjectsubclass)builder: query builder
Return value:
- number of removed records,
-1on failure
Parameters
TODO
Attachments
TODO
Metadata
TODO
Sitegroups
TODO
Localization
TODO
Access control
TODO
Data type inspection
MgdSchema uses the GObject API to provide a data inspection mechanism. This makes it possible to write general-purpose clients without hardcoding any information that is specific to a given data type. This feature is especially important to language bindings.
TODO
Clients can use the MidgardObject base class to find the available MgdSchema data types:
guint ntypes = 0;
GType *types = g_type_children(MIDGARD_TYPE_OBJECT, &ntypes);
The name of each data type:
GType type = ...;
const gchar *name = g_type_name(type);
The properties of a data type:
GType type = ...;
GObjectClass *klass = G_OBJECT_CLASS(g_type_class_ref(type));
guint nproperties = 0;
GParamSpec *properties = g_object_class_list_properties(klass, &nproperties);
g_type_class_unref(klass);
Link structure:
GType type = ...;
GParamSpec *property = ...;
if (property->flags & MIDGARD_PARAM_LINK) {
GType target = midgard_type_get_link_target(type, property->name);
}
Tree structure:
GType type = ...;
GParamSpec *parentfield = midgard_type_get_parent_field(type);
GParamSpec *namefield = midgard_type_get_name_field(type);
