> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt # Stockage Google Cloud Spanner L'implémentation du stockage Google Cloud Spanner fournit à Mastra un backend de stockage à forte capacité, évolutif horizontalement et fortement cohérent. Elle cible le dialecte GoogleSQL de Cloud Spanner. ## Installation **npm**: ```bash npm install @mastra/spanner@latest ``` **pnpm**: ```bash pnpm add @mastra/spanner@latest ``` **Yarn**: ```bash yarn add @mastra/spanner@latest ``` **Bun**: ```bash bun add @mastra/spanner@latest ``` ## Utilisation ```typescript import { SpannerStore } from '@mastra/spanner' const storage = new SpannerStore({ id: 'spanner-storage', projectId: process.env.SPANNER_PROJECT_ID!, instanceId: process.env.SPANNER_INSTANCE_ID!, databaseId: process.env.SPANNER_DATABASE_ID!, }) ``` L'instance et la base de données doivent déjà exister. L'adaptateur crée les tables requises lors de la première utilisation ; les identifiants fournis au client Spanner doivent donc autoriser les modifications du schéma (vous pouvez aussi exécuter `storage.init()` une fois pendant une étape de déploiement avec des identifiants disposant de privilèges élevés). ## Paramètres **id** (`string`): Identifiant unique de cette instance de stockage. **projectId** (`string`): ID du projet Google Cloud. Requis sauf si database est fourni. **instanceId** (`string`): ID de l’instance Cloud Spanner. Requis sauf si database est fourni. **databaseId** (`string`): ID de la base de données Cloud Spanner. Requis sauf si database est fourni. **database** (`@google-cloud/spanner Database`): Handle Spanner Database préconfiguré. Utilisez-le lorsque vous gérez le client Spanner ailleurs (par exemple, pour partager des options d’authentification ou de connexion entre plusieurs services). **spannerOptions** (`object`): Options transmises au constructeur du client @google-cloud/spanner. Utilisez-les pour définir les identifiants, des points de terminaison personnalisés ou l’émulateur local. **disableInit** (`boolean`): Lorsque cette valeur est true, ignore la création automatique des tables lors de la première utilisation. Vous devez appeler explicitement storage.init() pendant une étape de déploiement distincte. (Default: `false`) **skipDefaultIndexes** (`boolean`): Lorsque cette valeur est true, ignore la création des index par défaut pendant l’initialisation. (Default: `false`) **indexes** (`CreateIndexOptions[]`): Index secondaires personnalisés à créer. Chaque index doit indiquer la table à laquelle il appartient. Les index sont acheminés vers le domaine approprié selon le nom de la table. **initMode** (`'sync' | 'validate'`): Contrôle le comportement d’initialisation du schéma. 'sync' crée les tables, colonnes et index manquants pendant init() (comportement historique). 'validate' n’émet aucune instruction DDL et vérifie à la place que toutes les tables, colonnes et tous les index par défaut ou personnalisés attendus existent déjà. Une erreur utilisateur typée est levée si un élément manque. Cette option est utile lorsqu’un processus externe (Terraform, Liquibase, pipeline de publication, etc.) gère le schéma et que Mastra doit uniquement le vérifier. (Default: `'sync'`) ## Exemples de constructeurs Vous pouvez instancier `SpannerStore` de plusieurs manières : ```typescript import { Spanner } from '@google-cloud/spanner' import { SpannerStore } from '@mastra/spanner' // Using projectId / instanceId / databaseId const store1 = new SpannerStore({ id: 'spanner-storage-1', projectId: 'my-gcp-project', instanceId: 'my-instance', databaseId: 'mastra', }) // Reusing an existing Spanner Database handle const spanner = new Spanner({ projectId: 'my-gcp-project' }) const database = spanner.instance('my-instance').database('mastra') const store2 = new SpannerStore({ id: 'spanner-storage-2', database, }) // Using the local Spanner emulator (set the SPANNER_EMULATOR_HOST env var) process.env.SPANNER_EMULATOR_HOST = 'localhost:9010' const store3 = new SpannerStore({ id: 'spanner-storage-emulator', projectId: 'test-project', instanceId: 'test-instance', databaseId: 'test-db', spannerOptions: { servicePath: 'localhost', port: 9010, sslCreds: undefined }, }) ``` ## Remarques complémentaires ### Gestion du schéma L'adaptateur de stockage crée les tables suivantes, toutes à l'aide du dialecte GoogleSQL : - `mastra_workflow_snapshot` : état du workflow et données d'exécution - `mastra_threads` : threads de conversation - `mastra_messages` : messages individuels - `mastra_resources` : mémoire de travail des ressources - `mastra_scorers` : scores d'évaluation - `mastra_background_tasks` : état d'exécution des Tools en arrière-plan - `mastra_agents` : enregistrements légers des agents (ID, état, version active) - `mastra_agent_versions` : instantanés versionnés de la configuration des agents - `mastra_mcp_clients` / `mastra_mcp_client_versions` : configurations des clients MCP et historique de leurs versions - `mastra_mcp_servers` / `mastra_mcp_server_versions` : configurations des serveurs MCP et historique de leurs versions - `mastra_skills` / `mastra_skill_versions` : enregistrements de Skills et instantanés versionnés des Skills (instructions, références, scripts, ressources, arborescence du contenu) - `mastra_skill_blobs` : stockage de blobs adressables par contenu, indexé par hachage SHA-256 et utilisé pour le contenu des versions de Skills - `mastra_prompt_blocks` / `mastra_prompt_block_versions` : enregistrements de blocs de prompt et instantanés versionnés du contenu (contenu du modèle, règles, schéma Request Context) - `mastra_scorer_definitions` / `mastra_scorer_definition_versions` : enregistrements de définitions de Scorers et instantanés versionnés de la configuration (instructions du juge, modèle, plage de scores, configuration prédéfinie, échantillonnage par défaut) - `mastra_schedules` / `mastra_schedule_triggers` : planifications de workflows pilotées par cron et historique des déclenchements, utilisés par le `WorkflowScheduler` intégré de Mastra - `mastra_workspaces` / `mastra_workspace_versions` : enregistrements de Workspaces et instantanés versionnés de leur configuration (système de fichiers, Sandbox, montages, recherche, Skills, Tools) - `mastra_datasets` / `mastra_dataset_items` / `mastra_dataset_versions` : jeux de données d'évaluation, éléments versionnés selon SCD-2 et instantanés de versions - `mastra_experiments` / `mastra_experiment_results` : exécutions d'expériences et résultats de chaque élément - `mastra_favorites` : favoris par utilisateur pour les agents et les Skills, avec le champ `favoriteCount` dénormalisé conservé dans l'enregistrement parent - `mastra_channel_installations` / `mastra_channel_config` : installations de canaux multiplateformes et configuration propre à chaque plateforme - `mastra_ai_spans` : spans de traçage de l'IA pour l'observabilité (enregistrements par trace et par span, utilisés pour alimenter l'interface des traces de Studio) Les tables sont créées avec `STRING(MAX)` pour le texte et les payloads JSON, ainsi qu'avec `INT64`, `FLOAT64`, `BOOL` et `TIMESTAMP`. Les tables suivantes contiennent des colonnes générées `STORED` propres à Spanner. L'adaptateur les renseigne à partir des payloads JSON afin que les filtres courants puissent utiliser un index secondaire standard plutôt qu'une analyse `JSON_VALUE` : - `mastra_workflow_snapshot.snapshotStatus` : extrait `$.status` de `snapshot`. Prend en charge `listWorkflowRuns({ status })`. - `mastra_schedules.target_workflow_id` : extrait `$.workflowId` de `target`. Prend en charge `listSchedules({ workflowId })`. Ces deux colonnes sont ajoutées avec `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` pendant `init()` et ignorées lorsque `initMode: 'validate'` est utilisé (le schéma est alors géré en externe). Si la colonne est absente, l'adaptateur utilise à l'exécution un filtre `JSON_VALUE` comme solution de repli. L'adaptateur ne crée ni n'utilise de schémas. Utilisez une base de données dédiée pour garantir l'isolation. ### Initialisation Lorsque vous transmettez le stockage à la classe `Mastra`, `init()` est appelée automatiquement avant toute opération de stockage : ```typescript import { Mastra } from '@mastra/core' import { SpannerStore } from '@mastra/spanner' const storage = new SpannerStore({ id: 'spanner-storage', projectId: process.env.SPANNER_PROJECT_ID!, instanceId: process.env.SPANNER_INSTANCE_ID!, databaseId: process.env.SPANNER_DATABASE_ID!, }) const mastra = new Mastra({ storage, // init() is called automatically }) ``` Si vous utilisez directement le stockage, appelez `init()` une fois avant la première opération. Spanner n'autorise pas les modifications simultanées du schéma ; `SpannerStore.init()` exécute donc séquentiellement la configuration de chaque domaine. ```typescript const storage = new SpannerStore({ id: 'spanner-storage', projectId: process.env.SPANNER_PROJECT_ID!, instanceId: process.env.SPANNER_INSTANCE_ID!, databaseId: process.env.SPANNER_DATABASE_ID!, }) await storage.init() const memory = await storage.getStore('memory') const thread = await memory?.getThreadById({ threadId: '...' }) ``` > **Attention:** Si `init()` n'est pas appelée et que `disableInit` vaut true, les tables requises n'existeront pas et les opérations de stockage échoueront. ### Particularités de GoogleSQL Certains comportements diffèrent de ceux des autres adaptateurs relationnels : - Les upserts utilisent `INSERT OR UPDATE`. Spanner ne fournit aucune clause `RETURNING` pour les upserts ; les appelants qui ont besoin de l'état après l'écriture doivent donc le relire. - Il n'existe pas de commande `TRUNCATE`. `dangerouslyClearAll()` émet `DELETE WHERE TRUE`. - Les identifiants sont placés entre des accents graves. - Les instructions DDL sont appliquées avec `database.updateSchema(...)`, qui est asynchrone (opération de longue durée). - `NULLS FIRST/LAST` n'est pas pris en charge. Le tri avec gestion des valeurs NULL est émulé à l'aide d'une clé de tri `IS NULL`. - La contenance JSON n'est pas prise en charge nativement. Dans `listTraces`, les filtres `metadata` et `scope` sont compilés en contrôles d'égalité `JSON_VALUE(...) = @v` par clé, tandis que les filtres `tags` sont compilés en `EXISTS` sur `JSON_QUERY_ARRAY(...)`. Ce comportement diffère de l'opérateur de contenance `@>` de Postgres, qui peut faire correspondre une structure imbriquée en une seule analyse d'index : la plupart des recherches ponctuelles fonctionnent toujours, mais les correspondances structurelles profondément imbriquées ne peuvent pas être exprimées. ### Accès direct à la base de données `SpannerStore` expose les objets sous-jacents du client Spanner : ```typescript store.database // @google-cloud/spanner Database store.instance // @google-cloud/spanner Instance (when created internally) store.spanner // @google-cloud/spanner Spanner client (when created internally) ``` Ces objets sont destinés aux scénarios avancés, comme les transactions personnalisées ou l'introspection du schéma. Lorsque vous réutilisez directement la base de données, vous contournez la logique de validation et de conversion JSON de l'adaptateur. ### Développement local avec l'émulateur Exécutez localement l'émulateur Cloud Spanner avec Docker : ```bash docker run -p 9010:9010 -p 9020:9020 gcr.io/cloud-spanner-emulator/emulator ``` Définissez `SPANNER_EMULATOR_HOST=localhost:9010`, puis créez l'instance et la base de données avant d'exécuter votre application : ```bash gcloud spanner instances create test-instance --config=emulator-config --nodes=1 gcloud spanner databases create test-db --instance=test-instance ``` Connectez-vous ensuite en définissant la même variable d'environnement dans votre processus Node.js. Le client `@google-cloud/spanner` détecte automatiquement l'émulateur.