Files
SpacetimeDB/docs/build/subscriptions/index.html
T
Julien Lavocat c20c30524b Remove old docs
2025-10-21 12:12:01 +02:00

348 lines
80 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-Subscriptions/Subscription-Reference" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.9.1">
<title data-rh="true">Subscription Reference | SpacetimeDB docs</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://docs.spacetimedb.com/subscriptions"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Subscription Reference | SpacetimeDB docs"><meta data-rh="true" name="description" content="The subscription API allows a client to replicate a subset of a database."><meta data-rh="true" property="og:description" content="The subscription API allows a client to replicate a subset of a database."><link data-rh="true" rel="icon" href="/images/favicon.ico"><link data-rh="true" rel="canonical" href="https://docs.spacetimedb.com/subscriptions"><link data-rh="true" rel="alternate" href="https://docs.spacetimedb.com/subscriptions" hreflang="en"><link data-rh="true" rel="alternate" href="https://docs.spacetimedb.com/subscriptions" hreflang="x-default"><link data-rh="true" rel="preconnect" href="https://QBC7Z9KXS2-dsn.algolia.net" crossorigin="anonymous"><script data-rh="true" type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Subscription Reference","item":"https://docs.spacetimedb.com/subscriptions"}]}</script><link rel="search" type="application/opensearchdescription+xml" title="SpacetimeDB docs" href="/opensearch.xml"><link rel="stylesheet" href="/assets/css/styles.0cb9f7a7.css">
<script src="/assets/js/runtime~main.d71df0f5.js" defer="defer"></script>
<script src="/assets/js/main.31d95d83.js" defer="defer"></script>
</head>
<body class="navigation-with-keyboard">
<svg style="display: none;"><defs>
<symbol id="theme-svg-external-link" viewBox="0 0 24 24"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"/></symbol>
</defs></svg>
<script>document.documentElement.setAttribute("data-theme","light"),document.documentElement.setAttribute("data-theme-choice","light"),function(){try{const c=new URLSearchParams(window.location.search).entries();for(var[t,e]of c)if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id="__docusaurus"><link rel="preload" as="image" href="https://spacetimedb.com/images/brand.png"><div role="region" aria-label="Skip to main content"><a class="skipToContent_6jFv" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="theme-layout-navbar navbar navbar--fixed-top"><div class="navbar__inner"><div class="theme-layout-navbar-left navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><div class="navbar__logo"><img src="https://spacetimedb.com/images/brand.png" alt="SpacetimeDB Logo" class="themedComponent_rvet themedComponent--light_mbAJ"><img src="https://spacetimedb.com/images/brand.png" alt="SpacetimeDB Logo" class="themedComponent_rvet themedComponent--dark_Ncy6"></div></a><div class="navbarSearchContainer_AesG"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search (Command+K)"><span class="DocSearch-Button-Container"><svg width="20" height="20" class="DocSearch-Search-Icon" viewBox="0 0 20 20" aria-hidden="true"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"></span></button></div></div><div class="theme-layout-navbar-right navbar__items navbar__items--right"><a href="https://spacetimedb.com/install" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Install</a><a href="https://spacetimedb.com/pricing" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Pricing</a><a href="https://spacetimedb.com/maincloud" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Maincloud</a><a href="https://spacetimedb.com/blog" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Blog</a><a href="https://spacetimedb.com/community" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Community</a></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="theme-layout-main main-wrapper mainWrapper_hV_y"><div class="docsWrapper_f07g"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_MJiz" type="button"></button><div class="docRoot_Gd2s"><aside class="theme-doc-sidebar-container docSidebarContainer_fSpF"><div class="sidebarViewport_YElg"><div class="sidebar_kjg4"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_AG0n"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/"><span title="Intro" class="categoryLinkLabel_EDYQ">Intro</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/deploying/maincloud"><span title="Deploying" class="categoryLinkLabel_EDYQ">Deploying</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/unity"><span title="Unity tutorial" class="categoryLinkLabel_EDYQ">Unity tutorial</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/unreal"><span title="Unreal Tutorial" class="categoryLinkLabel_EDYQ">Unreal Tutorial</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/cli-reference"><span title="CLI Reference" class="categoryLinkLabel_EDYQ">CLI Reference</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/modules"><span title="Server Module Languages" class="categoryLinkLabel_EDYQ">Server Module Languages</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/sdks"><span title="Client SDK Languages" class="categoryLinkLabel_EDYQ">Client SDK Languages</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/sql"><span title="SQL" class="categoryLinkLabel_EDYQ">SQL</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" role="button" aria-expanded="true" href="/subscriptions"><span title="Subscriptions" class="categoryLinkLabel_EDYQ">Subscriptions</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/subscriptions"><span title="Subscription Reference" class="linkLabel_dpMB">Subscription Reference</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/subscriptions/semantics"><span title="Subscription Semantics" class="linkLabel_dpMB">Subscription Semantics</span></a></li></ul></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/rls"><span title="Row Level Security" class="linkLabel_dpMB">Row Level Security</span></a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/how-to/incremental-migrations"><span title="How-To" class="categoryLinkLabel_EDYQ">How-To</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/spacetimeauth"><span title="SpacetimeAuth" class="categoryLinkLabel_EDYQ">SpacetimeAuth</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/http/authorization"><span title="HTTP API" class="categoryLinkLabel_EDYQ">HTTP API</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_ggI5 menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/webassembly-abi"><span title="Internals" class="categoryLinkLabel_EDYQ">Internals</span></a></div></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/appendix"><span title="Appendix" class="linkLabel_dpMB">Appendix</span></a></li></ul></nav></div></div></aside><main class="docMainContainer_dkUT"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_w2oE"><div class="docItemContainer_f71m"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_xsLZ" aria-label="Breadcrumbs"><ul class="breadcrumbs"><li class="breadcrumbs__item"><a aria-label="Home page" class="breadcrumbs__link" href="/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_oyay"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li class="breadcrumbs__item"><span class="breadcrumbs__link">Subscriptions</span></li><li class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link">Subscription Reference</span></li></ul></nav><div class="tocCollapsible_dqme theme-doc-toc-mobile tocMobile_Z34P"><button type="button" class="clean-btn tocCollapsibleButton_QMSE">On this page</button></div><div class="theme-doc-markdown markdown"><header><h1>The SpacetimeDB Subscription API</h1></header>
<p>The subscription API allows a client to replicate a subset of a database.
It does so by registering SQL queries, which we call subscriptions, through a database connection.
A client will only receive updates for rows that match the subscriptions it has registered.</p>
<p>For more information on syntax and requirements see the <a href="/sql#subscriptions">SQL docs</a>.</p>
<p>This guide describes the two main interfaces that comprise the API - <code>SubscriptionBuilder</code> and <code>SubscriptionHandle</code>.
By using these interfaces, you can create efficient and responsive client applications that only receive the data they need.</p>
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="subscriptionbuilder">SubscriptionBuilder<a href="#subscriptionbuilder" class="hash-link" aria-label="Direct link to SubscriptionBuilder" title="Direct link to SubscriptionBuilder" translate="no"></a></h2>
<div class="theme-tabs-container tabs-container tabList_MbSD"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_Ssy3 tabs__item--active">Rust</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_Ssy3">C#</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_sydm"><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">pub</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> SubscriptionBuilder</span><span style="color:#F8F8F2">&lt;</span><span style="color:#8BE9FD;font-style:italic">M</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeModule</span><span style="color:#F8F8F2">&gt; { </span><span style="color:#6272A4">/* private fields */</span><span style="color:#F8F8F2"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FF79C6">impl</span><span style="color:#F8F8F2">&lt;</span><span style="color:#8BE9FD;font-style:italic">M</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeModule</span><span style="color:#F8F8F2">&gt; </span><span style="color:#8BE9FD;font-style:italic">SubscriptionBuilder</span><span style="color:#F8F8F2">&lt;</span><span style="color:#8BE9FD;font-style:italic">M</span><span style="color:#F8F8F2">&gt; {</span></span>
<span class="line"><span style="color:#6272A4"> /// Register a callback that runs when the subscription has been applied.</span></span>
<span class="line"><span style="color:#6272A4"> /// This callback receives a context containing the current state of the subscription.</span></span>
<span class="line"><span style="color:#FF79C6"> pub</span><span style="color:#FF79C6"> fn</span><span style="color:#50FA7B"> on_applied</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">mut</span><span style="color:#BD93F9;font-style:italic"> self</span><span style="color:#F8F8F2">, callback</span><span style="color:#FF79C6">:</span><span style="color:#FF79C6"> impl</span><span style="color:#50FA7B"> FnOnce</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">&amp;</span><span style="color:#F8F8F2">M</span><span style="color:#FF79C6">::</span><span style="color:#8BE9FD;font-style:italic">SubscriptionEventContext</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">+</span><span style="color:#8BE9FD;font-style:italic"> Send</span><span style="color:#FF79C6"> +</span><span style="color:#F8F8F2"> &#x27;</span><span style="color:#8BE9FD;font-style:italic">static</span><span style="color:#F8F8F2">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// Register a callback to run when the subscription fails.</span></span>
<span class="line"><span style="color:#6272A4"> ///</span></span>
<span class="line"><span style="color:#6272A4"> /// Note that this callback may run either when attempting to apply the subscription,</span></span>
<span class="line"><span style="color:#6272A4"> /// in which case [`Self::on_applied`] will never run,</span></span>
<span class="line"><span style="color:#6272A4"> /// or later during the subscription&#x27;s lifetime if the module&#x27;s interface changes,</span></span>
<span class="line"><span style="color:#6272A4"> /// in which case [`Self::on_applied`] may have already run.</span></span>
<span class="line"><span style="color:#FF79C6"> pub</span><span style="color:#FF79C6"> fn</span><span style="color:#50FA7B"> on_error</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">mut</span><span style="color:#BD93F9;font-style:italic"> self</span><span style="color:#F8F8F2">, callback</span><span style="color:#FF79C6">:</span><span style="color:#FF79C6"> impl</span><span style="color:#50FA7B"> FnOnce</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">&amp;</span><span style="color:#F8F8F2">M</span><span style="color:#FF79C6">::</span><span style="color:#8BE9FD;font-style:italic">ErrorContext</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">crate::</span><span style="color:#8BE9FD;font-style:italic">Error</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">+</span><span style="color:#8BE9FD;font-style:italic"> Send</span><span style="color:#FF79C6"> +</span><span style="color:#F8F8F2"> &#x27;</span><span style="color:#8BE9FD;font-style:italic">static</span><span style="color:#F8F8F2">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// Subscribe to a subset of the database via a set of SQL queries.</span></span>
<span class="line"><span style="color:#6272A4"> /// Returns a handle which you can use to monitor or drop the subscription later.</span></span>
<span class="line"><span style="color:#FF79C6"> pub</span><span style="color:#FF79C6"> fn</span><span style="color:#50FA7B"> subscribe</span><span style="color:#F8F8F2">&lt;</span><span style="color:#8BE9FD;font-style:italic">Queries</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> IntoQueries</span><span style="color:#F8F8F2">&gt;(</span><span style="color:#BD93F9;font-style:italic">self</span><span style="color:#F8F8F2">, query_sql</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> Queries</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">-&gt;</span><span style="color:#F8F8F2"> M</span><span style="color:#FF79C6">::</span><span style="color:#8BE9FD;font-style:italic">SubscriptionHandle</span><span style="color:#F8F8F2">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// Subscribe to all rows from all tables.</span></span>
<span class="line"><span style="color:#6272A4"> ///</span></span>
<span class="line"><span style="color:#6272A4"> /// This method is intended as a convenience</span></span>
<span class="line"><span style="color:#6272A4"> /// for applications where client-side memory use and network bandwidth are not concerns.</span></span>
<span class="line"><span style="color:#6272A4"> /// Applications where these resources are a constraint</span></span>
<span class="line"><span style="color:#6272A4"> /// should register more precise queries via [`Self::subscribe`]</span></span>
<span class="line"><span style="color:#6272A4"> /// in order to replicate only the subset of data which the client needs to function.</span></span>
<span class="line"><span style="color:#FF79C6"> pub</span><span style="color:#FF79C6"> fn</span><span style="color:#50FA7B"> subscribe_to_all_tables</span><span style="color:#F8F8F2">(</span><span style="color:#BD93F9;font-style:italic">self</span><span style="color:#F8F8F2">);</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">/// Types which specify a list of query strings.</span></span>
<span class="line"><span style="color:#FF79C6">pub</span><span style="color:#FF79C6"> trait</span><span style="color:#8BE9FD;font-style:italic"> IntoQueries</span><span style="color:#F8F8F2"> {</span></span>
<span class="line"><span style="color:#FF79C6"> fn</span><span style="color:#50FA7B"> into_queries</span><span style="color:#F8F8F2">(</span><span style="color:#BD93F9;font-style:italic">self</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">-&gt;</span><span style="color:#8BE9FD;font-style:italic"> Box</span><span style="color:#F8F8F2">&lt;[</span><span style="color:#8BE9FD;font-style:italic">Box</span><span style="color:#F8F8F2">&lt;</span><span style="color:#8BE9FD;font-style:italic">str</span><span style="color:#F8F8F2">&gt;]&gt;;</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre></div><div role="tabpanel" class="tabItem_sydm" hidden=""><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> sealed</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> SubscriptionBuilder</span></span>
<span class="line"><span style="color:#F8F8F2">{</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// Register a callback to run when the subscription is applied.</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#8BE9FD;font-style:italic"> SubscriptionBuilder</span><span style="color:#50FA7B"> OnApplied</span><span style="color:#F8F8F2">(</span></span>
<span class="line"><span style="color:#8BE9FD;font-style:italic"> Action</span><span style="color:#F8F8F2">&lt;</span><span style="color:#8BE9FD;font-style:italic">SubscriptionEventContext</span><span style="color:#F8F8F2">&gt; </span><span style="color:#FFB86C;font-style:italic">callback</span></span>
<span class="line"><span style="color:#F8F8F2"> );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// Register a callback to run when the subscription fails.</span></span>
<span class="line"><span style="color:#6272A4"> ///</span></span>
<span class="line"><span style="color:#6272A4"> /// Note that this callback may run either when attempting to apply the subscription,</span></span>
<span class="line"><span style="color:#6272A4"> /// in which case </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">c</span><span style="color:#F8F8F2">&gt;</span><span style="color:#6272A4">Self::on_applied</span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">c</span><span style="color:#F8F8F2">&gt;</span><span style="color:#6272A4"> will never run,</span></span>
<span class="line"><span style="color:#6272A4"> /// or later during the subscription&#x27;s lifetime if the module&#x27;s interface changes,</span></span>
<span class="line"><span style="color:#6272A4"> /// in which case </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">c</span><span style="color:#F8F8F2">&gt;</span><span style="color:#6272A4">Self::on_applied</span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">c</span><span style="color:#F8F8F2">&gt;</span><span style="color:#6272A4"> may have already run.</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#8BE9FD;font-style:italic"> SubscriptionBuilder</span><span style="color:#50FA7B"> OnError</span><span style="color:#F8F8F2">(</span></span>
<span class="line"><span style="color:#8BE9FD;font-style:italic"> Action</span><span style="color:#F8F8F2">&lt;</span><span style="color:#8BE9FD;font-style:italic">ErrorContext</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Exception</span><span style="color:#F8F8F2">&gt; </span><span style="color:#FFB86C;font-style:italic">callback</span></span>
<span class="line"><span style="color:#F8F8F2"> );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// Subscribe to the following SQL queries.</span></span>
<span class="line"><span style="color:#6272A4"> ///</span></span>
<span class="line"><span style="color:#6272A4"> /// This method returns immediately, with the data not yet added to the DbConnection.</span></span>
<span class="line"><span style="color:#6272A4"> /// The provided callbacks will be invoked once the data is returned from the remote server.</span></span>
<span class="line"><span style="color:#6272A4"> /// Data from all the provided queries will be returned at the same time.</span></span>
<span class="line"><span style="color:#6272A4"> ///</span></span>
<span class="line"><span style="color:#6272A4"> /// See the SpacetimeDB SQL docs for more information on SQL syntax:</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">a</span><span style="color:#50FA7B;font-style:italic"> href</span><span style="color:#6272A4">=</span><span style="color:#E9F284">&quot;</span><span style="color:#F1FA8C">https://spacetimedb.com/docs/sql</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">&gt;</span><span style="color:#6272A4">https://spacetimedb.com/docs/sql</span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">a</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#8BE9FD;font-style:italic"> SubscriptionHandle</span><span style="color:#50FA7B"> Subscribe</span><span style="color:#F8F8F2">(</span></span>
<span class="line"><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2">[] </span><span style="color:#FFB86C;font-style:italic">querySqls</span></span>
<span class="line"><span style="color:#F8F8F2"> );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// Subscribe to all rows from all tables.</span></span>
<span class="line"><span style="color:#6272A4"> ///</span></span>
<span class="line"><span style="color:#6272A4"> /// This method is intended as a convenience</span></span>
<span class="line"><span style="color:#6272A4"> /// for applications where client-side memory use and network bandwidth are not concerns.</span></span>
<span class="line"><span style="color:#6272A4"> /// Applications where these resources are a constraint</span></span>
<span class="line"><span style="color:#6272A4"> /// should register more precise queries via </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">c</span><span style="color:#F8F8F2">&gt;</span><span style="color:#6272A4">Self.Subscribe</span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">c</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// in order to replicate only the subset of data which the client needs to function.</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> SubscribeToAllTables</span><span style="color:#F8F8F2">();</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre></div></div></div>
<p>A <code>SubscriptionBuilder</code> provides an interface for registering subscription queries with a database.
It allows you to register callbacks that run when the subscription is successfully applied or when an error occurs.
Once applied, a client will start receiving row updates to its client cache.
A client can react to these updates by registering row callbacks for the appropriate table.</p>
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="example-usage">Example Usage<a href="#example-usage" class="hash-link" aria-label="Direct link to Example Usage" title="Direct link to Example Usage" translate="no"></a></h3>
<div class="theme-tabs-container tabs-container tabList_MbSD"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_Ssy3 tabs__item--active">Rust</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_Ssy3">C#</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_sydm"><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#6272A4">// Establish a database connection</span></span>
<span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> conn</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> DbConnection</span><span style="color:#FF79C6"> =</span><span style="color:#50FA7B"> connect_to_db</span><span style="color:#F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// Register a subscription with the database</span></span>
<span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> subscription_handle </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscription_builder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">on_applied</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2">ctx</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle applied state */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">on_error</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2">error_ctx, error</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle error */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscribe</span><span style="color:#F8F8F2">([</span><span style="color:#F1FA8C">&quot;SELECT * FROM user&quot;</span><span style="color:#F8F8F2">, </span><span style="color:#F1FA8C">&quot;SELECT * FROM message&quot;</span><span style="color:#F8F8F2">]);</span></span></code></pre></div><div role="tabpanel" class="tabItem_sydm" hidden=""><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#6272A4">// Establish a database connection</span></span>
<span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> conn </span><span style="color:#FF79C6">=</span><span style="color:#50FA7B"> ConnectToDB</span><span style="color:#F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// Register a subscription with the database</span></span>
<span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> userSubscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">SubscriptionBuilder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">OnApplied</span><span style="color:#F8F8F2">((</span><span style="color:#FFB86C;font-style:italic">ctx</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">=&gt;</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle applied state */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">OnError</span><span style="color:#F8F8F2">((</span><span style="color:#FFB86C;font-style:italic">errorCtx</span><span style="color:#F8F8F2">, </span><span style="color:#FFB86C;font-style:italic">error</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">=&gt;</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle error */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">Subscribe</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2">[] { </span><span style="color:#E9F284">&quot;</span><span style="color:#F1FA8C">SELECT * FROM user</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">, </span><span style="color:#E9F284">&quot;</span><span style="color:#F1FA8C">SELECT * FROM message</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2"> });</span></span></code></pre></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="subscriptionhandle">SubscriptionHandle<a href="#subscriptionhandle" class="hash-link" aria-label="Direct link to SubscriptionHandle" title="Direct link to SubscriptionHandle" translate="no"></a></h2>
<div class="theme-tabs-container tabs-container tabList_MbSD"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_Ssy3 tabs__item--active">Rust</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_Ssy3">C#</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_sydm"><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">pub</span><span style="color:#FF79C6"> trait</span><span style="color:#8BE9FD;font-style:italic"> SubscriptionHandle</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> InModule</span><span style="color:#FF79C6"> +</span><span style="color:#8BE9FD;font-style:italic"> Clone</span><span style="color:#FF79C6"> +</span><span style="color:#8BE9FD;font-style:italic"> Send</span><span style="color:#FF79C6"> +</span><span style="color:#F8F8F2"> &#x27;</span><span style="color:#8BE9FD;font-style:italic">static</span></span>
<span class="line"><span style="color:#FF79C6">where</span></span>
<span class="line"><span style="color:#BD93F9;font-style:italic"> Self</span><span style="color:#FF79C6">::</span><span style="color:#8BE9FD;font-style:italic">Module</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeModule</span><span style="color:#F8F8F2">&lt;</span><span style="color:#8BE9FD;font-style:italic">SubscriptionHandle</span><span style="color:#FF79C6"> =</span><span style="color:#BD93F9;font-style:italic"> Self</span><span style="color:#F8F8F2">&gt;,</span></span>
<span class="line"><span style="color:#F8F8F2">{</span></span>
<span class="line"><span style="color:#6272A4"> /// Returns `true` if the subscription has been ended.</span></span>
<span class="line"><span style="color:#6272A4"> /// That is, if it has been unsubscribed or terminated due to an error.</span></span>
<span class="line"><span style="color:#FF79C6"> fn</span><span style="color:#50FA7B"> is_ended</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">&amp;</span><span style="color:#BD93F9;font-style:italic">self</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">-&gt;</span><span style="color:#8BE9FD;font-style:italic"> bool</span><span style="color:#F8F8F2">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// Returns `true` if the subscription is currently active.</span></span>
<span class="line"><span style="color:#FF79C6"> fn</span><span style="color:#50FA7B"> is_active</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">&amp;</span><span style="color:#BD93F9;font-style:italic">self</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">-&gt;</span><span style="color:#8BE9FD;font-style:italic"> bool</span><span style="color:#F8F8F2">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// Unsubscribe from the query controlled by this `SubscriptionHandle`,</span></span>
<span class="line"><span style="color:#6272A4"> /// then run `on_end` when its rows are removed from the client cache.</span></span>
<span class="line"><span style="color:#6272A4"> /// Returns an error if the subscription is already ended,</span></span>
<span class="line"><span style="color:#6272A4"> /// or if unsubscribe has already been called.</span></span>
<span class="line"><span style="color:#FF79C6"> fn</span><span style="color:#50FA7B"> unsubscribe_then</span><span style="color:#F8F8F2">(</span><span style="color:#BD93F9;font-style:italic">self</span><span style="color:#F8F8F2">, on_end</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> OnEndedCallback</span><span style="color:#F8F8F2">&lt;</span><span style="color:#BD93F9;font-style:italic">Self</span><span style="color:#FF79C6">::</span><span style="color:#8BE9FD;font-style:italic">Module</span><span style="color:#F8F8F2">&gt;) </span><span style="color:#FF79C6">-&gt;</span><span style="color:#FF79C6"> crate::</span><span style="color:#8BE9FD;font-style:italic">Result</span><span style="color:#F8F8F2">&lt;()&gt;;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// Unsubscribe from the query controlled by this `SubscriptionHandle`.</span></span>
<span class="line"><span style="color:#6272A4"> /// Returns an error if the subscription is already ended,</span></span>
<span class="line"><span style="color:#6272A4"> /// or if unsubscribe has already been called.</span></span>
<span class="line"><span style="color:#FF79C6"> fn</span><span style="color:#50FA7B"> unsubscribe</span><span style="color:#F8F8F2">(</span><span style="color:#BD93F9;font-style:italic">self</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">-&gt;</span><span style="color:#FF79C6"> crate::</span><span style="color:#8BE9FD;font-style:italic">Result</span><span style="color:#F8F8F2">&lt;()&gt;;</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre></div><div role="tabpanel" class="tabItem_sydm" hidden=""><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> SubscriptionHandle</span><span style="color:#F8F8F2">&lt;</span><span style="color:#FFB86C;font-style:italic">SubscriptionEventContext</span><span style="color:#F8F8F2">, </span><span style="color:#FFB86C;font-style:italic">ErrorContext</span><span style="color:#F8F8F2">&gt; : </span><span style="color:#8BE9FD;font-style:italic">ISubscriptionHandle</span></span>
<span class="line"><span style="color:#FF79C6"> where</span><span style="color:#FFB86C;font-style:italic"> SubscriptionEventContext</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">ISubscriptionEventContext</span></span>
<span class="line"><span style="color:#FF79C6"> where</span><span style="color:#FFB86C;font-style:italic"> ErrorContext</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">IErrorContext</span></span>
<span class="line"><span style="color:#F8F8F2"> {</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// Whether the subscription has ended.</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> bool</span><span style="color:#F8F8F2"> IsEnded;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// Whether the subscription is active.</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> bool</span><span style="color:#F8F8F2"> IsActive;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// Unsubscribe from the query controlled by this subscription handle.</span></span>
<span class="line"><span style="color:#6272A4"> ///</span></span>
<span class="line"><span style="color:#6272A4"> /// Calling this more than once will result in an exception.</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Unsubscribe</span><span style="color:#F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#6272A4"> /// Unsubscribe from the query controlled by this subscription handle,</span></span>
<span class="line"><span style="color:#6272A4"> /// and call onEnded when its rows are removed from the client cache.</span></span>
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2">&lt;/</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">&gt;</span></span>
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> UnsubscribeThen</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Action</span><span style="color:#F8F8F2">&lt;</span><span style="color:#8BE9FD;font-style:italic">SubscriptionEventContext</span><span style="color:#F8F8F2">&gt;? </span><span style="color:#FFB86C;font-style:italic">onEnded</span><span style="color:#F8F8F2">);</span></span>
<span class="line"><span style="color:#F8F8F2"> }</span></span></code></pre></div></div></div>
<p>When you register a subscription, you receive a <code>SubscriptionHandle</code>.
A <code>SubscriptionHandle</code> manages the lifecycle of each subscription you register.
In particular, it provides methods to check the status of the subscription and to unsubscribe if necessary.
Because each subscription has its own independently managed lifetime,
clients can dynamically subscribe to different subsets of the database as their application requires.</p>
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="example-usage-1">Example Usage<a href="#example-usage-1" class="hash-link" aria-label="Direct link to Example Usage" title="Direct link to Example Usage" translate="no"></a></h3>
<div class="theme-tabs-container tabs-container tabList_MbSD"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_Ssy3 tabs__item--active">Rust</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_Ssy3">C#</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_sydm"><p>Consider a game client that displays shop items and discounts based on a player&#x27;s level.
You subscribe to <code>shop_items</code> and <code>shop_discounts</code> when a player is at level 5:</p><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> conn</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> DbConnection</span><span style="color:#FF79C6"> =</span><span style="color:#50FA7B"> connect_to_db</span><span style="color:#F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> shop_items_subscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscription_builder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">on_applied</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2">ctx</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle applied state */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">on_error</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2">error_ctx, error</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle error */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscribe</span><span style="color:#F8F8F2">([</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM shop_items WHERE required_level &lt;= 5&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM shop_discounts WHERE required_level &lt;= 5&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> ]);</span></span></code></pre><p>Later, when the player reaches level 6 and new items become available,
you can subscribe to the new queries and unsubscribe from the old ones:</p><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> new_shop_items_subscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscription_builder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">on_applied</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2">ctx</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle applied state */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">on_error</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2">error_ctx, error</span><span style="color:#FF79C6">|</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle error */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscribe</span><span style="color:#F8F8F2">([</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM shop_items WHERE required_level &lt;= 6&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM shop_discounts WHERE required_level &lt;= 6&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> ]);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FF79C6">if</span><span style="color:#F8F8F2"> shop_items_subscription</span><span style="color:#FF79C6">.</span><span style="color:#50FA7B">is_active</span><span style="color:#F8F8F2">() {</span></span>
<span class="line"><span style="color:#F8F8F2"> shop_items_subscription</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">unsubscribe</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">expect</span><span style="color:#F8F8F2">(</span><span style="color:#F1FA8C">&quot;Unsubscribing from shop_items failed&quot;</span><span style="color:#F8F8F2">);</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre><p>All other subscriptions continue to remain in effect.</p></div><div role="tabpanel" class="tabItem_sydm" hidden=""><p>Consider a game client that displays shop items and discounts based on a player&#x27;s level.
You subscribe to <code>shop_items</code> and <code>shop_discounts</code> when a player is at level 5:</p><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> conn </span><span style="color:#FF79C6">=</span><span style="color:#50FA7B"> ConnectToDB</span><span style="color:#F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> shopItemsSubscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">SubscriptionBuilder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">OnApplied</span><span style="color:#F8F8F2">((</span><span style="color:#FFB86C;font-style:italic">ctx</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">=&gt;</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle applied state */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">OnError</span><span style="color:#F8F8F2">((</span><span style="color:#FFB86C;font-style:italic">errorCtx</span><span style="color:#F8F8F2">, </span><span style="color:#FFB86C;font-style:italic">error</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">=&gt;</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle error */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">Subscribe</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2">[] {</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM shop_items WHERE required_level &lt;= 5</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM shop_discounts WHERE required_level &lt;= 5</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> });</span></span></code></pre><p>Later, when the player reaches level 6 and new items become available,
you can subscribe to the new queries and unsubscribe from the old ones:</p><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> newShopItemsSubscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">SubscriptionBuilder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">OnApplied</span><span style="color:#F8F8F2">((</span><span style="color:#FFB86C;font-style:italic">ctx</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">=&gt;</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle applied state */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">OnError</span><span style="color:#F8F8F2">((</span><span style="color:#FFB86C;font-style:italic">errorCtx</span><span style="color:#F8F8F2">, </span><span style="color:#FFB86C;font-style:italic">error</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">=&gt;</span><span style="color:#F8F8F2"> { </span><span style="color:#6272A4">/* handle error */</span><span style="color:#F8F8F2"> })</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">Subscribe</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2">[] {</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM shop_items WHERE required_level &lt;= 6</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM shop_discounts WHERE required_level &lt;= 6</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FF79C6">if</span><span style="color:#F8F8F2"> (shopItemsSubscription.IsActive)</span></span>
<span class="line"><span style="color:#F8F8F2">{</span></span>
<span class="line"><span style="color:#F8F8F2"> shopItemsSubscription.</span><span style="color:#50FA7B">Unsubscribe</span><span style="color:#F8F8F2">();</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre><p>All other subscriptions continue to remain in effect.</p></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="best-practices-for-optimizing-server-compute-and-reducing-serialization-overhead">Best Practices for Optimizing Server Compute and Reducing Serialization Overhead<a href="#best-practices-for-optimizing-server-compute-and-reducing-serialization-overhead" class="hash-link" aria-label="Direct link to Best Practices for Optimizing Server Compute and Reducing Serialization Overhead" title="Direct link to Best Practices for Optimizing Server Compute and Reducing Serialization Overhead" translate="no"></a></h2>
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="1-writing-efficient-sql-queries">1. Writing Efficient SQL Queries<a href="#1-writing-efficient-sql-queries" class="hash-link" aria-label="Direct link to 1. Writing Efficient SQL Queries" title="Direct link to 1. Writing Efficient SQL Queries" translate="no"></a></h3>
<p>For writing efficient SQL queries, see our <a href="/sql#best-practices-for-performance-and-scalability">SQL Best Practices Guide</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="2-group-subscriptions-with-the-same-lifetime-together">2. Group Subscriptions with the Same Lifetime Together<a href="#2-group-subscriptions-with-the-same-lifetime-together" class="hash-link" aria-label="Direct link to 2. Group Subscriptions with the Same Lifetime Together" title="Direct link to 2. Group Subscriptions with the Same Lifetime Together" translate="no"></a></h3>
<p>Subscriptions with the same lifetime should be grouped together.</p>
<p>For example, you may have certain data that is required for the lifetime of your application,
but you may have other data that is only sometimes required by your application.</p>
<p>By managing these sets as two independent subscriptions,
your application can subscribe and unsubscribe from the latter,
without needlessly unsubscribing and resubscribing to the former.</p>
<p>This will improve throughput by reducing the amount of data transferred from the database to your application.</p>
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="example">Example<a href="#example" class="hash-link" aria-label="Direct link to Example" title="Direct link to Example" translate="no"></a></h4>
<div class="theme-tabs-container tabs-container tabList_MbSD"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_Ssy3 tabs__item--active">Rust</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_Ssy3">C#</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_sydm"><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> conn</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> DbConnection</span><span style="color:#FF79C6"> =</span><span style="color:#50FA7B"> connect_to_db</span><span style="color:#F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// Never need to unsubscribe from global subscriptions</span></span>
<span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> global_subscriptions </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscription_builder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscribe</span><span style="color:#F8F8F2">([</span></span>
<span class="line"><span style="color:#6272A4"> // Global messages the client should always display</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM announcements&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#6272A4"> // A description of rewards for in-game achievements</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM badges&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> ]);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// May unsubscribe to shop_items as player advances</span></span>
<span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> shop_subscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscription_builder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscribe</span><span style="color:#F8F8F2">([</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM shop_items WHERE required_level &lt;= 5&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> ]);</span></span></code></pre></div><div role="tabpanel" class="tabItem_sydm" hidden=""><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> conn </span><span style="color:#FF79C6">=</span><span style="color:#50FA7B"> ConnectToDB</span><span style="color:#F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// Never need to unsubscribe from global subscriptions</span></span>
<span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> globalSubscriptions </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">SubscriptionBuilder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">Subscribe</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2">[] {</span></span>
<span class="line"><span style="color:#6272A4"> // Global messages the client should always display</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM announcements</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#6272A4"> // A description of rewards for in-game achievements</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM badges</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// May unsubscribe to shop_items as player advances</span></span>
<span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> shopSubscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">SubscriptionBuilder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">Subscribe</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2">[] {</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM shop_items WHERE required_level &lt;= 5</span><span style="color:#E9F284">&quot;</span></span>
<span class="line"><span style="color:#F8F8F2"> });</span></span></code></pre></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="3-subscribe-before-unsubscribing">3. Subscribe Before Unsubscribing<a href="#3-subscribe-before-unsubscribing" class="hash-link" aria-label="Direct link to 3. Subscribe Before Unsubscribing" title="Direct link to 3. Subscribe Before Unsubscribing" translate="no"></a></h3>
<p>If you want to update or modify a subscription by dropping it and subscribing to a new set,
you should subscribe to the new set before unsubscribing from the old one.</p>
<p>This is because SpacetimeDB subscriptions are zero-copy.
Subscribing to the same query more than once doesn&#x27;t incur additional processing or serialization overhead.
Likewise, if a query is subscribed to more than once,
unsubscribing from it does not result in any server processing or data serializtion.</p>
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="example-1">Example<a href="#example-1" class="hash-link" aria-label="Direct link to Example" title="Direct link to Example" translate="no"></a></h4>
<div class="theme-tabs-container tabs-container tabList_MbSD"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_Ssy3 tabs__item--active">Rust</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_Ssy3">C#</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_sydm"><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> conn</span><span style="color:#FF79C6">:</span><span style="color:#8BE9FD;font-style:italic"> DbConnection</span><span style="color:#FF79C6"> =</span><span style="color:#50FA7B"> connect_to_db</span><span style="color:#F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// Initial subscription: player at level 5.</span></span>
<span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> shop_subscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscription_builder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscribe</span><span style="color:#F8F8F2">([</span></span>
<span class="line"><span style="color:#6272A4"> // For displaying the price of shop items in the player&#x27;s currency of choice</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM exchange_rates&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM shop_items WHERE required_level &lt;= 5&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> ]);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// New subscription: player now at level 6, which overlaps with the previous query.</span></span>
<span class="line"><span style="color:#FF79C6">let</span><span style="color:#F8F8F2"> new_shop_subscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscription_builder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#FF79C6"> .</span><span style="color:#50FA7B">subscribe</span><span style="color:#F8F8F2">([</span></span>
<span class="line"><span style="color:#6272A4"> // For displaying the price of shop items in the player&#x27;s currency of choice</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM exchange_rates&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F1FA8C"> &quot;SELECT * FROM shop_items WHERE required_level &lt;= 6&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#F8F8F2"> ]);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// Unsubscribe from the old subscription once the new one is active.</span></span>
<span class="line"><span style="color:#FF79C6">if</span><span style="color:#F8F8F2"> shop_subscription</span><span style="color:#FF79C6">.</span><span style="color:#50FA7B">is_active</span><span style="color:#F8F8F2">() {</span></span>
<span class="line"><span style="color:#F8F8F2"> shop_subscription</span><span style="color:#FF79C6">.</span><span style="color:#50FA7B">unsubscribe</span><span style="color:#F8F8F2">();</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre></div><div role="tabpanel" class="tabItem_sydm" hidden=""><pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> conn </span><span style="color:#FF79C6">=</span><span style="color:#50FA7B"> ConnectToDB</span><span style="color:#F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// Initial subscription: player at level 5.</span></span>
<span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> shopSubscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">SubscriptionBuilder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">Subscribe</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2">[] {</span></span>
<span class="line"><span style="color:#6272A4"> // For displaying the price of shop items in the player&#x27;s currency of choice</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM exchange_rates</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM shop_items WHERE required_level &lt;= 5</span><span style="color:#E9F284">&quot;</span></span>
<span class="line"><span style="color:#F8F8F2"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// New subscription: player now at level 6, which overlaps with the previous query.</span></span>
<span class="line"><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> newShopSubscription </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> conn</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">SubscriptionBuilder</span><span style="color:#F8F8F2">()</span></span>
<span class="line"><span style="color:#F8F8F2"> .</span><span style="color:#50FA7B">Subscribe</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2">[] {</span></span>
<span class="line"><span style="color:#6272A4"> // For displaying the price of shop items in the player&#x27;s currency of choice</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM exchange_rates</span><span style="color:#E9F284">&quot;</span><span style="color:#F8F8F2">,</span></span>
<span class="line"><span style="color:#E9F284"> &quot;</span><span style="color:#F1FA8C">SELECT * FROM shop_items WHERE required_level &lt;= 6</span><span style="color:#E9F284">&quot;</span></span>
<span class="line"><span style="color:#F8F8F2"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6272A4">// Unsubscribe from the old subscription once the new one is in place.</span></span>
<span class="line"><span style="color:#FF79C6">if</span><span style="color:#F8F8F2"> (shopSubscription.IsActive)</span></span>
<span class="line"><span style="color:#F8F8F2">{</span></span>
<span class="line"><span style="color:#F8F8F2"> shopSubscription.</span><span style="color:#50FA7B">Unsubscribe</span><span style="color:#F8F8F2">();</span></span>
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="4-avoid-overlapping-queries">4. Avoid Overlapping Queries<a href="#4-avoid-overlapping-queries" class="hash-link" aria-label="Direct link to 4. Avoid Overlapping Queries" title="Direct link to 4. Avoid Overlapping Queries" translate="no"></a></h3>
<p>This refers to distinct queries that return intersecting data sets,
which can result in the server processing and serializing the same row multiple times.
While SpacetimeDB can manage this redundancy, it may lead to unnecessary inefficiencies.</p>
<p>Consider the following two queries:</p>
<pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">SELECT</span><span style="color:#FF79C6"> *</span><span style="color:#FF79C6"> FROM</span><span style="color:#F8F8F2"> User</span></span>
<span class="line"><span style="color:#FF79C6">SELECT</span><span style="color:#FF79C6"> *</span><span style="color:#FF79C6"> FROM</span><span style="color:#F8F8F2"> User </span><span style="color:#FF79C6">WHERE</span><span style="color:#F8F8F2"> id </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 5</span></span></code></pre>
<p>If <code>User.id</code> is a unique or primary key column,
the cost of subscribing to both queries is minimal.
This is because the server will use an index when processing the 2nd query,
and it will only serialize a single row for the 2nd query.</p>
<p>In contrast, consider these two queries:</p>
<pre tabindex="0" class="codeBlockStandalone_pMzE thin-scrollbar codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="line"><span style="color:#FF79C6">SELECT</span><span style="color:#FF79C6"> *</span><span style="color:#FF79C6"> FROM</span><span style="color:#F8F8F2"> User</span></span>
<span class="line"><span style="color:#FF79C6">SELECT</span><span style="color:#FF79C6"> *</span><span style="color:#FF79C6"> FROM</span><span style="color:#F8F8F2"> User </span><span style="color:#FF79C6">WHERE</span><span style="color:#F8F8F2"> id </span><span style="color:#FF79C6">!=</span><span style="color:#BD93F9"> 5</span></span></code></pre>
<p>The server must now process each row of the <code>User</code> table twice,
since the 2nd query cannot be processed using an index.
It must also serialize all but one row of the <code>User</code> table twice,
due to the significant overlap between the two queries.</p>
<p>By following these best practices, you can optimize your data replication strategy and ensure your application remains efficient and responsive.</p></div></article><nav class="docusaurus-mt-lg pagination-nav" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/docs/sql/pg-wire"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">PostgreSQL Wire Protocol (PGWire)</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/subscriptions/semantics"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Subscription Semantics</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_Ea_L thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#subscriptionbuilder" class="table-of-contents__link toc-highlight">SubscriptionBuilder</a><ul><li><a href="#example-usage" class="table-of-contents__link toc-highlight">Example Usage</a></li></ul></li><li><a href="#subscriptionhandle" class="table-of-contents__link toc-highlight">SubscriptionHandle</a><ul><li><a href="#example-usage-1" class="table-of-contents__link toc-highlight">Example Usage</a></li></ul></li><li><a href="#best-practices-for-optimizing-server-compute-and-reducing-serialization-overhead" class="table-of-contents__link toc-highlight">Best Practices for Optimizing Server Compute and Reducing Serialization Overhead</a><ul><li><a href="#1-writing-efficient-sql-queries" class="table-of-contents__link toc-highlight">1. Writing Efficient SQL Queries</a></li><li><a href="#2-group-subscriptions-with-the-same-lifetime-together" class="table-of-contents__link toc-highlight">2. Group Subscriptions with the Same Lifetime Together</a></li><li><a href="#3-subscribe-before-unsubscribing" class="table-of-contents__link toc-highlight">3. Subscribe Before Unsubscribing</a></li><li><a href="#4-avoid-overlapping-queries" class="table-of-contents__link toc-highlight">4. Avoid Overlapping Queries</a></li></ul></li></ul></div></div></div></div></main></div></div></div><footer class="theme-layout-footer footer"><div class="container container-fluid"></div></footer></div>
</body>
</html>