mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-05-16 20:57:48 -04:00
941 lines
215 KiB
HTML
941 lines
215 KiB
HTML
<!doctype html>
|
||
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-Server Module Languages/CSharp-Reference" data-has-hydrated="false">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="generator" content="Docusaurus v3.9.1">
|
||
<title data-rh="true">C# 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/modules/c-sharp"><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="C# Reference | SpacetimeDB docs"><meta data-rh="true" name="description" content="Module Library"><meta data-rh="true" property="og:description" content="Module Library"><link data-rh="true" rel="icon" href="/images/favicon.ico"><link data-rh="true" rel="canonical" href="https://docs.spacetimedb.com/modules/c-sharp"><link data-rh="true" rel="alternate" href="https://docs.spacetimedb.com/modules/c-sharp" hreflang="en"><link data-rh="true" rel="alternate" href="https://docs.spacetimedb.com/modules/c-sharp" 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":"C# Reference","item":"https://docs.spacetimedb.com/modules/c-sharp"}]}</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"><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="/modules"><span title="Server Module Languages" class="categoryLinkLabel_EDYQ">Server Module Languages</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" tabindex="0" href="/modules"><span title="Overview" class="linkLabel_dpMB">Overview</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="/modules/rust/quickstart"><span title="Rust Quickstart" class="linkLabel_dpMB">Rust Quickstart</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="/modules/rust"><span title="Rust Reference" class="linkLabel_dpMB">Rust 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="/modules/c-sharp/quickstart"><span title="C# Quickstart" class="linkLabel_dpMB">C# Quickstart</span></a></li><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="/modules/c-sharp"><span title="C# Reference" class="linkLabel_dpMB">C# Reference</span></a></li></ul></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 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="/subscriptions"><span title="Subscriptions" class="categoryLinkLabel_EDYQ">Subscriptions</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="/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">Server Module Languages</span></li><li class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link">C# 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>C# Module Library</h1></header>
|
||
<p><a href="https://spacetimedb.com/" target="_blank" rel="noopener noreferrer">SpacetimeDB</a> allows using the C# language to write server-side applications called <strong>modules</strong>. Modules, which run inside a relational database, have direct access to database tables, and expose public functions called <strong>reducers</strong> that can be invoked over the network. Clients connect directly to the database to read data.</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> Client Application SpacetimeDB</span></span>
|
||
<span class="line"><span>┌───────────────────────┐ ┌───────────────────────┐</span></span>
|
||
<span class="line"><span>│ │ │ │</span></span>
|
||
<span class="line"><span>│ ┌─────────────────┐ │ SQL Query │ ┌─────────────────┐ │</span></span>
|
||
<span class="line"><span>│ │ Subscribed Data │<─────────────────────│ Database │ │</span></span>
|
||
<span class="line"><span>│ └─────────────────┘ │ │ └─────────────────┘ │</span></span>
|
||
<span class="line"><span>│ │ │ │ ^ │</span></span>
|
||
<span class="line"><span>│ │ │ │ │ │</span></span>
|
||
<span class="line"><span>│ v │ │ v │</span></span>
|
||
<span class="line"><span>│ +─────────────────┐ │ call_reducer() │ ┌─────────────────┐ │</span></span>
|
||
<span class="line"><span>│ │ Client Code │─────────────────────>│ Module Code │ │</span></span>
|
||
<span class="line"><span>│ └─────────────────┘ │ │ └─────────────────┘ │</span></span>
|
||
<span class="line"><span>│ │ │ │</span></span>
|
||
<span class="line"><span>└───────────────────────┘ └───────────────────────┘</span></span></code></pre>
|
||
<p>C# modules are written with the the C# Module Library (this package). They are built using the <a href="https://learn.microsoft.com/en-us/dotnet/core/tools/" target="_blank" rel="noopener noreferrer">dotnet CLI tool</a> and deployed using the <a href="https://spacetimedb.com/install" target="_blank" rel="noopener noreferrer"><code>spacetime</code> CLI tool</a>. C# modules can import any <a href="https://www.nuget.org/packages" target="_blank" rel="noopener noreferrer">NuGet package</a> that supports being compiled to WebAssembly.</p>
|
||
<p>(Note: C# can also be used to write <strong>clients</strong> of SpacetimeDB databases, but this requires using a different library, the SpacetimeDB C# Client SDK. See the documentation on <a href="https://spacetimedb.com/docs/#client" target="_blank" rel="noopener noreferrer">clients</a> for more information.)</p>
|
||
<p>This reference assumes you are familiar with the basics of C#. If you aren't, check out the <a href="https://learn.microsoft.com/en-us/dotnet/csharp/" target="_blank" rel="noopener noreferrer">C# language documentation</a>. For a guided introduction to C# Modules, see the <a href="https://spacetimedb.com/docs/modules/c-sharp/quickstart" target="_blank" rel="noopener noreferrer">C# Module Quickstart</a>.</p>
|
||
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="overview">Overview<a href="#overview" class="hash-link" aria-label="Direct link to Overview" title="Direct link to Overview" translate="no"></a></h2>
|
||
<p>SpacetimeDB modules have two ways to interact with the outside world: tables and reducers.</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="#tables">Tables</a> store data and optionally make it readable by <a href="https://spacetimedb.com/docs/#client" target="_blank" rel="noopener noreferrer">clients</a>.</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="#reducers">Reducers</a> are functions that modify data and can be invoked by <a href="https://spacetimedb.com/docs/#client" target="_blank" rel="noopener noreferrer">clients</a> over the network. They can read and write data in tables, and write to a private debug log.</p>
|
||
</li>
|
||
</ul>
|
||
<p>These are the only ways for a SpacetimeDB module to interact with the outside world. Calling functions from <code>System.IO</code> or <code>System.Net</code> inside a reducer will result in runtime errors.</p>
|
||
<p>Declaring tables and reducers is straightforward:</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">static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">player</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Player</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Id;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Name;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> AddPerson</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">int</span><span style="color:#FFB86C;font-style:italic"> Id</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> Name</span><span style="color:#F8F8F2">) {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> ctx.Db.player.</span><span style="color:#50FA7B">Insert</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#8BE9FD;font-style:italic"> Player</span><span style="color:#F8F8F2"> { Id </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> Id, Name </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> Name });</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Note that reducers don't return data directly; they can only modify the database. Clients connect directly to the database and use SQL to query <a href="#public-and-private-tables">public</a> tables. Clients can also subscribe to a set of rows using SQL queries and receive streaming updates whenever any of those rows change.</p>
|
||
<p>Tables and reducers in C# modules can use any type annotated with <a href="#attribute-spacetimedbtype"><code>[SpacetimeDB.Type]</code></a>.</p>
|
||
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="setup">Setup<a href="#setup" class="hash-link" aria-label="Direct link to Setup" title="Direct link to Setup" translate="no"></a></h2>
|
||
<p>To create a C# module, install the <a href="https://spacetimedb.com/install" target="_blank" rel="noopener noreferrer"><code>spacetime</code> CLI tool</a> in your preferred shell. Navigate to your work directory and run the following command:</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:#50FA7B">spacetime</span><span style="color:#F1FA8C"> init</span><span style="color:#BD93F9"> --lang</span><span style="color:#F1FA8C"> csharp</span><span style="color:#F1FA8C"> my-project-directory</span></span></code></pre>
|
||
<p>This creates a <code>dotnet</code> project in <code>my-project-directory</code> with the following <code>StdbModule.csproj</code>:</p>
|
||
<div class="language-xml codeBlockContainer_HZVP theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_p1l2"><pre tabindex="0" class="prism-code language-xml codeBlock_qbrE thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_ckKi"><span class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)"><</span><span class="token tag" style="color:rgb(255, 85, 114)">Project</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">Sdk</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">Microsoft.NET.Sdk</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"><</span><span class="token tag" style="color:rgb(255, 85, 114)">PropertyGroup</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"><</span><span class="token tag" style="color:rgb(255, 85, 114)">TargetFramework</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain">net8.0</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"></</span><span class="token tag" style="color:rgb(255, 85, 114)">TargetFramework</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"><</span><span class="token tag" style="color:rgb(255, 85, 114)">RuntimeIdentifier</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain">wasi-wasm</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"></</span><span class="token tag" style="color:rgb(255, 85, 114)">RuntimeIdentifier</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"><</span><span class="token tag" style="color:rgb(255, 85, 114)">ImplicitUsings</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain">enable</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"></</span><span class="token tag" style="color:rgb(255, 85, 114)">ImplicitUsings</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"><</span><span class="token tag" style="color:rgb(255, 85, 114)">Nullable</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain">enable</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"></</span><span class="token tag" style="color:rgb(255, 85, 114)">Nullable</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"></</span><span class="token tag" style="color:rgb(255, 85, 114)">PropertyGroup</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"><</span><span class="token tag" style="color:rgb(255, 85, 114)">ItemGroup</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"><</span><span class="token tag" style="color:rgb(255, 85, 114)">PackageReference</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">Include</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">SpacetimeDB.Runtime</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">Version</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">1.0.0</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"></</span><span class="token tag" style="color:rgb(255, 85, 114)">ItemGroup</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)"></</span><span class="token tag" style="color:rgb(255, 85, 114)">Project</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">></span><br></span></code></pre></div></div>
|
||
<div class="theme-admonition theme-admonition-note admonition_scYj alert alert--secondary"><div class="admonitionHeading_zhQc"><span class="admonitionIcon_kfZz"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_O7JJ"><p>It is important to not change the <code>StdbModule.csproj</code> name because SpacetimeDB assumes that this will be the name of the file.</p></div></div>
|
||
<p>This is a standard <code>csproj</code>, with the exception of the line <code><RuntimeIdentifier>wasi-wasm</RuntimeIdentifier></code>.
|
||
This line is important: it allows the project to be compiled to a WebAssembly module.</p>
|
||
<p>The project's <code>Lib.cs</code> will contain the following skeleton:</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">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Person</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">AutoInc</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">PrimaryKey</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Id;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Name;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Age;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Add</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> name</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">int</span><span style="color:#FFB86C;font-style:italic"> age</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> person </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> ctx.Db.Person.</span><span style="color:#50FA7B">Insert</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#8BE9FD;font-style:italic"> Person</span><span style="color:#F8F8F2"> { Name </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> name, Age </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> age });</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Info</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">$"</span><span style="color:#F1FA8C">Inserted </span><span style="color:#FF79C6">{</span><span style="color:#F8F8F2">person</span><span style="color:#F1FA8C">.</span><span style="color:#F8F8F2">Name</span><span style="color:#FF79C6">}</span><span style="color:#F1FA8C"> under #</span><span style="color:#FF79C6">{</span><span style="color:#F8F8F2">person</span><span style="color:#F1FA8C">.</span><span style="color:#F8F8F2">Id</span><span style="color:#FF79C6">}</span><span style="color:#E9F284">"</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:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> SayHello</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> foreach</span><span style="color:#F8F8F2"> (</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> person </span><span style="color:#FF79C6">in</span><span style="color:#F8F8F2"> ctx.Db.Person.</span><span style="color:#50FA7B">Iter</span><span style="color:#F8F8F2">())</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Info</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">$"</span><span style="color:#F1FA8C">Hello, </span><span style="color:#FF79C6">{</span><span style="color:#F8F8F2">person</span><span style="color:#F1FA8C">.</span><span style="color:#F8F8F2">Name</span><span style="color:#FF79C6">}</span><span style="color:#F1FA8C">!</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Info</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">Hello, World!</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>This skeleton declares a <a href="#tables">table</a> and some <a href="#reducers">reducers</a>.</p>
|
||
<p>You can also add some <a href="#lifecycle-reducers">lifecycle reducers</a> to the <code>Module</code> class using the following code:</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">(ReducerKind.Init)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Init</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Run when the module is first loaded.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">(ReducerKind.ClientConnected)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> ClientConnected</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Called when a client connects.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">(ReducerKind.ClientDisconnected)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> ClientDisconnected</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Called when a client connects.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>To compile the project, run the following command:</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:#50FA7B">spacetime</span><span style="color:#F1FA8C"> build</span></span></code></pre>
|
||
<p>SpacetimeDB requires a WebAssembly-compatible <code>dotnet</code> toolchain. If the <code>spacetime</code> cli finds a compatible version of <a href="https://rustup.rs/" target="_blank" rel="noopener noreferrer"><code>dotnet</code></a> that it can run, it will automatically install the <code>wasi-experimental</code> workload and use it to build your application. This can also be done manually using the command:</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:#50FA7B">dotnet</span><span style="color:#F1FA8C"> workload</span><span style="color:#F1FA8C"> install</span><span style="color:#F1FA8C"> wasi-experimental</span></span></code></pre>
|
||
<p>If you are managing your dotnet installation in some other way, you will need to install the <code>wasi-experimental</code> workload yourself.</p>
|
||
<p>To build your application and upload it to the public SpacetimeDB network, run:</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:#50FA7B">spacetime</span><span style="color:#F1FA8C"> login</span></span></code></pre>
|
||
<p>And then:</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:#50FA7B">spacetime</span><span style="color:#F1FA8C"> publish</span><span style="color:#F8F8F2"> [MY_DATABASE_NAME]</span></span></code></pre>
|
||
<p>For example:</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:#50FA7B">spacetime</span><span style="color:#F1FA8C"> publish</span><span style="color:#F1FA8C"> silly_demo_app</span></span></code></pre>
|
||
<p>When you publish your module, a database named <code>silly_demo_app</code> will be created with the requested tables, and the module will be installed inside it.</p>
|
||
<p>The output of <code>spacetime publish</code> will end with a line:</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>Created new database with name: <name>, identity: <hex string></span></span></code></pre>
|
||
<p>This name is the human-readable name of the created database, and the hex string is its <a href="#struct-identity"><code>Identity</code></a>. These distinguish the created database from the other databases running on the SpacetimeDB network. They are used when administering the application, for example using the <a href="#class-log"><code>spacetime logs <DATABASE_NAME></code></a> command. You should probably write the database name down in a text file so that you can remember it.</p>
|
||
<p>After modifying your project, you can run:</p>
|
||
<p><code>spacetime publish <DATABASE_NAME></code></p>
|
||
<p>to update the module attached to your database. Note that SpacetimeDB tries to <a href="#automatic-migrations">automatically migrate</a> your database schema whenever you run <code>spacetime publish</code>.</p>
|
||
<p>You can also generate code for clients of your module using the <code>spacetime generate</code> command. See the <a href="https://spacetimedb.com/docs/#client" target="_blank" rel="noopener noreferrer">client SDK documentation</a> for more information.</p>
|
||
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="how-it-works">How it works<a href="#how-it-works" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no"></a></h2>
|
||
<p>Under the hood, SpacetimeDB modules are WebAssembly modules that import a <a href="https://spacetimedb.com/docs/webassembly-abi" target="_blank" rel="noopener noreferrer">specific WebAssembly ABI</a> and export a small number of special functions. This is automatically configured when you add the <code>SpacetimeDB.Runtime</code> package as a dependency of your application.</p>
|
||
<p>The SpacetimeDB host is an application that hosts SpacetimeDB databases. <a href="https://github.com/clockworklabs/SpacetimeDB" target="_blank" rel="noopener noreferrer">Its source code is available</a> under <a href="https://github.com/clockworklabs/SpacetimeDB/blob/master/LICENSE.txt" target="_blank" rel="noopener noreferrer">the Business Source License with an Additional Use Grant</a>. You can run your own host, or you can upload your module to the public SpacetimeDB network. The network will create a database for you and install your module in it to serve client requests.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="in-more-detail-publishing-a-module">In More Detail: Publishing a Module<a href="#in-more-detail-publishing-a-module" class="hash-link" aria-label="Direct link to In More Detail: Publishing a Module" title="Direct link to In More Detail: Publishing a Module" translate="no"></a></h3>
|
||
<p>The <code>spacetime publish [DATABASE_IDENTITY]</code> command compiles a module and uploads it to a SpacetimeDB host. After this:</p>
|
||
<ul>
|
||
<li>The host finds the database with the requested <code>DATABASE_IDENTITY</code>.<!-- -->
|
||
<ul>
|
||
<li>(Or creates a fresh database and identity, if no identity was provided).</li>
|
||
</ul>
|
||
</li>
|
||
<li>The host loads the new module and inspects its requested database schema. If there are changes to the schema, the host tries perform an <a href="#automatic-migrations">automatic migration</a>. If the migration fails, publishing fails.</li>
|
||
<li>The host terminates the old module attached to the database.</li>
|
||
<li>The host installs the new module into the database. It begins running the module's <a href="#lifecycle-reducers">lifecycle reducers</a> and <a href="#scheduled-reducers">scheduled reducers</a>, starting with the <code>Init</code> reducer.</li>
|
||
<li>The host begins allowing clients to call the module's reducers.</li>
|
||
</ul>
|
||
<p>From the perspective of clients, this process is seamless. Open connections are maintained and subscriptions continue functioning. <a href="#automatic-migrations">Automatic migrations</a> forbid most table changes except for adding new tables, so client code does not need to be recompiled.
|
||
However:</p>
|
||
<ul>
|
||
<li>Clients may witness a brief interruption in the execution of scheduled reducers (for example, game loops.)</li>
|
||
<li>New versions of a module may remove or change reducers that were previously present. Client code calling those reducers will receive runtime errors.</li>
|
||
</ul>
|
||
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="tables">Tables<a href="#tables" class="hash-link" aria-label="Direct link to Tables" title="Direct link to Tables" translate="no"></a></h2>
|
||
<p>Tables are declared using the <code>[SpacetimeDB.Table]</code> attribute.</p>
|
||
<p>This macro is applied to a C# <code>partial class</code> or <code>partial struct</code> with named fields. (The <code>partial</code> modifier is required to allow code generation to add methods.) All of the fields of the table must be marked with <a href="#attribute-spacetimedbtype"><code>[SpacetimeDB.Type]</code></a>.</p>
|
||
<p>The resulting type is used to store rows of the table. It's a normal class (or struct). Row values are not special -- operations on row types do not, by themselves, modify the table. Instead, a <a href="#class-reducercontext"><code>ReducerContext</code></a> is needed to get a handle to the table.</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">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2"><</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">></span></span>
|
||
<span class="line"><span style="color:#6272A4"> /// A Person is a row of the table person.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> /// </span><span style="color:#F8F8F2"></</span><span style="color:#FF79C6">summary</span><span style="color:#F8F8F2">></span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">person</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, Public)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Person</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">PrimaryKey</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">AutoInc</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> ulong</span><span style="color:#F8F8F2"> Id;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Index</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">BTree</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Name;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> // `Person` is a normal C# struct type.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Operations on a `Person` do not, by themselves, do anything.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // The following function does not interact with the database at all.</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> DoNothing</span><span style="color:#F8F8F2">() {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Creating a `Person` DOES NOT modify the database.</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> person </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> Person</span><span style="color:#F8F8F2"> { Id </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2">, Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">Joe Average</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2"> };</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Updating a `Person` DOES NOT modify the database.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> person.Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">Joanna Average</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Deallocating a `Person` DOES NOT modify the database.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> person </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> null</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"> // To interact with the database, you need a `ReducerContext`,</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // which is provided as the first parameter of any reducer.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> DoSomething</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">) {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // The following inserts a row into the table:</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> examplePerson </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> ctx.Db.person.</span><span style="color:#50FA7B">Insert</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#8BE9FD;font-style:italic"> Person</span><span style="color:#F8F8F2"> { id </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2">, name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">Joe Average</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2"> });</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> // `examplePerson` is a COPY of the row stored in the database.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // If we update it:</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> examplePerson.name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">Joanna Average</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">.</span><span style="color:#50FA7B">to_string</span><span style="color:#F8F8F2">();</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Our copy is now updated, but the database's copy is UNCHANGED.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // To push our change through, we can call `UniqueIndex.Update()`:</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> examplePerson </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> ctx.Db.person.Id.</span><span style="color:#50FA7B">Update</span><span style="color:#F8F8F2">(examplePerson);</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Now the database and our copy are in sync again.</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> // We can also delete the row in the database using `UniqueIndex.Delete()`.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> ctx.Db.person.Id.</span><span style="color:#50FA7B">Delete</span><span style="color:#F8F8F2">(examplePerson.Id);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>(See <a href="#reducers">reducers</a> for more information on declaring reducers.)</p>
|
||
<p>This library generates a custom API for each table, depending on the table's name and structure.</p>
|
||
<p>All tables support getting a handle implementing the <a href="#interface-itableview"><code>ITableView</code></a> interface from a <a href="#class-reducercontext"><code>ReducerContext</code></a>, using:</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>ctx.Db.{table_name}</span></span></code></pre>
|
||
<p>For example,</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:#F8F8F2">ctx.Db.person</span></span></code></pre>
|
||
<p><a href="#unique-and-primary-key-columns">Unique and primary key columns</a> and <a href="#indexes">indexes</a> generate additional accessors, such as <code>ctx.Db.person.Id</code> and <code>ctx.Db.person.Name</code>.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="interface-itableview">Interface <code>ITableView</code><a href="#interface-itableview" class="hash-link" aria-label="Direct link to interface-itableview" title="Direct link to interface-itableview" translate="no"></a></h3>
|
||
<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">namespace</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Internal</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> interface</span><span style="color:#8BE9FD;font-style:italic"> ITableView</span><span style="color:#F8F8F2"><</span><span style="color:#FFB86C;font-style:italic">View</span><span style="color:#F8F8F2">, </span><span style="color:#FFB86C;font-style:italic">Row</span><span style="color:#F8F8F2">></span></span>
|
||
<span class="line"><span style="color:#FF79C6"> where</span><span style="color:#FFB86C;font-style:italic"> Row</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">IStructuralReadWrite</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">new</span><span style="color:#F8F8F2">()</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#6272A4"> /* ... */</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Implemented for every table handle generated by the <a href="#tables"><code>Table</code></a> attribute.
|
||
For a table named <code>{name}</code>, a handle can be extracted from a <a href="#class-reducercontext"><code>ReducerContext</code></a> using <code>ctx.Db.{name}</code>. For example, <code>ctx.Db.person</code>.</p>
|
||
<p>Contains methods that are present for every table handle, regardless of what unique constraints
|
||
and indexes are present.</p>
|
||
<p>The type <code>Row</code> is the type of rows in the table.</p>
|
||
<table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td><a href="#method-itableviewinsert">Method <code>Insert</code></a></td><td>Insert a row into the table</td></tr><tr><td><a href="#method-itableviewdelete">Method <code>Delete</code></a></td><td>Delete a row from the table</td></tr><tr><td><a href="#method-itableviewiter">Method <code>Iter</code></a></td><td>Iterate all rows of the table</td></tr><tr><td><a href="#property-itableviewcount">Property <code>Count</code></a></td><td>Count all rows of the table</td></tr></tbody></table>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-itableviewinsert">Method <code>ITableView.Insert</code><a href="#method-itableviewinsert" class="hash-link" aria-label="Direct link to method-itableviewinsert" title="Direct link to method-itableviewinsert" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">Row</span><span style="color:#50FA7B"> Insert</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#FFB86C;font-style:italic"> row</span><span style="color:#F8F8F2">);</span></span></code></pre>
|
||
<p>Inserts <code>row</code> into the table.</p>
|
||
<p>The return value is the inserted row, with any auto-incrementing columns replaced with computed values.
|
||
The <code>insert</code> method always returns the inserted row, even when the table contains no auto-incrementing columns.</p>
|
||
<p>(The returned row is a copy of the row in the database.
|
||
Modifying this copy does not directly modify the database.
|
||
See <a href="#method-uniqueindexupdate"><code>UniqueIndex.Update()</code></a> if you want to update the row.)</p>
|
||
<p>Throws an exception if inserting the row violates any constraints.</p>
|
||
<p>Inserting a duplicate row in a table is a no-op,
|
||
as SpacetimeDB is a set-semantic database.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-itableviewdelete">Method <code>ITableView.Delete</code><a href="#method-itableviewdelete" class="hash-link" aria-label="Direct link to method-itableviewdelete" title="Direct link to method-itableviewdelete" translate="no"></a></h4>
|
||
<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">bool</span><span style="color:#50FA7B"> Delete</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#FFB86C;font-style:italic"> row</span><span style="color:#F8F8F2">);</span></span></code></pre>
|
||
<p>Deletes a row equal to <code>row</code> from the table.</p>
|
||
<p>Returns <code>true</code> if the row was present and has been deleted,
|
||
or <code>false</code> if the row was not present and therefore the tables have not changed.</p>
|
||
<p>Unlike <a href="#method-itableviewinsert"><code>Insert</code></a>, there is no need to return the deleted row,
|
||
as it must necessarily have been exactly equal to the <code>row</code> argument.
|
||
No analogue to auto-increment placeholders exists for deletions.</p>
|
||
<p>Throws an exception if deleting the row would violate any constraints.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-itableviewiter">Method <code>ITableView.Iter</code><a href="#method-itableviewiter" class="hash-link" aria-label="Direct link to method-itableviewiter" title="Direct link to method-itableviewiter" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">IEnumerable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">> </span><span style="color:#50FA7B">Iter</span><span style="color:#F8F8F2">();</span></span></code></pre>
|
||
<p>Iterate over all rows of the table.</p>
|
||
<p>(This keeps track of changes made to the table since the start of this reducer invocation. For example, if rows have been <a href="#method-itableviewdelete">deleted</a> since the start of this reducer invocation, those rows will not be returned by <code>Iter</code>. Similarly, <a href="#method-itableviewinsert">inserted</a> rows WILL be returned.)</p>
|
||
<p>For large tables, this can be a slow operation! Prefer <a href="#method-indexfilter">filtering</a> by an <a href="#class-index"><code>Index</code></a> or <a href="#method-uniqueindexfind">finding</a> a <a href="#class-uniqueindex"><code>UniqueIndex</code></a> if possible.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="property-itableviewcount">Property <code>ITableView.Count</code><a href="#property-itableviewcount" class="hash-link" aria-label="Direct link to property-itableviewcount" title="Direct link to property-itableviewcount" translate="no"></a></h4>
|
||
<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">ulong</span><span style="color:#F8F8F2"> Count { get; }</span></span></code></pre>
|
||
<p>Returns the number of rows of this table.</p>
|
||
<p>This takes into account modifications by the current transaction,
|
||
even though those modifications have not yet been committed or broadcast to clients.
|
||
This applies generally to insertions, deletions, updates, and iteration as well.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="public-and-private-tables">Public and Private Tables<a href="#public-and-private-tables" class="hash-link" aria-label="Direct link to Public and Private Tables" title="Direct link to Public and Private Tables" translate="no"></a></h3>
|
||
<p>By default, tables are considered <strong>private</strong>. This means that they are only readable by the database owner and by reducers. Reducers run inside the database, so clients cannot see private tables at all or even know of their existence.</p>
|
||
<p>Using the <code>[SpacetimeDB.Table(Name = "table_name", Public)]</code> flag makes a table public. <strong>Public</strong> tables are readable by all clients. They can still only be modified by reducers.</p>
|
||
<p>(Note that, when run by the module owner, the <code>spacetime sql <SQL_QUERY></code> command can also read private tables. This is for debugging convenience. Only the module owner can see these tables. This is determined by the <code>Identity</code> stored by the <code>spacetime login</code> command. Run <code>spacetime login show</code> to print your current logged-in <code>Identity</code>.)</p>
|
||
<p>To learn how to subscribe to a public table, see the <a href="https://spacetimedb.com/docs/sdks" target="_blank" rel="noopener noreferrer">client SDK documentation</a>.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="unique-and-primary-key-columns">Unique and Primary Key Columns<a href="#unique-and-primary-key-columns" class="hash-link" aria-label="Direct link to Unique and Primary Key Columns" title="Direct link to Unique and Primary Key Columns" translate="no"></a></h3>
|
||
<p>Columns of a table (that is, fields of a <a href="#tables"><code>[Table]</code></a> struct) can be annotated with <code>[Unique]</code> or <code>[PrimaryKey]</code>. Multiple columns can be <code>[Unique]</code>, but only one can be <code>[PrimaryKey]</code>. For example:</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">citizen</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Citizen</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">PrimaryKey</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> ulong</span><span style="color:#F8F8F2"> Id;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Unique</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Ssn;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Unique</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Email;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> name;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Every row in the table <code>Person</code> must have unique entries in the <code>id</code>, <code>ssn</code>, and <code>email</code> columns. Attempting to insert multiple <code>Person</code>s with the same <code>id</code>, <code>ssn</code>, or <code>email</code> will throw an exception.</p>
|
||
<p>Any <code>[Unique]</code> or <code>[PrimaryKey]</code> column supports getting a <a href="#class-uniqueindex"><code>UniqueIndex</code></a> from a <a href="#class-reducercontext"><code>ReducerContext</code></a> using:</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>ctx.Db.{table}.{unique_column}</span></span></code></pre>
|
||
<p>For example,</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:#F8F8F2">ctx.Db.citizen.Ssn</span></span></code></pre>
|
||
<p>Notice that updating a row is only possible if a row has a unique column -- there is no <code>update</code> method in the base <a href="#interface-itableview"><code>ITableView</code></a> interface. SpacetimeDB has no notion of rows having an "identity" aside from their unique / primary keys.</p>
|
||
<p>The <code>[PrimaryKey]</code> annotation implies a <code>[Unique]</code> annotation, but avails additional methods in the <a href="https://spacetimedb.com/docs/#client" target="_blank" rel="noopener noreferrer">client</a>-side SDKs.</p>
|
||
<p>It is not currently possible to mark a group of fields as collectively unique.</p>
|
||
<p>Filtering on unique columns is only supported for a limited number of types.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="class-uniqueindex">Class <code>UniqueIndex</code><a href="#class-uniqueindex" class="hash-link" aria-label="Direct link to class-uniqueindex" title="Direct link to class-uniqueindex" translate="no"></a></h3>
|
||
<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">namespace</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Internal</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> abstract</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> UniqueIndex</span><span style="color:#F8F8F2"><</span><span style="color:#FFB86C;font-style:italic">Handle</span><span style="color:#F8F8F2">, </span><span style="color:#FFB86C;font-style:italic">Row</span><span style="color:#F8F8F2">, </span><span style="color:#FFB86C;font-style:italic">Column</span><span style="color:#F8F8F2">, </span><span style="color:#FFB86C;font-style:italic">RW</span><span style="color:#F8F8F2">> : </span><span style="color:#8BE9FD;font-style:italic">IndexBase</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">></span></span>
|
||
<span class="line"><span style="color:#FF79C6"> where</span><span style="color:#FFB86C;font-style:italic"> Handle</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">ITableView</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Handle</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">></span></span>
|
||
<span class="line"><span style="color:#FF79C6"> where</span><span style="color:#FFB86C;font-style:italic"> Row</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">IStructuralReadWrite</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">new</span><span style="color:#F8F8F2">()</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> where</span><span style="color:#FFB86C;font-style:italic"> Column</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">IEquatable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Column</span><span style="color:#F8F8F2">></span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#6272A4"> /* ... */</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>A unique index on a column. Available for <code>[Unique]</code> and <code>[PrimaryKey]</code> columns.
|
||
(A custom class derived from <code>UniqueIndex</code> is generated for every such column.)</p>
|
||
<p><code>Row</code> is the type decorated with <code>[SpacetimeDB.Table]</code>, <code>Column</code> is the type of the column,
|
||
and <code>Handle</code> is the type of the generated table handle.</p>
|
||
<p>For a table <em>table</em> with a column <em>column</em>, use <code>ctx.Db.{table}.{column}</code>
|
||
to get a <code>UniqueColumn</code> from a <a href="#class-reducercontext"><code>ReducerContext</code></a>.</p>
|
||
<p>Example:</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">using</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">user</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> User</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">PrimaryKey</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> uint</span><span style="color:#F8F8F2"> Id;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Unique</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Username;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> ulong</span><span style="color:#F8F8F2"> DogCount;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Demo</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">) {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> idIndex </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> ctx.Db.user.Id;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> exampleUser </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> idIndex.</span><span style="color:#50FA7B">Find</span><span style="color:#F8F8F2">(</span><span style="color:#BD93F9">357</span><span style="color:#F8F8F2">).Value;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> exampleUser.DogCount </span><span style="color:#FF79C6">+=</span><span style="color:#BD93F9"> 5</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> idIndex.</span><span style="color:#50FA7B">Update</span><span style="color:#F8F8F2">(exampleUser);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> usernameIndex </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> ctx.Db.user.Username;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> usernameIndex.</span><span style="color:#50FA7B">Delete</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">Evil Bob</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td><a href="#method-uniqueindexfind">Method <code>Find</code></a></td><td>Find a row by the value of a unique column</td></tr><tr><td><a href="#method-uniqueindexupdate">Method <code>Update</code></a></td><td>Update a row with a unique column</td></tr><tr><td><a href="#method-uniqueindexdelete">Method <code>Delete</code></a></td><td>Delete a row by the value of a unique column</td></tr></tbody></table>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-uniqueindexfind">Method <code>UniqueIndex.Find</code><a href="#method-uniqueindexfind" class="hash-link" aria-label="Direct link to method-uniqueindexfind" title="Direct link to method-uniqueindexfind" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">? </span><span style="color:#50FA7B">Find</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Column</span><span style="color:#FFB86C;font-style:italic"> key</span><span style="color:#F8F8F2">);</span></span></code></pre>
|
||
<p>Finds and returns the row where the value in the unique column matches the supplied <code>key</code>,
|
||
or <code>null</code> if no such row is present in the database state.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-uniqueindexupdate">Method <code>UniqueIndex.Update</code><a href="#method-uniqueindexupdate" class="hash-link" aria-label="Direct link to method-uniqueindexupdate" title="Direct link to method-uniqueindexupdate" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">Row</span><span style="color:#50FA7B"> Update</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#FFB86C;font-style:italic"> row</span><span style="color:#F8F8F2">);</span></span></code></pre>
|
||
<p>Deletes the row where the value in the unique column matches that in the corresponding field of <code>row</code> and then inserts <code>row</code>.</p>
|
||
<p>Returns the new row as actually inserted, with any auto-inc placeholders substituted for computed values.</p>
|
||
<p>Throws if no row was previously present with the matching value in the unique column,
|
||
or if either the delete or the insertion would violate a constraint.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-uniqueindexdelete">Method <code>UniqueIndex.Delete</code><a href="#method-uniqueindexdelete" class="hash-link" aria-label="Direct link to method-uniqueindexdelete" title="Direct link to method-uniqueindexdelete" translate="no"></a></h4>
|
||
<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">bool</span><span style="color:#50FA7B"> Delete</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Column</span><span style="color:#FFB86C;font-style:italic"> key</span><span style="color:#F8F8F2">);</span></span></code></pre>
|
||
<p>Deletes the row where the value in the unique column matches the supplied <code>key</code>, if any such row is present in the database state.</p>
|
||
<p>Returns <code>true</code> if a row with the specified <code>key</code> was previously present and has been deleted,
|
||
or <code>false</code> if no such row was present.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="auto-inc-columns">Auto-inc columns<a href="#auto-inc-columns" class="hash-link" aria-label="Direct link to Auto-inc columns" title="Direct link to Auto-inc columns" translate="no"></a></h3>
|
||
<p>Columns can be marked <code>[SpacetimeDB.AutoInc]</code>. This can only be used on integer types (<code>int</code>, <code>ulong</code>, etc.)</p>
|
||
<p>When inserting into or updating a row in a table with an <code>[AutoInc]</code> column, if the annotated column is set to zero (<code>0</code>), the database will automatically overwrite that zero with an atomically increasing value.</p>
|
||
<p>[<code>ITableView.Insert</code>] and <a href="#method-uniqueindexupdate"><code>UniqueIndex.Update()</code></a> returns rows with <code>[AutoInc]</code> columns set to the values that were actually written into the database.</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">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">example</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Example</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">AutoInc</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Field;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> InsertAutoIncExample</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">int</span><span style="color:#FFB86C;font-style:italic"> Id</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> Name</span><span style="color:#F8F8F2">) {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> for</span><span style="color:#F8F8F2"> (</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> i </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2">; i </span><span style="color:#FF79C6"><</span><span style="color:#BD93F9"> 10</span><span style="color:#F8F8F2">; i</span><span style="color:#FF79C6">++</span><span style="color:#F8F8F2">) {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // These will have distinct, unique values</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // at rest in the database, since they</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // are inserted with the sentinel value 0.</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> actual </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> ctx.Db.example.</span><span style="color:#50FA7B">Insert</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#8BE9FD;font-style:italic"> Example</span><span style="color:#F8F8F2"> { Field </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2"> });</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Debug.</span><span style="color:#50FA7B">Assert</span><span style="color:#F8F8F2">(actual.Field </span><span style="color:#FF79C6">!=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p><code>[AutoInc]</code> is often combined with <code>[Unique]</code> or <code>[PrimaryKey]</code> to automatically assign unique integer identifiers to rows.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="indexes">Indexes<a href="#indexes" class="hash-link" aria-label="Direct link to Indexes" title="Direct link to Indexes" translate="no"></a></h3>
|
||
<p>SpacetimeDB supports both single- and multi-column <a href="https://en.wikipedia.org/wiki/B-tree" target="_blank" rel="noopener noreferrer">B-Tree</a> indexes.</p>
|
||
<p>Indexes are declared using the syntax:</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Index</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">BTree</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">IndexName</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, Columns </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> [</span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Column1), </span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Column2), </span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Column3)])]</span></span></code></pre>
|
||
<p>For example:</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">paper</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)]</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Index</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">BTree</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">TitleAndDate</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, Columns </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> [</span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Title), </span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Date)])]</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Index</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">BTree</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">UrlAndCountry</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, Columns </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> [</span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Url), </span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Country)])]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> AcademicPaper</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Title;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Url;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Date;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Venue;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Country;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Multiple indexes can be declared.</p>
|
||
<p>Single-column indexes can also be declared using an annotation on a column:</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">academic_paper</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> AcademicPaper</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Title;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Url;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Index</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">BTree</span><span style="color:#F8F8F2">] </span><span style="color:#6272A4">// The index will be named "Date".</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Date;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Index</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">BTree</span><span style="color:#F8F8F2">] </span><span style="color:#6272A4">// The index will be named "Venue".</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Venue;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Index</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">BTree</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">ByCountry</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)] </span><span style="color:#6272A4">// The index will be named "ByCountry".</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Country;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Any table supports getting an <a href="#class-index"><code>Index</code></a> using <code>ctx.Db.{table}.{index}</code>. For example, <code>ctx.Db.academic_paper.TitleAndDate</code> or <code>ctx.Db.academic_paper.Venue</code>.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="indexable-types">Indexable Types<a href="#indexable-types" class="hash-link" aria-label="Direct link to Indexable Types" title="Direct link to Indexable Types" translate="no"></a></h3>
|
||
<p>SpacetimeDB supports only a restricted set of types as index keys:</p>
|
||
<ul>
|
||
<li>Signed and unsigned integers of various widths.</li>
|
||
<li><code>bool</code>.</li>
|
||
<li><code>string</code>.</li>
|
||
<li><a href="#struct-identity"><code>Identity</code></a>.</li>
|
||
<li><a href="#struct-connectionid"><code>ConnectionId</code></a>.</li>
|
||
<li><code>enum</code>s annotated with <a href="#attribute-spacetimedbtype"><code>SpacetimeDB.Type</code></a>.</li>
|
||
</ul>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="class-index">Class <code>Index</code><a href="#class-index" class="hash-link" aria-label="Direct link to class-index" title="Direct link to class-index" translate="no"></a></h3>
|
||
<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"> abstract</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> IndexBase</span><span style="color:#F8F8F2"><</span><span style="color:#FFB86C;font-style:italic">Row</span><span style="color:#F8F8F2">></span></span>
|
||
<span class="line"><span style="color:#FF79C6"> where</span><span style="color:#FFB86C;font-style:italic"> Row</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">IStructuralReadWrite</span><span style="color:#F8F8F2">, </span><span style="color:#FF79C6">new</span><span style="color:#F8F8F2">()</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // ...</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Each index generates a subclass of <code>IndexBase</code>, which is accessible via <code>ctx.Db.{table}.{index}</code>. For example, <code>ctx.Db.academic_paper.TitleAndDate</code>.</p>
|
||
<p>Indexes can be applied to a variable number of columns, referred to as <code>Column1</code>, <code>Column2</code>, <code>Column3</code>... in the following examples.</p>
|
||
<table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td>Method <a href="#method-indexfilter"><code>Filter</code></a></td><td>Filter rows in an index</td></tr><tr><td>Method <a href="#method-indexdelete"><code>Delete</code></a></td><td>Delete rows in an index</td></tr></tbody></table>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-indexfilter">Method <code>Index.Filter</code><a href="#method-indexfilter" class="hash-link" aria-label="Direct link to method-indexfilter" title="Direct link to method-indexfilter" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic"> IEnumerable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">> </span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#FFB86C;font-style:italic"> bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#8BE9FD;font-style:italic"> IEnumerable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">> </span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Bound</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">> </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#8BE9FD;font-style:italic"> IEnumerable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">> </span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">((</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Column2</span><span style="color:#F8F8F2">) </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#8BE9FD;font-style:italic"> IEnumerable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">> </span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">((</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Bound</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Column2</span><span style="color:#F8F8F2">>) </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#8BE9FD;font-style:italic"> IEnumerable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">> </span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">((</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Column2</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Column3</span><span style="color:#F8F8F2">) </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#8BE9FD;font-style:italic"> IEnumerable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Row</span><span style="color:#F8F8F2">> </span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">((</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Column2</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Bound</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Column3</span><span style="color:#F8F8F2">>) </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#6272A4">// ...</span></span></code></pre>
|
||
<p>Returns an iterator over all rows in the database state where the indexed column(s) match the passed <code>bound</code>. Bound is a tuple of column values, possibly terminated by a <code>Bound<LastColumn></code>. A <code>Bound<LastColumn></code> is simply a tuple <code>(LastColumn Min, LastColumn Max)</code>. Any prefix of the indexed columns can be passed, for example:</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">using</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">zoo_animal</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)]</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Index</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">BTree</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">SpeciesAgeName</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, Columns </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> [</span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Species), </span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Age), </span><span style="color:#FF79C6">nameof</span><span style="color:#F8F8F2">(Name)])]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> ZooAnimal</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Species;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> uint</span><span style="color:#F8F8F2"> Age;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Name;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">PrimaryKey</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> uint</span><span style="color:#F8F8F2"> Id;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Example</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> foreach</span><span style="color:#F8F8F2"> (</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> baboon </span><span style="color:#FF79C6">in</span><span style="color:#F8F8F2"> ctx.Db.zoo_animal.SpeciesAgeName.</span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">baboon</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">))</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Work with the baboon.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> foreach</span><span style="color:#F8F8F2"> (</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> animal </span><span style="color:#FF79C6">in</span><span style="color:#F8F8F2"> ctx.Db.zoo_animal.SpeciesAgeName.</span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">((</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">b</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, </span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">e</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)))</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Work with the animal.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // The name of the species starts with a character between "b" and "e".</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> foreach</span><span style="color:#F8F8F2"> (</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> babyBaboon </span><span style="color:#FF79C6">in</span><span style="color:#F8F8F2"> ctx.Db.zoo_animal.SpeciesAgeName.</span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">((</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">baboon</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, </span><span style="color:#BD93F9">1</span><span style="color:#F8F8F2">)))</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Work with the baby baboon.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> foreach</span><span style="color:#F8F8F2"> (</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> youngBaboon </span><span style="color:#FF79C6">in</span><span style="color:#F8F8F2"> ctx.Db.zoo_animal.SpeciesAgeName.</span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">((</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">baboon</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, (</span><span style="color:#BD93F9">1</span><span style="color:#F8F8F2">, </span><span style="color:#BD93F9">5</span><span style="color:#F8F8F2">))))</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Work with the young baboon.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> foreach</span><span style="color:#F8F8F2"> (</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> babyBaboonNamedBob </span><span style="color:#FF79C6">in</span><span style="color:#F8F8F2"> ctx.Db.zoo_animal.SpeciesAgeName.</span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">((</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">baboon</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, </span><span style="color:#BD93F9">1</span><span style="color:#F8F8F2">, </span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">Bob</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)))</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Work with the baby baboon named "Bob".</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> foreach</span><span style="color:#F8F8F2"> (</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> babyBaboon </span><span style="color:#FF79C6">in</span><span style="color:#F8F8F2"> ctx.Db.zoo_animal.SpeciesAgeName.</span><span style="color:#50FA7B">Filter</span><span style="color:#F8F8F2">((</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">baboon</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, </span><span style="color:#BD93F9">1</span><span style="color:#F8F8F2">, (</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">a</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, </span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">f</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">))))</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // Work with the baby baboon, whose name starts with a letter between "a" and "f".</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-indexdelete">Method <code>Index.Delete</code><a href="#method-indexdelete" class="hash-link" aria-label="Direct link to method-indexdelete" title="Direct link to method-indexdelete" translate="no"></a></h4>
|
||
<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"> ulong</span><span style="color:#50FA7B"> Delete</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#FFB86C;font-style:italic"> bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> ulong</span><span style="color:#50FA7B"> Delete</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Bound</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">> </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> ulong</span><span style="color:#50FA7B"> Delete</span><span style="color:#F8F8F2">((</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Column2</span><span style="color:#F8F8F2">) </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> ulong</span><span style="color:#50FA7B"> Delete</span><span style="color:#F8F8F2">((</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Bound</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Column2</span><span style="color:#F8F8F2">>) </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> ulong</span><span style="color:#50FA7B"> Delete</span><span style="color:#F8F8F2">((</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Column2</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Column3</span><span style="color:#F8F8F2">) </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> ulong</span><span style="color:#50FA7B"> Delete</span><span style="color:#F8F8F2">((</span><span style="color:#8BE9FD;font-style:italic">Column1</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Column2</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Bound</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Column3</span><span style="color:#F8F8F2">>) </span><span style="color:#FFB86C;font-style:italic">bound</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#6272A4">// ...</span></span></code></pre>
|
||
<p>Delete all rows in the database state where the indexed column(s) match the passed <code>bound</code>. Returns the count of rows deleted. Note that there may be multiple rows deleted even if only a single column value is passed, since the index is not guaranteed to be unique.</p>
|
||
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="reducers">Reducers<a href="#reducers" class="hash-link" aria-label="Direct link to Reducers" title="Direct link to Reducers" translate="no"></a></h2>
|
||
<p>Reducers are declared using the <code>[SpacetimeDB.Reducer]</code> attribute.</p>
|
||
<p><code>[SpacetimeDB.Reducer]</code> is always applied to static C# functions. The first parameter of a reducer must be a [<code>ReducerContext</code>]. The remaining parameters must be types marked with [<code>SpacetimeDB.Type</code>]. Reducers should return <code>void</code>.</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">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> GivePlayerItem</span><span style="color:#F8F8F2">(</span></span>
|
||
<span class="line"><span style="color:#8BE9FD;font-style:italic"> ReducerContext</span><span style="color:#FFB86C;font-style:italic"> context</span><span style="color:#F8F8F2">,</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> ulong</span><span style="color:#FFB86C;font-style:italic"> PlayerId</span><span style="color:#F8F8F2">,</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> ulong</span><span style="color:#FFB86C;font-style:italic"> ItemId</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> )</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // ...</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Every reducer runs inside a <a href="https://en.wikipedia.org/wiki/Database_transaction" target="_blank" rel="noopener noreferrer">database transaction</a>. This means that reducers will not observe the effects of other reducers modifying the database while they run. If a reducer fails, all of its changes to the database will automatically be rolled back. Reducers can fail by throwing an exception.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="class-reducercontext">Class <code>ReducerContext</code><a href="#class-reducercontext" class="hash-link" aria-label="Direct link to class-reducercontext" title="Direct link to class-reducercontext" translate="no"></a></h3>
|
||
<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"> record</span><span style="color:#8BE9FD"> ReducerContext</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">DbContext</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Local</span><span style="color:#F8F8F2">>, </span><span style="color:#8BE9FD;font-style:italic">Internal</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">IReducerContext</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // ...</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Reducers have access to a special [<code>ReducerContext</code>] parameter. This parameter allows reading and writing the database attached to a module. It also provides some additional functionality, like generating random numbers and scheduling future operations.</p>
|
||
<p>[<code>ReducerContext</code>] provides access to the database tables via <a href="#property-reducercontextdb">the <code>.Db</code> property</a>. The <a href="#tables"><code>[Table]</code></a> attribute generated code that adds table accessors to this property.</p>
|
||
<table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td>Property <a href="#property-reducercontextdb"><code>Db</code></a></td><td>The current state of the database</td></tr><tr><td>Property <a href="#property-reducercontextsender"><code>Sender</code></a></td><td>The <a href="#struct-identity"><code>Identity</code></a> of the caller of the reducer</td></tr><tr><td>Property <a href="#property-reducercontextconnectionid"><code>ConnectionId</code></a></td><td>The <a href="#struct-connectionid"><code>ConnectionId</code></a> of the caller of the reducer, if any</td></tr><tr><td>Property <a href="#property-reducercontextrng"><code>Rng</code></a></td><td>A <a href="https://learn.microsoft.com/en-us/dotnet/api/system.random?view=net-9.0" target="_blank" rel="noopener noreferrer"><code>System.Random</code></a> instance.</td></tr><tr><td>Property <a href="#property-reducercontexttimestamp"><code>Timestamp</code></a></td><td>The <a href="#struct-timestamp"><code>Timestamp</code></a> of the reducer invocation</td></tr><tr><td>Property <a href="#property-reducercontextidentity"><code>Identity</code></a></td><td>The <a href="#struct-identity"><code>Identity</code></a> of the module</td></tr></tbody></table>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="property-reducercontextdb">Property <code>ReducerContext.Db</code><a href="#property-reducercontextdb" class="hash-link" aria-label="Direct link to property-reducercontextdb" title="Direct link to property-reducercontextdb" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">DbView</span><span style="color:#F8F8F2"> Db;</span></span></code></pre>
|
||
<p>Allows accessing the local database attached to a module.</p>
|
||
<p>The <code>[Table]</code> attribute generates a field of this property.</p>
|
||
<p>For a table named <em>table</em>, use <code>ctx.Db.{table}</code> to get a <a href="#interface-itableview">table view</a>.
|
||
For example, <code>ctx.Db.users</code>.</p>
|
||
<p>You can also use <code>ctx.Db.{table}.{index}</code> to get an <a href="#class-index">index</a> or <a href="#class-uniqueindex">unique index</a>.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="property-reducercontextsender">Property <code>ReducerContext.Sender</code><a href="#property-reducercontextsender" class="hash-link" aria-label="Direct link to property-reducercontextsender" title="Direct link to property-reducercontextsender" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">Identity</span><span style="color:#F8F8F2"> Sender;</span></span></code></pre>
|
||
<p>The <a href="#struct-identity"><code>Identity</code></a> of the client that invoked the reducer.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="property-reducercontextconnectionid">Property <code>ReducerContext.ConnectionId</code><a href="#property-reducercontextconnectionid" class="hash-link" aria-label="Direct link to property-reducercontextconnectionid" title="Direct link to property-reducercontextconnectionid" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">ConnectionId</span><span style="color:#F8F8F2">? ConnectionId;</span></span></code></pre>
|
||
<p>The <a href="#struct-connectionid"><code>ConnectionId</code></a> of the client that invoked the reducer.</p>
|
||
<p><code>null</code> if no <code>ConnectionId</code> was supplied to the <code>/database/call</code> HTTP endpoint,
|
||
or via the CLI's <code>spacetime call</code> subcommand.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="property-reducercontextrng">Property <code>ReducerContext.Rng</code><a href="#property-reducercontextrng" class="hash-link" aria-label="Direct link to property-reducercontextrng" title="Direct link to property-reducercontextrng" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">Random</span><span style="color:#F8F8F2"> Rng;</span></span></code></pre>
|
||
<p>A <a href="https://learn.microsoft.com/en-us/dotnet/api/system.random?view=net-9.0" target="_blank" rel="noopener noreferrer"><code>System.Random</code></a> that can be used to generate random numbers.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="property-reducercontexttimestamp">Property <code>ReducerContext.Timestamp</code><a href="#property-reducercontexttimestamp" class="hash-link" aria-label="Direct link to property-reducercontexttimestamp" title="Direct link to property-reducercontexttimestamp" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">Timestamp</span><span style="color:#F8F8F2"> Timestamp;</span></span></code></pre>
|
||
<p>The time at which the reducer was invoked.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="property-reducercontextidentity">Property <code>ReducerContext.Identity</code><a href="#property-reducercontextidentity" class="hash-link" aria-label="Direct link to property-reducercontextidentity" title="Direct link to property-reducercontextidentity" translate="no"></a></h4>
|
||
<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:#8BE9FD;font-style:italic">Identity</span><span style="color:#F8F8F2"> Identity;</span></span></code></pre>
|
||
<p>The <a href="#struct-identity"><code>Identity</code></a> of the module.</p>
|
||
<p>This can be used to <a href="#restricting-scheduled-reducers">check whether a scheduled reducer is being called by a user</a>.</p>
|
||
<p>Note: this is not the identity of the caller, that's <a href="#property-reducercontextsender"><code>ReducerContext.Sender</code></a>.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="lifecycle-reducers">Lifecycle Reducers<a href="#lifecycle-reducers" class="hash-link" aria-label="Direct link to Lifecycle Reducers" title="Direct link to Lifecycle Reducers" translate="no"></a></h3>
|
||
<p>A small group of reducers are called at set points in the module lifecycle. These are used to initialize
|
||
the database and respond to client connections. You can have one of each per module.</p>
|
||
<p>These reducers cannot be called manually and may not have any parameters except for <code>ReducerContext</code>.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="the-init-reducer">The <code>Init</code> reducer<a href="#the-init-reducer" class="hash-link" aria-label="Direct link to the-init-reducer" title="Direct link to the-init-reducer" translate="no"></a></h4>
|
||
<p>This reducer is marked with <code>[SpacetimeDB.Reducer(ReducerKind.Init)]</code>. It is run the first time a module is published and any time the database is cleared.</p>
|
||
<p>If an error occurs when initializing, the module will not be published.</p>
|
||
<p>This reducer can be used to configure any static data tables used by your module. It can also be used to start running <a href="#scheduled-reducers">scheduled reducers</a>.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="the-clientconnected-reducer">The <code>ClientConnected</code> reducer<a href="#the-clientconnected-reducer" class="hash-link" aria-label="Direct link to the-clientconnected-reducer" title="Direct link to the-clientconnected-reducer" translate="no"></a></h4>
|
||
<p>This reducer is marked with <code>[SpacetimeDB.Reducer(ReducerKind.ClientConnected)]</code>. It is run when a client connects to the SpacetimeDB database. Their identity can be found in the sender value of the <code>ReducerContext</code>.</p>
|
||
<p>If an error occurs in the reducer, the client will be disconnected.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="the-clientdisconnected-reducer">The <code>ClientDisconnected</code> reducer<a href="#the-clientdisconnected-reducer" class="hash-link" aria-label="Direct link to the-clientdisconnected-reducer" title="Direct link to the-clientdisconnected-reducer" translate="no"></a></h4>
|
||
<p>This reducer is marked with <code>[SpacetimeDB.Reducer(ReducerKind.ClientDisconnected)]</code>. It is run when a client disconnects from the SpacetimeDB database. Their identity can be found in the sender value of the <code>ReducerContext</code>.</p>
|
||
<p>If an error occurs in the disconnect reducer, the client is still recorded as disconnected.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="scheduled-reducers">Scheduled Reducers<a href="#scheduled-reducers" class="hash-link" aria-label="Direct link to Scheduled Reducers" title="Direct link to Scheduled Reducers" translate="no"></a></h3>
|
||
<p>Reducers can schedule other reducers to run asynchronously. This allows calling the reducers at a particular time, or at repeating intervals. This can be used to implement timers, game loops, and maintenance tasks.</p>
|
||
<p>The scheduling information for a reducer is stored in a table.
|
||
This table has two mandatory fields:</p>
|
||
<ul>
|
||
<li>An <code>[AutoInc] [PrimaryKey] ulong</code> field that identifies scheduled reducer calls.</li>
|
||
<li>A <a href="#record-scheduleat"><code>ScheduleAt</code></a> field that says when to call the reducer.</li>
|
||
</ul>
|
||
<p>Managing timers with a scheduled table is as simple as inserting or deleting rows from the table.
|
||
This makes scheduling transactional in SpacetimeDB. If a reducer A first schedules B but then errors for some other reason, B will not be scheduled to run.</p>
|
||
<p>A <a href="#record-scheduleat"><code>ScheduleAt</code></a> can be created from a <a href="#struct-timestamp"><code>Timestamp</code></a>, in which case the reducer will be scheduled once, or from a <a href="#struct-timeduration"><code>TimeDuration</code></a>, in which case the reducer will be scheduled in a loop.</p>
|
||
<p>Example:</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">using</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> // First, we declare the table with scheduling information.</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">send_message_schedule</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">, Scheduled </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> nameof</span><span style="color:#F8F8F2">(SendMessage), ScheduledAt </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> nameof</span><span style="color:#F8F8F2">(ScheduledAt))]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> SendMessageSchedule</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> // Mandatory fields:</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">PrimaryKey</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">AutoInc</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> ulong</span><span style="color:#F8F8F2"> Id;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#8BE9FD;font-style:italic"> ScheduleAt</span><span style="color:#F8F8F2"> ScheduledAt;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> // Custom fields:</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Message;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> // Then, we declare the scheduled reducer.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // The first argument of the reducer should be, as always, a `ReducerContext`.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // The second argument should be a row of the scheduling information table.</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> SendMessage</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">SendMessageSchedule</span><span style="color:#FFB86C;font-style:italic"> schedule</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Info</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">$"</span><span style="color:#F1FA8C">Sending message </span><span style="color:#FF79C6">{</span><span style="color:#F8F8F2">schedule</span><span style="color:#F1FA8C">.</span><span style="color:#F8F8F2">Message</span><span style="color:#FF79C6">}</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // ...</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> // Finally, we want to actually start scheduling reducers.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // It's convenient to do this inside the `init` reducer.</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">(ReducerKind.Init)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Init</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> currentTime </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> ctx.Timestamp;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> tenSeconds </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> TimeDuration</span><span style="color:#F8F8F2"> { Microseconds </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> +</span><span style="color:#BD93F9">10_000_000</span><span style="color:#F8F8F2"> };</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> futureTimestamp </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> currentTime </span><span style="color:#FF79C6">+</span><span style="color:#F8F8F2"> tenSeconds;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> ctx.Db.send_message_schedule.</span><span style="color:#50FA7B">Insert</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#F8F8F2">()</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Id </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2">, </span><span style="color:#6272A4">// Have [AutoInc] assign an Id.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> ScheduledAt </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> ScheduleAt</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Time</span><span style="color:#F8F8F2">(futureTimestamp),</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Message </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">I'm a bot sending a message one time!</span><span style="color:#E9F284">"</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> });</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> ctx.Db.send_message_schedule.</span><span style="color:#50FA7B">Insert</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#F8F8F2">()</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Id </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2">, </span><span style="color:#6272A4">// Have [AutoInc] assign an Id.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> ScheduledAt </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> ScheduleAt</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Interval</span><span style="color:#F8F8F2">(tenSeconds),</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Message </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">I'm a bot sending a message every ten seconds!</span><span style="color:#E9F284">"</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> });</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Scheduled reducers are called on a best-effort basis and may be slightly delayed in their execution
|
||
when a database is under heavy load.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="restricting-scheduled-reducers">Restricting scheduled reducers<a href="#restricting-scheduled-reducers" class="hash-link" aria-label="Direct link to Restricting scheduled reducers" title="Direct link to Restricting scheduled reducers" translate="no"></a></h4>
|
||
<p>Scheduled reducers are normal reducers, and may still be called by clients.
|
||
If a scheduled reducer should only be called by the scheduler, consider beginning it with a check that the caller <code>Identity</code> is the module:</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> SendMessage</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">SendMessageSchedule</span><span style="color:#FFB86C;font-style:italic"> schedule</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> if</span><span style="color:#F8F8F2"> (ctx.Sender </span><span style="color:#FF79C6">!=</span><span style="color:#F8F8F2"> ctx.Identity)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> throw</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> Exception</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">Reducer SendMessage may not be invoked by clients, only via scheduling.</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // ...</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="automatic-migrations">Automatic migrations<a href="#automatic-migrations" class="hash-link" aria-label="Direct link to Automatic migrations" title="Direct link to Automatic migrations" translate="no"></a></h2>
|
||
<p>When you <code>spacetime publish</code> a module that has already been published using <code>spacetime publish <DATABASE_NAME_OR_IDENTITY></code>,
|
||
SpacetimeDB attempts to automatically migrate your existing database to the new schema. (The "schema" is just the collection
|
||
of tables and reducers you've declared in your code, together with the types they depend on.) This form of migration is limited and only supports a few kinds of changes.
|
||
On the plus side, automatic migrations usually don't break clients. The situations that may break clients are documented below.</p>
|
||
<p>The following changes are always allowed and never breaking:</p>
|
||
<ul>
|
||
<li>✅ <strong>Adding tables</strong>. Non-updated clients will not be able to see the new tables.</li>
|
||
<li>✅ <strong>Adding indexes</strong>.</li>
|
||
<li>✅ <strong>Adding or removing <code>[AutoInc]</code> annotations.</strong></li>
|
||
<li>✅ <strong>Changing tables from private to public</strong>.</li>
|
||
<li>✅ <strong>Adding reducers</strong>.</li>
|
||
<li>✅ <strong>Removing <code>[Unique]</code> annotations.</strong></li>
|
||
</ul>
|
||
<p>The following changes are allowed, but may break clients:</p>
|
||
<ul>
|
||
<li>
|
||
<p>⚠️ <strong>Changing or removing reducers</strong>. Clients that attempt to call the old version of a changed reducer will receive runtime errors.</p>
|
||
</li>
|
||
<li>
|
||
<p>⚠️ <strong>Changing tables from public to private</strong>. Clients that are subscribed to a newly-private table will receive runtime errors.</p>
|
||
</li>
|
||
<li>
|
||
<p>⚠️ <strong>Removing <code>[PrimaryKey]</code> annotations</strong>. Non-updated clients will still use the old <code>[PrimaryKey]</code> as a unique key in their local cache, which can result in non-deterministic behavior when updates are received.</p>
|
||
</li>
|
||
<li>
|
||
<p>⚠️ <strong>Removing indexes</strong>. This is only breaking in some situtations.
|
||
The specific problem is subscription queries involving semijoins, such as:</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:#F8F8F2"> Employee.</span><span style="color:#FF79C6">*</span></span>
|
||
<span class="line"><span style="color:#FF79C6">FROM</span><span style="color:#F8F8F2"> Employee </span><span style="color:#FF79C6">JOIN</span><span style="color:#F8F8F2"> Dept</span></span>
|
||
<span class="line"><span style="color:#FF79C6">ON</span><span style="color:#BD93F9"> Employee</span><span style="color:#F8F8F2">.</span><span style="color:#BD93F9">DeptName</span><span style="color:#FF79C6"> =</span><span style="color:#BD93F9"> Dept</span><span style="color:#F8F8F2">.</span><span style="color:#BD93F9">DeptName</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">)</span></span></code></pre>
|
||
<p>For performance reasons, SpacetimeDB will only allow this kind of subscription query if there are indexes on <code>Employee.DeptName</code> and <code>Dept.DeptName</code>. Removing either of these indexes will invalidate this subscription query, resulting in client-side runtime errors.</p>
|
||
</li>
|
||
</ul>
|
||
<p>The following changes are forbidden without a manual migration:</p>
|
||
<ul>
|
||
<li>❌ <strong>Removing tables</strong>.</li>
|
||
<li>❌ <strong>Changing the columns of a table</strong>. This includes changing the order of columns of a table.</li>
|
||
<li>❌ <strong>Changing whether a table is used for <a href="#scheduled-reducers">scheduling</a>.</strong> </li>
|
||
<li>❌ <strong>Adding <code>[Unique]</code> or <code>[PrimaryKey]</code> constraints.</strong> This could result in existing tables being in an invalid state.</li>
|
||
</ul>
|
||
<p>Currently, manual migration support is limited. The <code>spacetime publish --clear-database <DATABASE_IDENTITY></code> command can be used to <strong>COMPLETELY DELETE</strong> and reinitialize your database, but naturally it should be used with EXTREME CAUTION.</p>
|
||
<h2 class="anchor anchorWithStickyNavbar_wKCU" id="other-infrastructure">Other infrastructure<a href="#other-infrastructure" class="hash-link" aria-label="Direct link to Other infrastructure" title="Direct link to Other infrastructure" translate="no"></a></h2>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="class-log">Class <code>Log</code><a href="#class-log" class="hash-link" aria-label="Direct link to class-log" title="Direct link to class-log" translate="no"></a></h3>
|
||
<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">namespace</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Log</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Debug</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> message</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Error</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> message</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Exception</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> message</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Exception</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Exception</span><span style="color:#FFB86C;font-style:italic"> exception</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Info</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> message</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Trace</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> message</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Warn</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> message</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Methods for writing to a private debug log. Log messages will include file and line numbers.</p>
|
||
<p>Log outputs of a running database can be inspected using the <code>spacetime logs</code> command:</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>spacetime logs <DATABASE_IDENTITY></span></span></code></pre>
|
||
<p>These are only visible to the database owner, not to clients or other developers.</p>
|
||
<p>Note that <code>Log.Error</code> and <code>Log.Exception</code> only write to the log, they do not throw exceptions themselves.</p>
|
||
<p>Example:</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">using</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">user</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> User</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">PrimaryKey</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> uint</span><span style="color:#F8F8F2"> Id;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Unique</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> Username;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> ulong</span><span style="color:#F8F8F2"> DogCount;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> LogDogs</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">) {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Info</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">Examining users.</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6"> var</span><span style="color:#F8F8F2"> totalDogCount </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6"> foreach</span><span style="color:#F8F8F2"> (</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> user </span><span style="color:#FF79C6">in</span><span style="color:#F8F8F2"> ctx.Db.user.</span><span style="color:#50FA7B">Iter</span><span style="color:#F8F8F2">()) {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Info</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">$"</span><span style="color:#F1FA8C"> User: Id = </span><span style="color:#FF79C6">{</span><span style="color:#F8F8F2">user</span><span style="color:#F1FA8C">.</span><span style="color:#F8F8F2">Id</span><span style="color:#FF79C6">}</span><span style="color:#F1FA8C">, Username = </span><span style="color:#FF79C6">{</span><span style="color:#F8F8F2">user</span><span style="color:#F1FA8C">.</span><span style="color:#F8F8F2">Username</span><span style="color:#FF79C6">}</span><span style="color:#F1FA8C">, DogCount = </span><span style="color:#FF79C6">{</span><span style="color:#F8F8F2">user</span><span style="color:#F1FA8C">.</span><span style="color:#F8F8F2">DogCount</span><span style="color:#FF79C6">}</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> totalDogCount </span><span style="color:#FF79C6">+=</span><span style="color:#F8F8F2"> user.DogCount;</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"> (totalDogCount </span><span style="color:#FF79C6"><</span><span style="color:#BD93F9"> 300</span><span style="color:#F8F8F2">) {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Warn</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">Insufficient dogs.</span><span style="color:#E9F284">"</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"> (totalDogCount </span><span style="color:#FF79C6"><</span><span style="color:#BD93F9"> 100</span><span style="color:#F8F8F2">) {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Error</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">Dog population is critically low!</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="attribute-spacetimedbtype">Attribute <code>[SpacetimeDB.Type]</code><a href="#attribute-spacetimedbtype" class="hash-link" aria-label="Direct link to attribute-spacetimedbtype" title="Direct link to attribute-spacetimedbtype" translate="no"></a></h3>
|
||
<p>This attribute makes types self-describing, allowing them to automatically register their structure
|
||
with SpacetimeDB. Any C# type annotated with <code>[SpacetimeDB.Type]</code> can be used as a table column or reducer argument.</p>
|
||
<p>Types marked <code>[SpacetimeDB.Table]</code> are automatically marked <code>[SpacetimeDB.Type]</code>.</p>
|
||
<p><code>[SpacetimeDB.Type]</code> can be combined with [<code>SpacetimeDB.TaggedEnum</code>] to use tagged enums in tables or reducers.</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">using</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> class</span><span style="color:#8BE9FD"> Module</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Coord</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> X;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Y;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> TankData</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Ammo;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> LeftTreadHealth;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> RightTreadHealth;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> TransportData</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> TroopCount;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6272A4"> // A type that could be either the data for a Tank or the data for a Transport.</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // See SpacetimeDB.TaggedEnum docs.</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> record</span><span style="color:#8BE9FD"> VehicleData</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">TaggedEnum</span><span style="color:#F8F8F2"><(</span><span style="color:#8BE9FD;font-style:italic">TankData</span><span style="color:#F8F8F2"> Tank, </span><span style="color:#8BE9FD;font-style:italic">TransportData</span><span style="color:#F8F8F2"> Transport)> {}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">Table</span><span style="color:#F8F8F2">(Name </span><span style="color:#FF79C6">=</span><span style="color:#E9F284"> "</span><span style="color:#F1FA8C">vehicle</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">)]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Vehicle</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">PrimaryKey</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">AutoInc</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> uint</span><span style="color:#F8F8F2"> Id;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#8BE9FD;font-style:italic"> Coord</span><span style="color:#F8F8F2"> Coord;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#8BE9FD;font-style:italic"> VehicleData</span><span style="color:#F8F8F2"> Data;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2"> [</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Reducer</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> InsertVehicle</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ReducerContext</span><span style="color:#FFB86C;font-style:italic"> ctx</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">Coord</span><span style="color:#FFB86C;font-style:italic"> Coord</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">VehicleData</span><span style="color:#FFB86C;font-style:italic"> Data</span><span style="color:#F8F8F2">) {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> ctx.Db.vehicle.</span><span style="color:#50FA7B">Insert</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">new</span><span style="color:#8BE9FD;font-style:italic"> Vehicle</span><span style="color:#F8F8F2"> { Id </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2">, Coord </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> Coord, Data </span><span style="color:#FF79C6">=</span><span style="color:#F8F8F2"> Data });</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>The fields of the struct/enum must also be marked with <code>[SpacetimeDB.Type]</code>.</p>
|
||
<p>Some types from the standard library are also considered to be marked with <code>[SpacetimeDB.Type]</code>, including:</p>
|
||
<ul>
|
||
<li><code>byte</code></li>
|
||
<li><code>sbyte</code></li>
|
||
<li><code>ushort</code></li>
|
||
<li><code>short</code></li>
|
||
<li><code>uint</code></li>
|
||
<li><code>int</code></li>
|
||
<li><code>ulong</code></li>
|
||
<li><code>long</code></li>
|
||
<li><code>SpacetimeDB.U128</code></li>
|
||
<li><code>SpacetimeDB.I128</code></li>
|
||
<li><code>SpacetimeDB.U256</code></li>
|
||
<li><code>SpacetimeDB.I256</code></li>
|
||
<li><code>List<T></code> where <code>T</code> is a <code>[SpacetimeDB.Type]</code></li>
|
||
</ul>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="struct-identity">Struct <code>Identity</code><a href="#struct-identity" class="hash-link" aria-label="Direct link to struct-identity" title="Direct link to struct-identity" translate="no"></a></h3>
|
||
<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">namespace</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> readonly</span><span style="color:#FF79C6"> record</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Identity</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#8BE9FD;font-style:italic"> Identity</span><span style="color:#50FA7B"> FromHexString</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> hex</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#50FA7B"> ToString</span><span style="color:#F8F8F2">();</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>An <code>Identity</code> for something interacting with the database.</p>
|
||
<p>This is a record struct, so it can be printed, compared with <code>==</code>, and used as a <code>Dictionary</code> key.</p>
|
||
<p><code>ToString()</code> returns a hex encoding of the Identity, suitable for printing.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="struct-connectionid">Struct <code>ConnectionId</code><a href="#struct-connectionid" class="hash-link" aria-label="Direct link to struct-connectionid" title="Direct link to struct-connectionid" translate="no"></a></h3>
|
||
<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">namespace</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> readonly</span><span style="color:#FF79C6"> record</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> ConnectionId</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> static</span><span style="color:#8BE9FD;font-style:italic"> ConnectionId</span><span style="color:#F8F8F2">? </span><span style="color:#50FA7B">FromHexString</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">string</span><span style="color:#FFB86C;font-style:italic"> hex</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> string</span><span style="color:#50FA7B"> ToString</span><span style="color:#F8F8F2">();</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>A unique identifier for a client connection to a SpacetimeDB database.</p>
|
||
<p>This is a record struct, so it can be printed, compared with <code>==</code>, and used as a <code>Dictionary</code> key.</p>
|
||
<p><code>ToString()</code> returns a hex encoding of the <code>ConnectionId</code>, suitable for printing.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="struct-timestamp">Struct <code>Timestamp</code><a href="#struct-timestamp" class="hash-link" aria-label="Direct link to struct-timestamp" title="Direct link to struct-timestamp" translate="no"></a></h3>
|
||
<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">namespace</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> record</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Timestamp</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">long</span><span style="color:#FFB86C;font-style:italic"> MicrosecondsSinceUnixEpoch</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">IStructuralReadWrite</span><span style="color:#F8F8F2">,</span></span>
|
||
<span class="line"><span style="color:#8BE9FD;font-style:italic"> IComparable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Timestamp</span><span style="color:#F8F8F2">></span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // ...</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>A point in time, measured in microseconds since the Unix epoch.
|
||
This can be converted to/from a standard library <a href="https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset?view=net-9.0" target="_blank" rel="noopener noreferrer"><code>DateTimeOffset</code></a>. It is provided for consistency of behavior between SpacetimeDB's supported module and SDK languages.</p>
|
||
<table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td>Property <code>MicrosecondsSinceUnixEpoch</code></td><td>Microseconds since the <a href="https://en.wikipedia.org/wiki/Unix_time" target="_blank" rel="noopener noreferrer">unix epoch</a>.</td></tr><tr><td>Conversion to/from <code>DateTimeOffset</code></td><td>Convert to/from a standard library <a href="https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset?view=net-9.0" target="_blank" rel="noopener noreferrer"><code>DateTimeOffset</code></a></td></tr><tr><td>Static property <code>UNIX_EPOCH</code></td><td>The <a href="https://en.wikipedia.org/wiki/Unix_time" target="_blank" rel="noopener noreferrer">unix epoch</a> as a <code>Timestamp</code></td></tr><tr><td>Method <code>TimeDurationSince</code></td><td>Measure the time elapsed since another <code>Timestamp</code></td></tr><tr><td>Operator <code>+</code></td><td>Add a [<code>TimeDuration</code>] to a <code>Timestamp</code></td></tr><tr><td>Method <code>CompareTo</code></td><td>Compare to another <code>Timestamp</code></td></tr></tbody></table>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="property-timestampmicrosecondssinceunixepoch">Property <code>Timestamp.MicrosecondsSinceUnixEpoch</code><a href="#property-timestampmicrosecondssinceunixepoch" class="hash-link" aria-label="Direct link to property-timestampmicrosecondssinceunixepoch" title="Direct link to property-timestampmicrosecondssinceunixepoch" translate="no"></a></h4>
|
||
<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">long</span><span style="color:#F8F8F2"> MicrosecondsSinceUnixEpoch;</span></span></code></pre>
|
||
<p>The number of microseconds since the <a href="https://en.wikipedia.org/wiki/Unix_time" target="_blank" rel="noopener noreferrer">unix epoch</a>.</p>
|
||
<p>A positive value means a time after the Unix epoch, and a negative value means a time before.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="conversion-tofrom-datetimeoffset">Conversion to/from <code>DateTimeOffset</code><a href="#conversion-tofrom-datetimeoffset" class="hash-link" aria-label="Direct link to conversion-tofrom-datetimeoffset" title="Direct link to conversion-tofrom-datetimeoffset" translate="no"></a></h4>
|
||
<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"> static</span><span style="color:#F8F8F2"> implicit </span><span style="color:#8BE9FD;font-style:italic">operator</span><span style="color:#50FA7B"> DateTimeOffset</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Timestamp</span><span style="color:#FFB86C;font-style:italic"> t</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#F8F8F2"> implicit </span><span style="color:#8BE9FD;font-style:italic">operator</span><span style="color:#50FA7B"> Timestamp</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">DateTimeOffset</span><span style="color:#FFB86C;font-style:italic"> offset</span><span style="color:#F8F8F2">);</span></span></code></pre>
|
||
<p><code>Timestamp</code> may be converted to/from a <a href="https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset?view=net-9.0" target="_blank" rel="noopener noreferrer"><code>DateTimeOffset</code></a>, but the conversion can lose precision.
|
||
This type has less precision than DateTimeOffset (units of microseconds rather than units of 100ns).</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="static-property-timestampunix_epoch">Static property <code>Timestamp.UNIX_EPOCH</code><a href="#static-property-timestampunix_epoch" class="hash-link" aria-label="Direct link to static-property-timestampunix_epoch" title="Direct link to static-property-timestampunix_epoch" translate="no"></a></h4>
|
||
<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"> static</span><span style="color:#FF79C6"> readonly</span><span style="color:#8BE9FD;font-style:italic"> Timestamp</span><span style="color:#F8F8F2"> UNIX_EPOCH </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> Timestamp</span><span style="color:#F8F8F2"> { MicrosecondsSinceUnixEpoch </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2"> };</span></span></code></pre>
|
||
<p>The <a href="https://en.wikipedia.org/wiki/Unix_time" target="_blank" rel="noopener noreferrer">unix epoch</a> as a <code>Timestamp</code>.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-timestamptimedurationsince">Method <code>Timestamp.TimeDurationSince</code><a href="#method-timestamptimedurationsince" class="hash-link" aria-label="Direct link to method-timestamptimedurationsince" title="Direct link to method-timestamptimedurationsince" translate="no"></a></h4>
|
||
<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"> readonly</span><span style="color:#8BE9FD;font-style:italic"> TimeDuration</span><span style="color:#50FA7B"> TimeDurationSince</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Timestamp</span><span style="color:#FFB86C;font-style:italic"> earlier</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">=></span></span></code></pre>
|
||
<p>Create a new [<code>TimeDuration</code>] that is the difference between two <code>Timestamps</code>.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="operator-timestamp">Operator <code>Timestamp.+</code><a href="#operator-timestamp" class="hash-link" aria-label="Direct link to operator-timestamp" title="Direct link to operator-timestamp" translate="no"></a></h4>
|
||
<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"> static</span><span style="color:#F8F8F2"> Timestamp operator </span><span style="color:#FF79C6">+</span><span style="color:#F8F8F2">(Timestamp point, TimeDuration interval);</span></span></code></pre>
|
||
<p>Create a new <code>Timestamp</code> that occurs <code>interval</code> after <code>point</code>.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="method-timestampcompareto">Method <code>Timestamp.CompareTo</code><a href="#method-timestampcompareto" class="hash-link" aria-label="Direct link to method-timestampcompareto" title="Direct link to method-timestampcompareto" translate="no"></a></h4>
|
||
<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"> int</span><span style="color:#50FA7B"> CompareTo</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">Timestamp</span><span style="color:#FFB86C;font-style:italic"> that</span><span style="color:#F8F8F2">)</span></span></code></pre>
|
||
<p>Compare two <code>Timestamp</code>s.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="struct-timeduration">Struct <code>TimeDuration</code><a href="#struct-timeduration" class="hash-link" aria-label="Direct link to struct-timeduration" title="Direct link to struct-timeduration" translate="no"></a></h3>
|
||
<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">namespace</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> record</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> TimeDuration</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">long</span><span style="color:#FFB86C;font-style:italic"> Microseconds</span><span style="color:#F8F8F2">) : </span><span style="color:#8BE9FD;font-style:italic">IStructuralReadWrite</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#6272A4"> // ...</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>A duration that represents an interval between two [<code>Timestamp</code>]s.</p>
|
||
<p>This type may be converted to/from a <a href="https://learn.microsoft.com/en-us/dotnet/api/system.timespan?view=net-9.0" target="_blank" rel="noopener noreferrer"><code>TimeSpan</code></a>. It is provided for consistency of behavior between SpacetimeDB's supported module and SDK languages.</p>
|
||
<table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td>Property <a href="#property-timedurationmicroseconds"><code>Microseconds</code></a></td><td>Microseconds between the [<code>Timestamp</code>]s.</td></tr><tr><td><a href="#conversion-tofrom-timespan">Conversion to/from <code>TimeSpan</code></a></td><td>Convert to/from a standard library <a href="https://learn.microsoft.com/en-us/dotnet/api/system.timespan?view=net-9.0" target="_blank" rel="noopener noreferrer"><code>TimeSpan</code></a></td></tr><tr><td>Static property <a href="#static-property-timedurationzero"><code>ZERO</code></a></td><td>The duration between any [<code>Timestamp</code>] and itself</td></tr></tbody></table>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="property-timedurationmicroseconds">Property <code>TimeDuration.Microseconds</code><a href="#property-timedurationmicroseconds" class="hash-link" aria-label="Direct link to property-timedurationmicroseconds" title="Direct link to property-timedurationmicroseconds" translate="no"></a></h4>
|
||
<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">long</span><span style="color:#F8F8F2"> Microseconds;</span></span></code></pre>
|
||
<p>The number of microseconds between two [<code>Timestamp</code>]s.</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="conversion-tofrom-timespan">Conversion to/from <code>TimeSpan</code><a href="#conversion-tofrom-timespan" class="hash-link" aria-label="Direct link to conversion-tofrom-timespan" title="Direct link to conversion-tofrom-timespan" translate="no"></a></h4>
|
||
<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"> static</span><span style="color:#F8F8F2"> implicit </span><span style="color:#8BE9FD;font-style:italic">operator</span><span style="color:#50FA7B"> TimeSpan</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">TimeDuration</span><span style="color:#FFB86C;font-style:italic"> d</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">=></span></span>
|
||
<span class="line"><span style="color:#FF79C6"> new</span><span style="color:#F8F8F2">(d.Microseconds </span><span style="color:#FF79C6">*</span><span style="color:#F8F8F2"> Util.TicksPerMicrosecond);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> static</span><span style="color:#F8F8F2"> implicit </span><span style="color:#8BE9FD;font-style:italic">operator</span><span style="color:#50FA7B"> TimeDuration</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">TimeSpan</span><span style="color:#FFB86C;font-style:italic"> timeSpan</span><span style="color:#F8F8F2">) </span><span style="color:#FF79C6">=></span></span>
|
||
<span class="line"><span style="color:#FF79C6"> new</span><span style="color:#F8F8F2">(timeSpan.Ticks </span><span style="color:#FF79C6">/</span><span style="color:#F8F8F2"> Util.TicksPerMicrosecond);</span></span></code></pre>
|
||
<p><code>TimeDuration</code> may be converted to/from a <a href="https://learn.microsoft.com/en-us/dotnet/api/system.timespan?view=net-9.0" target="_blank" rel="noopener noreferrer"><code>TimeSpan</code></a>, but the conversion can lose precision.
|
||
This type has less precision than <a href="https://learn.microsoft.com/en-us/dotnet/api/system.timespan?view=net-9.0" target="_blank" rel="noopener noreferrer"><code>TimeSpan</code></a> (units of microseconds rather than units of 100ns).</p>
|
||
<h4 class="anchor anchorWithStickyNavbar_wKCU" id="static-property-timedurationzero">Static property <code>TimeDuration.ZERO</code><a href="#static-property-timedurationzero" class="hash-link" aria-label="Direct link to static-property-timedurationzero" title="Direct link to static-property-timedurationzero" translate="no"></a></h4>
|
||
<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"> static</span><span style="color:#FF79C6"> readonly</span><span style="color:#8BE9FD;font-style:italic"> TimeDuration</span><span style="color:#F8F8F2"> ZERO </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> TimeDuration</span><span style="color:#F8F8F2"> { Microseconds </span><span style="color:#FF79C6">=</span><span style="color:#BD93F9"> 0</span><span style="color:#F8F8F2"> };</span></span></code></pre>
|
||
<p>The duration between any <code>Timestamp</code> and itself.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="record-taggedenum">Record <code>TaggedEnum</code><a href="#record-taggedenum" class="hash-link" aria-label="Direct link to record-taggedenum" title="Direct link to record-taggedenum" translate="no"></a></h3>
|
||
<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">namespace</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> abstract</span><span style="color:#FF79C6"> record</span><span style="color:#8BE9FD"> TaggedEnum</span><span style="color:#F8F8F2"><</span><span style="color:#FFB86C;font-style:italic">Variants</span><span style="color:#F8F8F2">> : </span><span style="color:#8BE9FD;font-style:italic">IEquatable</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">TaggedEnum</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Variants</span><span style="color:#F8F8F2">>> </span><span style="color:#FF79C6">where</span><span style="color:#FFB86C;font-style:italic"> Variants</span><span style="color:#F8F8F2"> : </span><span style="color:#FF79C6">struct</span><span style="color:#F8F8F2">, </span><span style="color:#8BE9FD;font-style:italic">ITuple</span></span></code></pre>
|
||
<p>A <a href="https://en.wikipedia.org/wiki/Tagged_union" target="_blank" rel="noopener noreferrer">tagged enum</a> is a type that can hold a value from any one of several types. <code>TaggedEnum</code> uses code generation to accomplish this.</p>
|
||
<p>For example, to declare a type that can be either a <code>string</code> or an <code>int</code>, write:</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> record</span><span style="color:#8BE9FD"> ProductId</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">TaggedEnum</span><span style="color:#F8F8F2"><(</span><span style="color:#FF79C6">string</span><span style="color:#F8F8F2"> Text, </span><span style="color:#FF79C6">uint</span><span style="color:#F8F8F2"> Number)> { }</span></span></code></pre>
|
||
<p>Here there are two <strong>variants</strong>: one is named <code>Text</code> and holds a <code>string</code>, the other is named <code>Number</code> and holds a <code>uint</code>.</p>
|
||
<p>To create a value of this type, use <code>new {Type}.{Variant}({data})</code>. For example:</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:#8BE9FD;font-style:italic">ProductId</span><span style="color:#F8F8F2"> a </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> ProductId</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Text</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">"</span><span style="color:#F1FA8C">apple</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#8BE9FD;font-style:italic">ProductId</span><span style="color:#F8F8F2"> b </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> ProductId</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Number</span><span style="color:#F8F8F2">(</span><span style="color:#BD93F9">57</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#8BE9FD;font-style:italic">ProductId</span><span style="color:#F8F8F2"> c </span><span style="color:#FF79C6">=</span><span style="color:#FF79C6"> new</span><span style="color:#8BE9FD;font-style:italic"> ProductId</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Number</span><span style="color:#F8F8F2">(</span><span style="color:#BD93F9">59</span><span style="color:#F8F8F2">);</span></span></code></pre>
|
||
<p>To use a value of this type, you need to check which variant it stores.
|
||
This is done with <a href="https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching" target="_blank" rel="noopener noreferrer">C# pattern matching syntax</a>. For example:</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">public</span><span style="color:#FF79C6"> static</span><span style="color:#FF79C6"> void</span><span style="color:#50FA7B"> Print</span><span style="color:#F8F8F2">(</span><span style="color:#8BE9FD;font-style:italic">ProductId</span><span style="color:#FFB86C;font-style:italic"> id</span><span style="color:#F8F8F2">)</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">{</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> if</span><span style="color:#F8F8F2"> (id </span><span style="color:#FF79C6">is</span><span style="color:#8BE9FD;font-style:italic"> ProductId</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Text</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> s))</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Info</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">$"</span><span style="color:#F1FA8C">Textual product ID: '</span><span style="color:#FF79C6">{</span><span style="color:#F8F8F2">s</span><span style="color:#FF79C6">}</span><span style="color:#F1FA8C">'</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> else</span><span style="color:#FF79C6"> if</span><span style="color:#F8F8F2"> (id </span><span style="color:#FF79C6">is</span><span style="color:#8BE9FD;font-style:italic"> ProductId</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Number</span><span style="color:#F8F8F2">(</span><span style="color:#FF79C6">var</span><span style="color:#F8F8F2"> i))</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> Log.</span><span style="color:#50FA7B">Info</span><span style="color:#F8F8F2">(</span><span style="color:#E9F284">$"</span><span style="color:#F1FA8C">Numeric Product ID: </span><span style="color:#FF79C6">{</span><span style="color:#F8F8F2">i</span><span style="color:#FF79C6">}</span><span style="color:#E9F284">"</span><span style="color:#F8F8F2">);</span></span>
|
||
<span class="line"><span style="color:#F8F8F2"> }</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>A <code>TaggedEnum</code> can have up to 255 variants, and the variants can be any type marked with [<code>[SpacetimeDB.Type]</code>].</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> record</span><span style="color:#8BE9FD"> ManyChoices</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">TaggedEnum</span><span style="color:#F8F8F2"><(</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> string</span><span style="color:#F8F8F2"> String,</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Int,</span></span>
|
||
<span class="line"><span style="color:#8BE9FD;font-style:italic"> List</span><span style="color:#F8F8F2"><</span><span style="color:#FF79C6">int</span><span style="color:#F8F8F2">> IntList,</span></span>
|
||
<span class="line"><span style="color:#8BE9FD;font-style:italic"> Banana</span><span style="color:#F8F8F2"> Banana,</span></span>
|
||
<span class="line"><span style="color:#8BE9FD;font-style:italic"> List</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">List</span><span style="color:#F8F8F2"><</span><span style="color:#8BE9FD;font-style:italic">Banana</span><span style="color:#F8F8F2">>> BananaMatrix</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">)> { }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> Banana</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Sweetness;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Rot;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p><code>TaggedEnums</code> are an excellent alternative to nullable fields when groups of fields are always set together. Consider a data type like:</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> ShapeData</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2">? CircleRadius;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2">? RectWidth;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2">? RectHeight;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span></code></pre>
|
||
<p>Often this is supposed to be a circle XOR a rectangle -- that is, not both at the same time. If this is the case, then we don't want to set <code>circleRadius</code> at the same time as <code>rectWidth</code> or <code>rectHeight</code>. Also, if <code>rectWidth</code> is set, we expect <code>rectHeight</code> to be set.
|
||
However, C# doesn't know about this, so code using this type will be littered with extra null checks.</p>
|
||
<p>If we instead write:</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:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> CircleData</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Radius;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> struct</span><span style="color:#8BE9FD;font-style:italic"> RectData</span><span style="color:#F8F8F2"> {</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Width;</span></span>
|
||
<span class="line"><span style="color:#FF79C6"> public</span><span style="color:#FF79C6"> int</span><span style="color:#F8F8F2"> Height;</span></span>
|
||
<span class="line"><span style="color:#F8F8F2">}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F8F8F2">[</span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">Type</span><span style="color:#F8F8F2">]</span></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> record</span><span style="color:#8BE9FD"> ShapeData</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">SpacetimeDB</span><span style="color:#F8F8F2">.</span><span style="color:#8BE9FD;font-style:italic">TaggedEnum</span><span style="color:#F8F8F2"><(</span><span style="color:#8BE9FD;font-style:italic">CircleData</span><span style="color:#F8F8F2"> Circle, </span><span style="color:#8BE9FD;font-style:italic">RectData</span><span style="color:#F8F8F2"> Rect)> { }</span></span></code></pre>
|
||
<p>Then code using a <code>ShapeData</code> will only have to do one check -- do I have a circle or a rectangle?
|
||
And in each case, the data will be guaranteed to have exactly the fields needed.</p>
|
||
<h3 class="anchor anchorWithStickyNavbar_wKCU" id="record-scheduleat">Record <code>ScheduleAt</code><a href="#record-scheduleat" class="hash-link" aria-label="Direct link to record-scheduleat" title="Direct link to record-scheduleat" translate="no"></a></h3>
|
||
<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">namespace</span><span style="color:#8BE9FD;font-style:italic"> SpacetimeDB</span><span style="color:#F8F8F2">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#FF79C6">public</span><span style="color:#FF79C6"> partial</span><span style="color:#FF79C6"> record</span><span style="color:#8BE9FD"> ScheduleAt</span><span style="color:#F8F8F2"> : </span><span style="color:#8BE9FD;font-style:italic">TaggedEnum</span><span style="color:#F8F8F2"><(</span><span style="color:#8BE9FD;font-style:italic">TimeDuration</span><span style="color:#F8F8F2"> Interval, </span><span style="color:#8BE9FD;font-style:italic">Timestamp</span><span style="color:#F8F8F2"> Time)></span></span></code></pre>
|
||
<p>When a <a href="#scheduled-reducers">scheduled reducer</a> should execute, either at a specific point in time, or at regular intervals for repeating schedules.</p>
|
||
<p>Stored in reducer-scheduling tables as a column.</p></div></article><nav class="docusaurus-mt-lg pagination-nav" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/modules/c-sharp/quickstart"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">C# Quickstart</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/sdks"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Overview</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="#overview" class="table-of-contents__link toc-highlight">Overview</a></li><li><a href="#setup" class="table-of-contents__link toc-highlight">Setup</a></li><li><a href="#how-it-works" class="table-of-contents__link toc-highlight">How it works</a><ul><li><a href="#in-more-detail-publishing-a-module" class="table-of-contents__link toc-highlight">In More Detail: Publishing a Module</a></li></ul></li><li><a href="#tables" class="table-of-contents__link toc-highlight">Tables</a><ul><li><a href="#interface-itableview" class="table-of-contents__link toc-highlight">Interface <code>ITableView</code></a><ul><li><a href="#method-itableviewinsert" class="table-of-contents__link toc-highlight">Method <code>ITableView.Insert</code></a></li><li><a href="#method-itableviewdelete" class="table-of-contents__link toc-highlight">Method <code>ITableView.Delete</code></a></li><li><a href="#method-itableviewiter" class="table-of-contents__link toc-highlight">Method <code>ITableView.Iter</code></a></li><li><a href="#property-itableviewcount" class="table-of-contents__link toc-highlight">Property <code>ITableView.Count</code></a></li></ul></li><li><a href="#public-and-private-tables" class="table-of-contents__link toc-highlight">Public and Private Tables</a></li><li><a href="#unique-and-primary-key-columns" class="table-of-contents__link toc-highlight">Unique and Primary Key Columns</a></li><li><a href="#class-uniqueindex" class="table-of-contents__link toc-highlight">Class <code>UniqueIndex</code></a><ul><li><a href="#method-uniqueindexfind" class="table-of-contents__link toc-highlight">Method <code>UniqueIndex.Find</code></a></li><li><a href="#method-uniqueindexupdate" class="table-of-contents__link toc-highlight">Method <code>UniqueIndex.Update</code></a></li><li><a href="#method-uniqueindexdelete" class="table-of-contents__link toc-highlight">Method <code>UniqueIndex.Delete</code></a></li></ul></li><li><a href="#auto-inc-columns" class="table-of-contents__link toc-highlight">Auto-inc columns</a></li><li><a href="#indexes" class="table-of-contents__link toc-highlight">Indexes</a></li><li><a href="#indexable-types" class="table-of-contents__link toc-highlight">Indexable Types</a></li><li><a href="#class-index" class="table-of-contents__link toc-highlight">Class <code>Index</code></a><ul><li><a href="#method-indexfilter" class="table-of-contents__link toc-highlight">Method <code>Index.Filter</code></a></li><li><a href="#method-indexdelete" class="table-of-contents__link toc-highlight">Method <code>Index.Delete</code></a></li></ul></li></ul></li><li><a href="#reducers" class="table-of-contents__link toc-highlight">Reducers</a><ul><li><a href="#class-reducercontext" class="table-of-contents__link toc-highlight">Class <code>ReducerContext</code></a><ul><li><a href="#property-reducercontextdb" class="table-of-contents__link toc-highlight">Property <code>ReducerContext.Db</code></a></li><li><a href="#property-reducercontextsender" class="table-of-contents__link toc-highlight">Property <code>ReducerContext.Sender</code></a></li><li><a href="#property-reducercontextconnectionid" class="table-of-contents__link toc-highlight">Property <code>ReducerContext.ConnectionId</code></a></li><li><a href="#property-reducercontextrng" class="table-of-contents__link toc-highlight">Property <code>ReducerContext.Rng</code></a></li><li><a href="#property-reducercontexttimestamp" class="table-of-contents__link toc-highlight">Property <code>ReducerContext.Timestamp</code></a></li><li><a href="#property-reducercontextidentity" class="table-of-contents__link toc-highlight">Property <code>ReducerContext.Identity</code></a></li></ul></li><li><a href="#lifecycle-reducers" class="table-of-contents__link toc-highlight">Lifecycle Reducers</a><ul><li><a href="#the-init-reducer" class="table-of-contents__link toc-highlight">The <code>Init</code> reducer</a></li><li><a href="#the-clientconnected-reducer" class="table-of-contents__link toc-highlight">The <code>ClientConnected</code> reducer</a></li><li><a href="#the-clientdisconnected-reducer" class="table-of-contents__link toc-highlight">The <code>ClientDisconnected</code> reducer</a></li></ul></li><li><a href="#scheduled-reducers" class="table-of-contents__link toc-highlight">Scheduled Reducers</a><ul><li><a href="#restricting-scheduled-reducers" class="table-of-contents__link toc-highlight">Restricting scheduled reducers</a></li></ul></li></ul></li><li><a href="#automatic-migrations" class="table-of-contents__link toc-highlight">Automatic migrations</a></li><li><a href="#other-infrastructure" class="table-of-contents__link toc-highlight">Other infrastructure</a><ul><li><a href="#class-log" class="table-of-contents__link toc-highlight">Class <code>Log</code></a></li><li><a href="#attribute-spacetimedbtype" class="table-of-contents__link toc-highlight">Attribute <code>[SpacetimeDB.Type]</code></a></li><li><a href="#struct-identity" class="table-of-contents__link toc-highlight">Struct <code>Identity</code></a></li><li><a href="#struct-connectionid" class="table-of-contents__link toc-highlight">Struct <code>ConnectionId</code></a></li><li><a href="#struct-timestamp" class="table-of-contents__link toc-highlight">Struct <code>Timestamp</code></a><ul><li><a href="#property-timestampmicrosecondssinceunixepoch" class="table-of-contents__link toc-highlight">Property <code>Timestamp.MicrosecondsSinceUnixEpoch</code></a></li><li><a href="#conversion-tofrom-datetimeoffset" class="table-of-contents__link toc-highlight">Conversion to/from <code>DateTimeOffset</code></a></li><li><a href="#static-property-timestampunix_epoch" class="table-of-contents__link toc-highlight">Static property <code>Timestamp.UNIX_EPOCH</code></a></li><li><a href="#method-timestamptimedurationsince" class="table-of-contents__link toc-highlight">Method <code>Timestamp.TimeDurationSince</code></a></li><li><a href="#operator-timestamp" class="table-of-contents__link toc-highlight">Operator <code>Timestamp.+</code></a></li><li><a href="#method-timestampcompareto" class="table-of-contents__link toc-highlight">Method <code>Timestamp.CompareTo</code></a></li></ul></li><li><a href="#struct-timeduration" class="table-of-contents__link toc-highlight">Struct <code>TimeDuration</code></a><ul><li><a href="#property-timedurationmicroseconds" class="table-of-contents__link toc-highlight">Property <code>TimeDuration.Microseconds</code></a></li><li><a href="#conversion-tofrom-timespan" class="table-of-contents__link toc-highlight">Conversion to/from <code>TimeSpan</code></a></li><li><a href="#static-property-timedurationzero" class="table-of-contents__link toc-highlight">Static property <code>TimeDuration.ZERO</code></a></li></ul></li><li><a href="#record-taggedenum" class="table-of-contents__link toc-highlight">Record <code>TaggedEnum</code></a></li><li><a href="#record-scheduleat" class="table-of-contents__link toc-highlight">Record <code>ScheduleAt</code></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> |