Coat::Persistent Votre base de données  à portées d'objets FPW 2009 – 13 Juin 2009 Alexis Sukrieh http://www.sukria.net
Plan <ul><li>Le concept ORM
Origines de Coat::Persistent
Mise en place de Coat::Persistent
Accèder aux données (lecture/écriture)
Relations entre tables / modèles
Fonctionnement du cache </li></ul>
Le concept ORM Une méthode moderne et  efficace pour manipuler les données
Le principe ORM <ul><li>Un framework Objet
Une table devient une classe
Une ligne devient une instance
Une colonne devient un attribut
Le SQL est désormais une couche de bas niveau </li></ul>
Avantages <ul><li>Moins de code pour manipuler les données
Plus de code pour écrire l'application
Factorisation du problème d'accès aux données
Facilités et puissance de l'approche Objet
Simplicité d'utilisation </li></ul>
Avantages <ul><li>Moins de code pour manipuler les données
Plus de code pour écrire l'application
Factorisation du problème d'accès aux données
Facilités et puissance de l'approche Objet
Simplicité d'utilisation
Moins de SQL </li></ul>
Avantages <ul><li>Moins de code pour manipuler les données
Plus de code pour écrire l'application
Factorisation du problème d'accès aux données
Facilités et puissance de l'approche Objet
Simplicité d'utilisation
Moins de SQL
Moins de SQL </li></ul>
Avantages Moins de SQL ??!
Avec du SQL ... my   $sql  =  'select * from table' ; my   $sth  =  $dbh ->prepare( $sql ); $sth ->execute or  die   $! ; ...
CATS DON'T LIKE SQL
Avec Coat::Persistent foreach   my   $obj  (Table->find())  { # ici on joue avec $obj ... } Je crois que le chat s'est cal...
Pourquoi vouloir moins de SQL ? <ul><li>Pour les tâches répétitives, SQL est lourd
Chaque fois qu'une requête SQL apparaît dans du code, un risque d'injection est présent
La validation des valeurs soumises en SQL est lourde
La préparation des valeurs l'est aussi (escaping, conversion de format)
Le temps passé à manipuler SQL n'est pas consacré au code métier </li></ul>
Mais le SQL est possible <ul><li>On ne ferme pas pour autant la porte au SQL
Pour les requêtes complexes, SQL reste un bon choix
Pour les requêtes simples et courantes, il faut l'éviter </li></ul>
Les ORM en Perl <ul><li>Class::DBI </li></ul>
Les ORM en Perl <ul><li>Class::DBI
DBIx::Class </li></ul>
Les ORM en Perl <ul><li>Class::DBI
DBIx::Class
Rose::DB::Object </li></ul>
Les ORM en Perl <ul><li>Class::DBI
DBIx::Class
Rose::DB::Object
...
Pourquoi un nouvel ORM ? </li></ul>
Les origines de Coat::Persistent <ul><li>ActiveRecord : l'ORM de Ruby on Rails
Coat : le mini Moose sans dépendances
Deux bonnes idées qui méritaient d'être réunies </li></ul>
Objectifs pour Coat::Persistent <ul><li>Simple d'utilisation </li></ul>
Objectifs pour Coat::Persistent <ul><li>Simple d'utilisation
Léger  </li></ul>
Objectifs pour Coat::Persistent <ul><li>Simple d'utilisation
Léger
Rapide </li></ul>
Objectifs pour Coat::Persistent <ul><li>Simple d'utilisation
Léger
Rapide
Aussi près que possible de l'API ActiveRecord </li></ul>
Upcoming SlideShare
Loading in...5
×

Coat::Persistent at FPW2009

1,499

Published on

Coat::Persistent est un ORM écrit pour Perl en s'inspirant de l'API d'ActiveRecord de Rails. Cette présentation a été tenue aux journées Perl 2009

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,499
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Coat::Persistent at FPW2009

  1. 1. Coat::Persistent Votre base de données à portées d'objets FPW 2009 – 13 Juin 2009 Alexis Sukrieh http://www.sukria.net
  2. 2. Plan <ul><li>Le concept ORM
  3. 3. Origines de Coat::Persistent
  4. 4. Mise en place de Coat::Persistent
  5. 5. Accèder aux données (lecture/écriture)
  6. 6. Relations entre tables / modèles
  7. 7. Fonctionnement du cache </li></ul>
  8. 8. Le concept ORM Une méthode moderne et efficace pour manipuler les données
  9. 9. Le principe ORM <ul><li>Un framework Objet
  10. 10. Une table devient une classe
  11. 11. Une ligne devient une instance
  12. 12. Une colonne devient un attribut
  13. 13. Le SQL est désormais une couche de bas niveau </li></ul>
  14. 14. Avantages <ul><li>Moins de code pour manipuler les données
  15. 15. Plus de code pour écrire l'application
  16. 16. Factorisation du problème d'accès aux données
  17. 17. Facilités et puissance de l'approche Objet
  18. 18. Simplicité d'utilisation </li></ul>
  19. 19. Avantages <ul><li>Moins de code pour manipuler les données
  20. 20. Plus de code pour écrire l'application
  21. 21. Factorisation du problème d'accès aux données
  22. 22. Facilités et puissance de l'approche Objet
  23. 23. Simplicité d'utilisation
  24. 24. Moins de SQL </li></ul>
  25. 25. Avantages <ul><li>Moins de code pour manipuler les données
  26. 26. Plus de code pour écrire l'application
  27. 27. Factorisation du problème d'accès aux données
  28. 28. Facilités et puissance de l'approche Objet
  29. 29. Simplicité d'utilisation
  30. 30. Moins de SQL
  31. 31. Moins de SQL </li></ul>
  32. 32. Avantages Moins de SQL ??!
  33. 33. Avec du SQL ... my $sql = 'select * from table' ; my $sth = $dbh ->prepare( $sql ); $sth ->execute or die $! ; while ( my $row = $sth ->fetchrow_hashref()) { # ici on joue avec $row ... } On a donc 4 lignes pour pouvoir itérer sur des enregistrements...
  34. 34. CATS DON'T LIKE SQL
  35. 35. Avec Coat::Persistent foreach my $obj (Table->find()) { # ici on joue avec $obj ... } Je crois que le chat s'est calmé...
  36. 36. Pourquoi vouloir moins de SQL ? <ul><li>Pour les tâches répétitives, SQL est lourd
  37. 37. Chaque fois qu'une requête SQL apparaît dans du code, un risque d'injection est présent
  38. 38. La validation des valeurs soumises en SQL est lourde
  39. 39. La préparation des valeurs l'est aussi (escaping, conversion de format)
  40. 40. Le temps passé à manipuler SQL n'est pas consacré au code métier </li></ul>
  41. 41. Mais le SQL est possible <ul><li>On ne ferme pas pour autant la porte au SQL
  42. 42. Pour les requêtes complexes, SQL reste un bon choix
  43. 43. Pour les requêtes simples et courantes, il faut l'éviter </li></ul>
  44. 44. Les ORM en Perl <ul><li>Class::DBI </li></ul>
  45. 45. Les ORM en Perl <ul><li>Class::DBI
  46. 46. DBIx::Class </li></ul>
  47. 47. Les ORM en Perl <ul><li>Class::DBI
  48. 48. DBIx::Class
  49. 49. Rose::DB::Object </li></ul>
  50. 50. Les ORM en Perl <ul><li>Class::DBI
  51. 51. DBIx::Class
  52. 52. Rose::DB::Object
  53. 53. ...
  54. 54. Pourquoi un nouvel ORM ? </li></ul>
  55. 55. Les origines de Coat::Persistent <ul><li>ActiveRecord : l'ORM de Ruby on Rails
  56. 56. Coat : le mini Moose sans dépendances
  57. 57. Deux bonnes idées qui méritaient d'être réunies </li></ul>
  58. 58. Objectifs pour Coat::Persistent <ul><li>Simple d'utilisation </li></ul>
  59. 59. Objectifs pour Coat::Persistent <ul><li>Simple d'utilisation
  60. 60. Léger </li></ul>
  61. 61. Objectifs pour Coat::Persistent <ul><li>Simple d'utilisation
  62. 62. Léger
  63. 63. Rapide </li></ul>
  64. 64. Objectifs pour Coat::Persistent <ul><li>Simple d'utilisation
  65. 65. Léger
  66. 66. Rapide
  67. 67. Aussi près que possible de l'API ActiveRecord </li></ul>
  68. 68. Objectifs pour Coat::Persistent <ul><li>Simple d'utilisation
  69. 69. Léger
  70. 70. Rapide
  71. 71. Aussi près que possible de l'API ActiveRecord
  72. 72. Interopérable (MySQL, SQLite, CSV, ...) </li></ul>
  73. 73. Mise en place Comment utiliser Coat::Persistent dans votre projet
  74. 74. Installation <ul><li>cpan install Coat
  75. 75. cpan install Coat::Persistent
  76. 76. Le driver DBI pour votre SGBD </li></ul>
  77. 77. Une premier modèle C::P package Camel ; use Coat; use Coat::Persistent;
  78. 78. Une premier modèle C::P avec MySQL package Camel ; use Coat; use Coat::Persistent; Coat::Persistent->map_to_dbi( mysql => ' dbname ',' dbuser ',' dbpass ');
  79. 79. Une premier modèle C::P avec SQLite package Camel ; use Coat; use Coat::Persistent; Coat::Persistent->map_to_dbi( sqlite => ' dbname=dbfile ');
  80. 80. Une premier modèle C::P avec CSV package Camel ; use Coat; use Coat::Persistent; Coat::Persistent->map_to_dbi( csv => ' f_dir=dbfile ');
  81. 81. Conventions <ul><li>La mapping est possible par défaut ou par classe
  82. 82. Le nom de la classe implique un nom de table
  83. 83. La clef primaire se nomme « id »
  84. 84. Une clef étrangère se nomme table_id
  85. 85. On peut surcharger chacune de ces conventions </li></ul>
  86. 86. Surcharger les conventions package Camel ; use Coat; use Coat::Persistent table_name => ' camels ', primary_key => ' cid '; Coat::Persistent->map_to_dbi( csv => ' f_dir=dbfile ');
  87. 87. Terminer le mapping package Camel ; use Coat; use Coat::Persistent; has_p name => (isa => 'Str'); has_p age => (isa => 'Int'); sqlite> create table camel (id int, name varchar(25), age int);
  88. 88. Maintenant il est possible : <ul><li>Remonter des objets à partir de la base
  89. 89. Créer de nouvelles entrées
  90. 90. Modifier des entrées existantes
  91. 91. Accèder au handle de la base de données
  92. 92. Obtenir des objets à partir de requetes SQL complexes </li></ul>
  93. 93. Coat::Persistent est en place !
  94. 94. Un modèle Coat::Persistent <ul><li>C'est une classe qui hérite de Coat::Object
  95. 95. C'est une classe qui hérite de Coat::Persistent
  96. 96. À ce titre, elle bénéficie de : </li><ul><li>Méthodes statiques qui s'appliquent à une table
  97. 97. Méthodes d'instances qui s'appliquent à une ligne </li></ul><li>Pour chaque attribut déclaré, des accesseurs et une série de méthodes sont automatiquement définies : </li></ul>
  98. 98. Attribut et méthodes La déclaration de l'attribut « foo » implique : <ul><ul><li>$obj->foo()
  99. 99. Class->find_by_foo()
  100. 100. Class->find_or_create_by_foo()
  101. 101. Class->find_or_initialize_by_foo() </li></ul></ul>
  102. 102. Création de données <ul><li>Un nouvel objet Coat::Persistent n'est pas sauvé en base tant que save() n'est pas appelé
  103. 103. La méthode create() permet de faire un new() et un save()
  104. 104. Des méthodes permettent de faire des créations d'objet avec ou sans sauvegarde selon l'existence d'un enregistrement particulier </li></ul>
  105. 105. Création de données <ul><li>Class->new() : crée une instance en mémoire
  106. 106. $obj->save() : sauve l'instance dans la base de donnée
  107. 107. Class->create() : crée et sauve l'instance
  108. 108. Class->find_or_create_by_ATTR(val) : find_by_ATTR(val) ou create(ATTR => val)
  109. 109. Class->find_or_initialize_by_ATTR(val) : find_by_ATTR(val) ou new(ATTR => val) </li></ul>
  110. 110. Exemple de création Perl> my $joe = Camel->new(name =>'joe',age => 7); $Camel1 = Camel=HASH(0x8dcf7a0); Perl> $joe->save 1 sqlite> select * from camel where id = 1; 1|joe|7
  111. 111. Exemple de création (plus court) Perl> my $joe = Camel->create(name =>'night',age => 4); $Camel1 = Camel=HASH(0x8dcf7a0); sqlite> select * from camel where id = 1; 1|joe|7 2|night|4
  112. 112. Lecture <ul><li>Pour lire les données existantes, on utilise un finder
  113. 113. Le contexte d'appel est important (on remonte N entrées avec un contexte de liste et uniquement la première en contexte scalaire)
  114. 114. Les finders peuvent se décliner
  115. 115. find, find_by_attribut, find(id), find('condition') ... </li></ul>
  116. 116. find en contexte de liste Perl> my @camels = Camel->find(); $ARRAY1 = [ Camel=HASH(0x9cfc568), Camel=HASH(0x9cfc718), Camel=HASH(0x9cfc7c8) ];
  117. 117. find avec un id Perl> my $camel = Camel->find(1); $Camel1 = Camel=HASH(0x9cfc568)
  118. 118. find avec plusieurs id Perl> my @camels = Camel->find(1,2); $ARRAY1 = [ Camel=HASH(0x9ba0648), Camel=HASH(0x9cfc818) ];
  119. 119. find avec un attribut Perl> my $joe = Camel->find_by_name('joe'); $Camel1 = Camel=HASH(0x9cfc568) Perl> $joe->name; 'joe'
  120. 120. find avec une condition Perl> @camels = Camel->find('age > 10'); $Camel1 = Camel=HASH(0x9d0af78); Perl> $camels[0]->age 12
  121. 121. find avec des options Perl> my @camels = Camel->find('age > 3', { order => 'name', limit => '5', });
  122. 122. find avec … du SQL Perl> @camels = Camel->find_by_sql('select * from camel where age is not null'); $ARRAY1 = [ Camel=HASH(0x9cfc528), Camel=HASH(0x9cfca78), Camel=HASH(0x94c3380) ];
  123. 123. Modifier Perl> $camel = Camel->find(1); $Camel1 = Camel=HASH(0x9cfc528) Perl> $camel->age(3); 3 Perl> $camel->save; 1
  124. 124. Supprimer Perl> $camel = Camel->find(1); $Camel1 = Camel=HASH(0x9cfc528) Perl> $camel->delete; 1 Perl> $camel = Camel->find(1); undef
  125. 125. N'oublions pas Coat <ul><li>Le hooks de Coat (Moose) s'appliquent très bien ici
  126. 126. Chaque méthode proposée par C::P est interceptable via les hooks Coat before, after et around
  127. 127. Les méthodes BUILD et DEMOLISH sont implémentables par les objets C::P
  128. 128. Types utilisateur et coercition </li></ul>
  129. 129. Les hooks <ul><li>before save => sub { ... }
  130. 130. after save => sub { }
  131. 131. sub BUILD { ... }
  132. 132. sub DEMOLISH { ... }
  133. 133. ... </li></ul>
  134. 134. Types et Coercition subtype 'DateTime' => as 'Str' => where { /d{4}-dd-dd dd:dd:dd/ }; coerce 'DateTime' => from 'Int' => via { convert_time_to_datetime_str($_) };
  135. 135. Types et Coercition has_p 'created_at' => ( is => 'rw', isa => 'DateTime', coerce => 1, ); before 'save' => sub { my ($self) = @_; $self->created_at(time()); };
  136. 136. Les relations entre tables
  137. 137. Relations côté SQL ... sqlite> create table master (id int, name varchar(25)); sqlite> alter table camel add column master_id int;
  138. 138. … et côté Perl package Camel ; use Coat; use Coat::Persistent; has_p name => (isa => 'Str' ); has_p age => (isa => 'Int' ); has_one 'master'; ;
  139. 139. … et côté Perl package Master ; use Coat; use Coat::Persistent; has_p name => (isa => 'Str' ); has_many 'camels', class_name => 'Camel'; ;
  140. 140. Le maître des chameaux Perl> my $m = Master->create(name => 'Al Kabir') $Master1 = Master=HASH(0x913c168); Perl> my @camels => Camel->find(); $ARRAY1 = [ Camel=HASH(0x913c5e8), Camel=HASH(0x913c588) ]; Perl> map { $_->master($m); $_->save; } @camels;
  141. 141. Trouver le maître Perl> my $camel = Camel->find(1); $Camel1 = Camel=HASH(0xa07cd60); Perl> $camel->master $Master1 = Master=HASH(0xa07d050); Perl> $camel->master->name Al Kabir
  142. 142. Trouver les chameaux Perl> my $master = Master->find(1); $Master1 = Master=HASH(0xa07d050); Perl> my @camels = $master->camels; $ARRAY1 = [ Camel=HASH(0xa07ce00), Camel=HASH(0xa07d080) ];
  143. 143. Accéler les choses <ul><li>Pour améliorer les performances, on peut cacher les résultats des requêtes SQL
  144. 144. Le cache est activable à la demande, par Classe ou pour l'ensemble du processus
  145. 145. Pour chaque requête SQL générée (pour un set de valeurs données) C::P maintient une entrée en cache avec le résultat
  146. 146. Ce résultat en cache est retourné s'il existe </li></ul>
  147. 147. Accéler les choses <ul><li>L'expiration des données est gérée en interne par Cache::FastMmap
  148. 148. On peut activer/désactiver le cache à la volée </li></ul>
  149. 149. Exemple de Cache Pour l'ensemble du processus (toutes les classes C::P sont affectées) Coat::Persistent ->enable_cache( expire_time => '1h' , cache_size => '50m' , share_file => '/var/cache/myapp.cache' , );
  150. 150. Exemple de Cache Uniquement pour la classe utilisée Camel ->enable_cache( expire_time => '1h' , cache_size => '50m' , share_file => '/var/cache/myapp.cache' , );
  151. 151. Pour la suite ... <ul><li>Gestion de l'option join dans les finder
  152. 152. Migrations (classe Coat::Persistent::Migration)
  153. 153. Valider de nouveaux drivers DBI
  154. 154. Méthodes manquantes de ActiveRecord
  155. 155. Optimisations (occupation mémoire, requêtes générées) </li></ul>
  156. 156. Pour Contribuer <ul><li>Les patchs sont toujours bienvenus
  157. 157. svn co svn://svn.sukria.net:2015/Coat-Persistent
  158. 158. Bugs : http://rt.cpan.org
  159. 159. Pour me contacter : sukria@sukria.net </li></ul>
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×