Documentation:Doc Outils PFCXX User

From Gameforge Official Website

Jump to: navigation, search
Persistence Framework for CXX (alias PFCXX)



Introduction

L'objectif de ce framework est d'avoir un moyen unique, simple et orienté object d'acceder à des données stocker en base. La base de données va être décris dans un fichier xml. A partir de ce fichier, un script (python) va générer les classes qui représenteront les tables et le lignes de la base.

Les grandes lignes

Objectif :

  • Utilisation orientée objets
  • pas de requête SQL à la main
  • différent backend (postegresql oracle, mysql...)
  • thread-safe

Limitation :

  • pas de support complet de orientée object (pas d'héritage...)
  • seul les relation de type foreing key sont supportée

Exemple de fichier xml

<?xml version="1.0"?>
<pfcxx>
  <object name="TotoTyty" table="TotoTable">
 
    <cxx>
      <namespace value="gt::hh::ppp"/>
      <folders sources="src1" hearders="include1"/>
    </cxx>
 
    <field name="id" column="ID" type="integer">
      <contraint name="pk" value="1" />
      <contraint name="nillable" value="0" />
      <contraint name="sequence" value="1" />
    </field>
 
    <field name="yuyu" column="Text" type="text">
      <contraint name="size" value="24" />
    </field>
 
    <field name="pouet" column="laspp" type="date">
    </field>
 
    <field name="fkid" column="fkC" type="integer">
      <fk object="hh::jj::kkkk::Tata" field="id" multi="false" handler="hhh" lazy="true" />
    </field>
 
  </object>
 
  <object name="Tata" table="TataTable">
 
    <cxx>
      <namespace value="hh::jj::kkkk" />
      <folders sources="src2" headers="include2"/>
    </cxx>
 
    <field name="id" column="ID" type="integer">
      <contraint name="pk" value="1" />
      <contraint name="nillable" value="0" />
      <contraint name="sequence" value="1" />
    </field>
 
    <field name="yuyu" column="Text" type="text">
      <contraint name="size" value="24" />
    </field>
  </object>
</pfcxx>

Explication :

<object name="TotoTyty" table="TotoTable">

Déclare que la table TotoTable sera décrite par l'object TotoTyty.

<cxx>
  <namespace value="gt::hh::ppp"/>
  <folders sources="src1" headers="include1"/>
</cxx>

Déclare que :

  • La classe TotoTyty sera dans le namespace gt::hh::ppp
  • L'header sera dans le repertoire include1
  • Le source sera dans le repertoire src1
<field name="id" column="ID" type="integer">
  <contraint name="pk" value="1" />
  <contraint name="nillable" value="0" />
  <contraint name="sequence" value="1" />
</field>

Déclare que le parametre id représente la colonne ID et sera de type integer. De plus, il aura un certain nombres de contraintes :

  • c'est un clé primaire,
  • qui ne peut pas être null,
  • qui est auto incrementé.

Une colonne a obligatoirement un type parmis :

  • integer (-2147483648 à +2147483647)
  • string
  • date

Et un ensemble de contraintes :

  • pk dit si c'est (value == 1) ou ce n'ai pas une clé primaire. Par défault cela vaut 0.
  • nillable dit si le champ peut etre nul. Par default cela vaut 0.
  • sequence dit s'il faut rajouter un index (cela accelaire les requete mais occupe plus d'espace). Par default cela vaut 0.
  • size definit la taille maximun. Par default cela vaut 24.

Remarque :

  • size n'est valable que pour les colonne de type string.
  • sequence n'est valable que pour les colonne de type integer.
<field name="fkid" column="fkC" type="integer">
  <fk object="hh::jj::kkkk::Tata" field="id" multi="false" handler="hhh" lazy="true" />
</field>

Déclare :

  • une foreing key dont le nom sera fkid de la colonne "fkC de type integer,
  • cette colonne sera reliée à la colonne id' de la l'objet hh::jj::kkkk::Tata.
  • cette relation est de type one-one ou multi-one (multi="false")
  • le chargement se fera sur demande (lazy="true") et l'objet Tata aura un parametre hhh qui lui permetra de retouver le ou les TotoTyty relié a lui-même.

Génération du code source

La génération se fait au moyen du script python pfcxx-gen.py

$ ./pfcxx-gen.py
No input file !
bin/pfcxx-gen.py [OPTIONS] xml-file

Options :
      --prefix folder   --> publication folder
      --log logFile     --> enable log and set output log file
      --help            --> print usage
      --list-files      --> list will be generated files

Pour savoir quels fichiers qui seront générés avec l'exemple précédent :

$ ./pfcxx-gen.py --prefix /tmp --list-files pf-sample1.xml
/tmp/include1/TotoTytyInfo.hh
/tmp/include1/TotoTyty.hh
/tmp/src1/TotoTytyInfo.cc
/tmp/src1/TotoTyty.cc
/tmp/include2/TataInfo.hh
/tmp/include2/Tata.hh
/tmp/src2/TataInfo.cc
/tmp/src2/Tata.cc

Pour générer les fichiers :

$ ./pfcxx-gen.py --prefix /tmp pf-sample1.xml

Pour générer les fichiers avec des log :

$ ./pfcxx-gen.py --prefix /tmp --log /tmp/s.log pf-sample1.xml

Pour voir les fichiers générés :

Configuration de la connection

Exemple de configuration du pool de connection :

#include "gameforge/server/pfcxx/tools/DbConnectorPool.hh"
#include "gameforge/server/pfcxx/tools/DefaultLoggerHandler.hh"
 
using namespace gameforge::server::pfcxx::drivers;
using namespace gameforge::server::pfcxx::tools;
using namespace gameforge::server::pfcxx;
 
int main(void)
{
  DbConnectorPool::Config config;
 
  config.driver = Postgresql;
 
  config.userDb = "user";
  config.pwdDb = "secret";
  config.db = "gameforgedb";
  config.cacheType = DbConnectorPool::Config::OnePerConnection;
  config.nbConnectionPool = 10;
  config.nbConnectionPoolMax = 50;
  config.nbConnectionPoolInit = 8;
 
  config.nbReconnect = 5;
  config.logger.reset(new DefaultLoggerHandler);
 
  DbConnectorPool::getInstance().setConfig(config);
 
  return 0;
}

Avec :

  config.driver = Postgresql;

Définit du drivers de de base données qui va être utilisés.

Valeur par défaut : Postgresql.

Liste des valeurs possible :

  • Postgresql
  config.userDb = "user";
  config.pwdDb = "secret";
  config.db = "gameforgedb";

Définit l'utilisateur, le password et la base de donnée qui va être utilisés.

  config.cacheType = DbConnectorPool::Config::OnePerConnection;

Définit le type de cache. Dans ce cas, il y a un cache par connection.

Valeur par defaut : OnePerConnection.

Liste des valeurs possible :

  • OnePerConnection
  • None
  config.nbConnectionPool     = 10;
  config.nbConnectionPoolMax  = 50;
  config.nbConnectionPoolInit = 8;

Définit les caractéristique du pool de connection :

  • nbConnectionPoolInit est le nombre de connection qui est créé à l'initialisation.
  • nbConnectionPoolMax est le nombre maximum de connection qui pourront être créées par le pool.
  • nbConnectionPool est le nombre qui a partir duquelle toute nouvelle connection, non utlisé, ne sera pas remis dans le pool mais détruit.

Valeurs par défaut :

  • nbConnectionPoolInit est 10
  • nbConnectionPoolMax est 100
  • nbConnectionPool est 0
  config.nbReconnect = 5;

Définit le nombre de tentative de connection ou reconnection avant la lever d'une exception.

Valeur par défaut : 5.

  config.logger.reset(new DefaultLoggerHandler);

Definit le handler de log. Cette handler à une méthode par niveau du log (debug, info, warn, error, fatal) qui est appellé pour l'inpression de ce message.

Par défault, la classe utilisé est DefaultLoggerHandler qui ne fait rien. La création d'une classe custom consiste à implémenter LoggerHandler.

  DbConnectorPool::getInstance().setConfig(config);

Set la configuration du pool.

Il est très fortement conseillé de setter la config du pool qu'une fois et au démarrage, avant son utilisation !!

Requète

Tester l'existence d'une table :

#include "include2/Tata.hh"
#include "gameforge/tools/pfcxx/query/Exist.hh"
...
Exist<Tata> exist1;
if(! exist1.execute())
{
  // Table TataTable n'existe pas !!
}

Créer une table :

#include "include2/Tata.hh"
#include "gameforge/tools/pfcxx/query/Exist.hh"
...
Exist<Tata> exist1;
if(! exist1.execute())
{
  Create<Tata> create;  // Création de la table TataTable
  create.execute();
}

Créer et inserer une instance en base :

Tata::ptr tata = Tata::newInstance();   // Création d'une instance
tata -> update(); // Insération en base 

Mise à jour de la base :

Tata::ptr tata = Tata::newInstance();
tata -> update(); // Insération en base
 
tata -> yuyu = "ddd pouet";  // Modification de la colonne Text
tata -> update(); // Mise à jour de la base 

Lier deux instance par une foreign key :

/**
 * Création d'une instance de Tata
 */
Tata::ptr tata = Tata::newInstance();
...
..
.
 
/**
 * Création d'une instance de TotoTyty
 */
TotoTyty::ptr toto = TotoTyty::newInstance();
...
..
.
 
/**
 * Lier les deux instances
 */
toto -> fkid.link(tata);
 
/**
 * Sauvegarde (attention a l'odre !!)
 */
tata -> update();
toto -> update();

Selectionner un ensemble de ligne :

Select<TotoTyty> select;
select.where<TotoTyty::eId>(LessThan, 7);
 
vector<TotoTyty::ptr> r = select.all();
 
for(unsigned int i = 0 ; i < r.size() ; ++i)
{
  cout << r[i] -> id.value() << " ";
  cout << r[i] -> yuyu.value() << " ";
  cout << r[i] -> pouet.value() << " ";
  cout << r[i] -> fkid.value() << " " << endl;
}

Sélectionner un ensemble de ligne avec un cursor :

Select<TotoTyty> select;
select.where<TotoTyty::eId>(LessThan, 7);
 
Cursor<TotoTyty> cursor = select.cursor();
TotoTyty::ptr t;
 
while(cursor.hasNext())
{
  t = cursor.next();
 
  cout << r[i] -> id.value() << " ";
  cout << r[i] -> yuyu.value() << " ";
  cout << r[i] -> pouet.value() << " ";
  cout << r[i] -> fkid.value() << " " << endl;
}

Selectionner qu'une ligne :

Select<TotoTyty> select;
select.where<TotoTyty::eId>(Equals, 10);
 
TotoTyty::ptr toto = select.one();

Pour des exemples complet:

Personal tools