Le Vide Tête

Tout ce qu'est trop long pour tenir dans un tweet

Swift côté serveur – Partie 3: Gestion du format Date avec Vapor et PostgreSQL

Dans cette 3ème partie, je vais expliquer comment gérer le type Date. Cela fonctionne avec PostgreSQL, devrait fonctionner à peu près pareil avec MariaDB/MySQL, mais je n’ai pas réussi le faire fonctionner avec MongoDB (voir la conclusion finale pour une possible piste).

Si tu as raté les épisodes précédents:
Dans la 1ère Partie j’ai détaillé l’installation de Swift, Vapor and PostgreSQL.
Dans la 2ème Partie j’ai créé une application basique à l’aide de Vapor qui enregistre un objet dans la base PostgreSQL et le récupère ou récupère tous les objets. L’objet utilisait que des types basiques Int et String (Double aussi est supporté par Vapor).

Remarque: Vapor 2.0 (et Fluent 2.0 – le framework qui gére les bases de données utilisé par Vapor) sont actuellement en version alpha. Les versions finales devrait proposer le support du type Date. En attendant, voici mon workaround.


A ce moment le modèle User.swift ressemble à:

On change la fonction prepare pour créer la colonne lastconnection de type Timestamp au lieu de Varchar .

Comme Timestamp (ou DateTime pour MariaDB/MySQL) n’est pas un type pris en chage par le framework on doit utiliser le type custom et préciser le type spécifique du champ de la base à utiliser.

Ensuite changeons le type en Date de l’élément lastconnection du modèle User :

et corrigeons le init:

Maintenant la partie délicate, corriger les fonctions: init(node…) et makeNode.
Le type Node ne sait pas gèrer les dates, donc le workaround afin de garder la colonne de la base de donnée de type Date/Timestamp est de la transformer de String en Date quand elle est lue de la base de donnée et de Date en String quand on écrit dans la base de données. Cela fonctionne parce que PostgreSQL et MariaDB/MySQL retournent les colonnes de type Timesamp (pour Postgres, DateTime pour MariaDB) comme chaîne de caractère.

Donc écrivons les fonctions de transfomation de Date en String et de String en Date.

On peut aussi étendre la classe Date avec ces fonctions au lieu d’un modèle en particulier si on veut partager ces fonctions entre plusieurs modèles. Dans cet exemple il y qu’un seul modèle donc j’ai préféré les mettre dans celui-ci.

Maintenant utilisons-les:

Puis corrigeons main.swift en modifiant les routes:
users:

  • createusers:

Rebuildons le projet:

Et avant d’exécuter, comme on a changé le schéma de la base de données, on fait en revert pour supprimer les tables créées précédemment.
Pour cela on execute dans un terminal:

et on répond y quand demandé.

Si on regarde le base Postgres on devrait plus voir les tables fluent et users.

Maintenant on est prêt pour lancer l’application:

Si on regarde la base de donnés on devrait avoir la table Users qui ressemble à:

Et si l’on va dans un navigateur à l’URL: http://localhost:8080/createusers
et ensuite on regarde en base de données on devrait voir les utilisateurs créés:

Et on devrait avoir la même chose, mais sous forme de JSON si on navigue vers: http://localhost:8080/allusers

De même tout fonctionne aussi, si l’on teste la création d’un client à l’aide d’un client REST et on fait un POST sur l’url: http://localhost:8080/user

Donc pour finir voici la version finale de main.swift avec un peu de ménage:

Et User.swift:


Et voilà, tout consiste à transformer les Date en String dans un sens et de String en Date dans l’autre. Attention au format de la date retournée par la base de donnée (MySQL par ex ne renvoie pas les millisecondes).

J’ai mis pas mal de temps à trouver cette solution. Surtout que j’ai commencé en utilisant MongoDB comme base de donnée et cette astuce ne marche pas (je pense qu’on peut arriver à peu près au même résultat avec MongoDB en utilisant le type Timestamp dans la base au lieu de Date et transformer depuis Int en Date lors de la lecture depuis la base et de Date en Int lors de l’écriture, mais personnellement je ne voulais pas changer le type de la colonne car cette collection était utilisée par ailleurs). J’ai trouvé plein de tutoriaux sur Vapor (un grand merci à Ray Wenderlich qui avec ses screencasts m’a initié à Swift côté server avec Vapor) mais aucun utilisait le type Date.

Si d’autres personnes galèrent avec ça, j’espère que ces articles les aiderons.