Sqlite.jsm

This is an archived page. It's not actively maintained.

Le module de code JavaScript Sqlite.jsm offre une interface de stockage/SQLite. Sqlite.jsm fonctionne avec des interfaces XPCOM de stockage de bas niveau:

  • la gestion de la d√©claration est automatique. Sqlite.jsm va cr√©er, g√©rer et d√©truire les instances d'instructions pour vous. Vous ne devez pas vous soucier de la mise en cache des instances des √©tats cr√©√©s, les d√©truire lorsque vous avez termin√©, etc. Cela se traduit par moins de lignes de code pour communiquer avec SQLite.
  • Toutes les op√©rations sont asynchrones. Utilisation des API de stockage synchrones est d√©conseill√©e, car ils bloquent le thread principal. Toutes les fonctionnalit√©s de Sqlite.jsm sont asynchrone.
  • La gestion de la m√©moire est plus facile. Sqlite.jsm g√®re les d√©clarations pour vous, il peut effectuer des actions intelligentes comme purger toutes les d√©clarations mises en cache qui ne sont pas utilis√©s, ce qui lib√®re la m√©moire dans le processus. Il y a m√™me une API shrinkMemory qui permettra de minimiser automatiquement l'utilisation de la m√©moire de la connexion.
  • Des op√©rations sont simples. Sqlite.jsm utilise une API de transaction construit avec¬† task.jsm qui permet aux transactions d'√™tre √©crites en tant que fonctions de proc√©dure JavaScript (par opposition √† une s√©rie d'op√©rations motrices de rappel). Si la fonction est lanc√©e, la transaction est automatiquement annul√©e. Cela rend le code facile √† lire et √† √©crire.
  • Sqlite.jsm est un module JavaScript pur. Les complexit√©s de XPCOM sont la plupart du temps cach√©s. Les programmeurs JavaScript doivent se sentir √† l'aise en l'utilisant.

Note : Le module de code de Javascript Sqlite.jsm peut seulement être utilisé du chrome.

Avant de pouvoir utiliser ce module, vous devez l'importer dans votre champ d'application:

let { Cu } = require('chrome')
Cu.import("resource://gre/modules/Sqlite.jsm")

Obtention d'une connexion

Sqlite.jsm exporte le symbole Sqlite. Ce symbole est un objet avec une seule fonction: openConnection. Cette fonction prend un objet dictionnaire définissant les options de connexion:

path
(Obligatoire) Le fichier de base de données à ouvrir. Cela peut être un chemin absolu ou relatif. Si un chemin relatif est donné, il est interprété comme relatif au répertoire du profil actuel. Si le chemin n'existe pas, une nouvelle base de données SQLite sera créé. La nom se termine généralement par .sqlite.
sharedMemoryCache
(En option) booléenne indiquant si plusieurs connexions à la base de données partagent la même mémoire cache. Toutefois, le partage nécessite également des connexions pour obtenir un verrou, rendant éventuellement l'accès de base de données plus lente. Par défaut, true.
shrinkMemoryOnConnectionIdleMS
(En option) Si défini, le de connexion va tenter de minimiser son utilisation de la mémoire après un grand nombre millisecondes de connexion inactive. La connexion est inactive lorsque aucun états n'est exécuter. Noter que ceci n'est pas une minuterie qui pourrait se déclencher pendant que l'Application est active.

openConnection(options) retourne une promise d'une instance de connexion ouverte ou est rejetée si une erreur survient lors de l'ouverture de la base de données.

Voici un exemple:

let { Cu } = require('chrome')
Cu.import("resource://gre/modules/Sqlite.jsm");

Sqlite.openConnection({ path: "myDatabase.sqlite", sharedMemoryCache: false }).then(
  function onConnection(connection) {
    // connection is the opened SQLite connection (see below for API).
  },
  function onError(error) {
    // The connection could not be opened. error is an Error describing what went wrong.
  }
);

Utilisation des connexions ouvertes

Les connexions ouvertes sont ce que vous interfacer avec Sqlite.jsm. Les sections suivantes détaillent l'API d'une instance de connexion ouverte.

Gestion des connexions

Ces API sont utilisées pour gérer et vérifier l'état de la connexion.

close()

Ferme la connexion de base de données. Doit être appelé pour chaque connexion ouverte.

Cette fonction retourne une promise qui sera résolu lorsque la base de données sera fermée.

Si une transaction est en cours d'execution au moment o√Ļ cette fonction est appel√©e, la transaction sera annul√©e.

Si des d√©clarations sont en cours au moment o√Ļ cette fonction est appel√©e, elles seront annul√©es.

Les utilisateurs ne doivent pas tenter d'utiliser la connexion après avoir appelé cette méthode que la connexion sera inutilisable.

clone (readOnly)

Cette fonction retourne un clone de la connexion-promise actuelle.

Ces fonctions reçoivent l' argument:

readOnly
(En option) Si true le clone sera en lecture seule, false par défaut. Si la connexion d'origine est déjà en lecture seule, le clone le sera, indépendamment de cette option. Si la connexion d'origine utilise le cache partagé, ce paramètre sera ignoré et le clone sera aussi privilégié que la connexion d'origine.

transactionInProgress

Cette propriété booléenne indique si une opération est en cours. Cela est rarement nécessaire par les appelants externes.

shrinkMemory()

Cette fonction peut être appelée pour diminuer l'utilisation de la mémoire de la connexion. Ceci est un wrapper utilisé dans le PRAGMA shrink_memory, qui impose à SQLite la réduiction d'utilisation de la mémoire (par les caches de compensation, etc.).

Elle peut rendre votre base de données plus lent. Par conséquent, il faut être prudent avant d'appeler cette fonction.

Cela renvoie une promise qui est résolu lorsque l'opération est terminée.

discardCachedStatements()

Cette fonction est utilisée pour éliminer les instances d'instructions mises en cache, ce qui libère la mémoire dans le processus. Les déclarations de cache actifs ne seront pas effacées. Peut être appeler à tout moment.

Cela renvoie le nombre de déclarations mises en cache qui ont été rejetés.

Table et gestion du schéma

Ces API traitent de la gestion des tables et le schéma de base de données.

getSchemaVersion()

La version définie par l'utilisateur associé au schéma de la base de données actuelle. Retourne 0 si aucune version de schéma a été défini.

setSchemaVersion(value)

Definie la valeur value de la nouvelle version associée au schéma de la base de données actuelle. Ceci est un wrapper autour de PRAGMA user_version.

tableExists(name)

Cette fonction détermine si une table existe dans la base de données actuelle. Elle renvoie une promise qui est résolu avec une valeur booléenne indiquant si la table existe.

indexExists(name)

Cette fonction détermine si un index nommé existe dans la base de données actuelle. Elle renvoie une promesse qui est résolu avec une valeur booléenne indiquant si l'index existe.

Exemples

Déclaration d'exécution

Ces API facilitent l'exécution des instructions de connexion.

executeCached(sql, params, onRow)

execute(sql, params, onRow)

Ces fonctions similaires sont utilisés pour exécuter une instruction SQL unique sur la connexion. Comme vous l'avez deviné par le nom, il y a 2 options: mises en cache et non mis en cache. En dehors de cela, ils se comportent de manière identique.

Ces fonctions reçoivent les arguments suivants:

sql
(Obligatoire) cha√ģne SQL √† ex√©cuter. Le point-virgule final n'est pas n√©cessaire.
params
(En option) Paramètres liés à cette déclaration. Cela peut être un tableau ou un objet. Voir les notes ci-dessous.
onRow
(En option) Fonction qui est appelée lorsqu'une ligne a été reçue.

La valeur de retour est une promise qui est résolu lorsque l'instruction a terminé l'exécution.

Quand une instruction est exécutée via executeCached(), l'objet instruction préparée est mis en cache à l'intérieur de la connexion ouverte. La prochaine fois que cette même instruction SQL est exécutée (sql argument est identique à celui passé avant), l'ancien objet de la déclaration est réutilisée. Cela permet d'économiser du temps associé à l'analyse de l'instruction SQL et la création d'un nouvel objet de déclaration. Inconvénient: l'objet de la déclaration en cache persiste dans la connexion ouverte, en prenant de la mémoire.

Quand une instruction est exécutée via execute(), l'objet de la déclaration sous-jacente est jeté au terme de l'exécution.

executeCached() est recommandé pour les déclarations qui seront exécutées plusieurs fois. execute() est recommandé pour les déclarations qui seront exécutées rarement ou une fois.

Noter que les utilisateurs ne doivent pas préparer les états manuellement avant l'exécution. Il suffit d'appeler executeCached() et la déclaration sera préparée pour vous automatiquement.

Les paramètres peuvent être liés à la déclaration faite par la définition de l'argument params . Cet argument peut être un tableau de paramètres ordonnées ou un objet de type dicionnaire. Si la déclaration ne contient pas de paramètres liés, cet argument peut être omis ou spécifié comme nulle.

Note : Les utilisateurs sont fortement encouragés à utiliser des paramètres liés au lieu de créer dynamiquement des instructions SQL pour des raisons de sécurité.

Note¬†:¬†Les utilisateurs sont encourag√©s √† passer des objets type dictionnaire plut√īt que des tableaux pour les param√®tres li√©s car ils emp√™chent de s'emeler les pinceaux.
 
Lorsque onRow n'est pas d√©fini, les r√©sultats complets de l'op√©ration sont tamponn√©s avant que l'appelant soit inform√© de la d√©claration d'ach√®vement. Pour INSERT, UPDATE et DELETE, ce n'est pas pertinentes. Cependant, il peut y avoir des cons√©quences importante pour SELECT . Si votre d√©claration SELECT retourne beaucoup de donn√©es, cette mise en m√©moire tampon peut entra√ģner une utilisation excessive de la m√©moire. Par cons√©quent, il est recommand√© d'utiliser onRow avec SELECT.
 
Si StopIteration est emis lors de l'exécution d'un gestionnaire onRow, l'exécution de l'instruction est immédiatement annulée. Les lignes suivantes ne seront pas traitées. La promise est résolu immédiatement.
 
Si une exception StopIteration est levée par le gestionnaire onRow , l'exception est enregistré et le traitement des lignes suivantes se poursuit normalement. La promise est toujours résolue (pas rejetée).

La promise sera rejet√© avec une Error , si la d√©claration n'a pas termin√© l'ex√©cution compl√®te. L'Error peut avoir une propri√©t√© errors. Si elle est d√©finie, ce sera un tableau d'objets d√©crivant les erreurs. Chaque objet poss√®de les propri√©t√©s result et message. result est un code d'erreur num√©rique et message est une cha√ģne d√©crivant le probl√®me.

Si onRow est spécifié, la promise sera résolu avec un booléen indiquant si le gestionnaire onRow a été appelé. Sinon, la valeur réglée sera un tableau de mozIStorageRow .

executeTransaction(func, type)

Cette fonction est utilisée pour exécuter une transaction de base de données. Une transaction est une série de déclarations connexes traités comme une seule unité fonctionnelle. Si la transaction réussit, toutes les déclarations contenues dedans sont engagés comme une seule unité. Si la transaction échoue, la base de données revient à son état avant le début de la transaction.

Cette fonction reçoit les arguments suivants:

func
La fonction définissant le corps de la transaction.
type
Le type de transaction à effectuer. Ce doit être l'une des constantes de TRANSACTION_* sur l'instance de connexion ouverte. Les valeurs valides sont TRANSACTION_DEFERRED , TRANSACTION_IMMEDIATE , TRANSACTION_EXCLUSIVE . Consultez la documentation SQLite pour leur signification. La valeur par défaut est TRANSACTION_DEFERRED.

La fonction passée est une fonction de générateur compatible Task.jsm. Lorsqu'elle est appelée, la fonction reçoit comme argument l'instance de connexion actuelle. Cette fonction de générateur devrait produire des promises, probablement ceux qui sont renvoyés en appelant executeCached() et execute().

Si nous arrivons à la fin de la fonction de générateur sans erreur, la transaction est validée. Si une erreur se produit, la transaction est abandonnée.

La valeur retournée par cette fonction est une promise qui est résolu lorsque la transaction a été exécutée ou rejetée si la transaction a été annulée.

Open, Execute, Close

Dans cet exemple, nous ouvrons une connexion, exécutons une instruction simple, puis fermons la connexion.

Sqlite.openConnection({path: "MyDB.sqlite"}).then(
  function onOpen(conn) {
    conn.execute("SELECT 1").then(
      function onStatementComplete(result) {
        conn.close().then(
          function onClose() {
            alert("We are done!");
          }
        )
      }
    )
  }
)

Ce n'est pas un excellent exemple parce qu'il ne comprend pas la gestion des erreurs et est un peu difficile à lire.

Voici la même chose mais avec Task.jsm:

Task.spawn(function* demoDatabase() {
  let conn = yield Sqlite.openConnection({path: "MyDB.sqlite"});

  try {
    let result = yield conn.execute("SELECT 1");
  } finally {
    yield conn.close();
  }
});

Bound Parameters

Voici quelques exemples montrant des paramètres liés. Supposons que nous ouvrons une connexion avec la variable conn.

let dataToInsert = [
  ["foo", "bar"],
  ["biz", "baz"],
  ["yo", "ho"],
];

Task.spawn(function* doInsert() {
  for (let data of dataToInsert) {
    yield conn.executeCached("INSERT INTO myTable VALUES (?, ?)", data);
  }
});

Et la même chose avec des paramètres nommés.

let dataToInsert = [
  {paramA: "foo", paramB: "bar"},
  {paramA: "biz", paramB: "baz"},
  {paramA: "yo", paramB: "ho"},
];

Task.spawn(function* doInsert() {
  for (let data of dataToInsert) {
    yield conn.executeCached("INSERT INTO myTable VALUES (:paramA, :paramB)", data);
  }
});

Transactions

Ces exemples montrent comment fonctionnent les transactions.

conn.executeTransaction(function* simpleTransaction() {
  yield conn.execute("INSERT INTO myTable VALUES (?, ?)", ["foo", "bar"]);
  yield conn.execute("INSERT INTO myTable VALUES (?, ?)", ["biz", "baz"]);
});

L'exemple ci-dessus se traduira par 2 instructions INSERT dans une transaction diff√©r√©e (en supposant que les inserts proc√®dent sans erreur, bien s√Ľr).

Voici un exemple o√Ļ nous voulons forcer une annulation de la transaction.

conn.executeTransaction(function* complexTransaction() {
  yield conn.execute("INSERT INTO myTable VALUES (?, ?)", ["foo", "bar"]);
  let data = yield conn.execute("SELECT * FROM myTable");
  if (data.length < 5) {
    throw new Error("We don't have the expected 5 rows to perform the next operation!");
  }

  // ...
});

Sélection et retour des données

Ces exemples montrent comment accéder aux données qui sont retournées.

Cet exemple montre plusieurs lignes d'une table retournées en utilisant le paramètre onRow.

let accounts = [];
let accountId, userName;

let statement = "SELECT account_id, username FROM accounts ORDER BY username ASC";

conn.executeCached(statement, null, function(row) {
  accountId = row.getResultByName("account_id");
  userName = row.getResultByName("username");
  accounts.push({ accountId: accountId, userName: userName });
}).then(function onStatementComplete(result) {
  // All accounts returned successfully, so do something with them.
  console.log(result); // It worked!
  if (callback) {
    callback(null, accounts);
  }
},
function onError(err) {
  // An error occurred.
  console.log(err); // Error, Oh noes!
  if (callback) {
    callback(err);
  }
});

Remarque: les> paramètres then peuvent être des fonctions anonymes (i.e. function() ) , les seulements nomées sont onStatementComplete et onError pour la lisibilité.

Cet exemple démontre la récupération d'une ligne sans utiliser le paramètre onRow, en utilisant le résultat de conn.execute. Cet exemple montre également la récupération de la clé primaire de la dernière ligne insérée.

Task.spawn(function* () {
  try {
    conn = yield Sqlite.openConnection({ path: dbFile.path });

    let statement = "INSERT INTO accounts (username, details) VALUES (:username, :details)"
    let params = { username:"LordBusiness", details: "All I'm asking for is total perfection." };

    yield conn.execute(statement,params);

    // Get accountId of the INSERT.
    statement = "SELECT last_insert_rowid() AS lastInsertRowID";
    result = yield conn.execute(statement);

    // Only one row is returned.
    let row = result[0];
    let accountId = row.getResultByName("lastInsertRowID");

    if (callback) {
      callback(null, accountId);
    }
  } catch (err) {
    if (callback) {
      callback(err);
    }
  } finally {
    conn.close();
  }
});

Remarque: La valeur retourn√©e par last_insert_rowid() l'est par connexion, de sorte que vous devrez peut-√™tre ouvrir des connexions s√©par√©es lorsque vous faites plusieurs INSERT √† diff√©rents endroits, pour √™tre s√Ľr que l'identifiant de ligne qui est retourn√© corresponde.

Voir aussi