@karmaniverous/entity-manager 5.0.8 → 5.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/FUNDING.yml +3 -0
- package/README.md +1 -2
- package/dist/cjs/BaseEntityClient/BaseEntityClient.js +28 -0
- package/dist/cjs/BaseQueryBuilder/BaseQueryBuilder.js +62 -0
- package/dist/cjs/EntityManager/EntityManager.js +131 -0
- package/dist/cjs/EntityManager/ParsedConfig.js +385 -0
- package/dist/cjs/EntityManager/addKeys.js +60 -0
- package/dist/cjs/EntityManager/createEntityManager.js +46 -0
- package/dist/cjs/EntityManager/decodeElement.js +46 -0
- package/dist/cjs/EntityManager/decodeGeneratedProperty.js +53 -0
- package/dist/cjs/EntityManager/dehydrateIndexItem.js +68 -0
- package/dist/cjs/EntityManager/dehydratePageKeyMap.js +93 -0
- package/dist/cjs/EntityManager/encodeElement.js +40 -0
- package/dist/cjs/EntityManager/encodeGeneratedProperty.js +55 -0
- package/dist/cjs/EntityManager/findIndexToken.js +10 -0
- package/dist/cjs/EntityManager/getHashKeySpace.js +89 -0
- package/dist/cjs/EntityManager/getIndexComponents.js +23 -0
- package/dist/cjs/EntityManager/getPrimaryKey.js +76 -0
- package/dist/cjs/EntityManager/getShardBump.js +24 -0
- package/dist/cjs/EntityManager/query.js +130 -0
- package/dist/cjs/EntityManager/rehydrateIndexItem.js +65 -0
- package/dist/cjs/EntityManager/rehydratePageKeyMap.js +103 -0
- package/dist/cjs/EntityManager/removeKeys.js +51 -0
- package/dist/cjs/EntityManager/unwrapIndex.js +59 -0
- package/dist/cjs/EntityManager/updateItemHashKey.js +79 -0
- package/dist/cjs/EntityManager/updateItemRangeKey.js +65 -0
- package/dist/cjs/EntityManager/validateEntityToken.js +17 -0
- package/dist/cjs/EntityManager/validateGeneratedProperty.js +23 -0
- package/dist/cjs/EntityManager/validateIndexToken.js +16 -0
- package/dist/cjs/EntityManager/validateTranscodedProperty.js +16 -0
- package/dist/cjs/index.js +15 -0
- package/dist/default/lib/EntityManager/EntityManager.js +46 -69
- package/dist/default/lib/EntityManager/PrivateEntityManager.js +44 -51
- package/dist/index.d.ts +1163 -0
- package/dist/mjs/BaseEntityClient/BaseEntityClient.js +26 -0
- package/dist/mjs/BaseQueryBuilder/BaseQueryBuilder.js +60 -0
- package/dist/mjs/EntityManager/EntityManager.js +129 -0
- package/dist/mjs/EntityManager/ParsedConfig.js +383 -0
- package/dist/mjs/EntityManager/addKeys.js +58 -0
- package/dist/mjs/EntityManager/createEntityManager.js +44 -0
- package/dist/mjs/EntityManager/decodeElement.js +44 -0
- package/dist/mjs/EntityManager/decodeGeneratedProperty.js +51 -0
- package/dist/mjs/EntityManager/dehydrateIndexItem.js +66 -0
- package/dist/mjs/EntityManager/dehydratePageKeyMap.js +91 -0
- package/dist/mjs/EntityManager/encodeElement.js +38 -0
- package/dist/mjs/EntityManager/encodeGeneratedProperty.js +53 -0
- package/dist/mjs/EntityManager/findIndexToken.js +8 -0
- package/dist/mjs/EntityManager/getHashKeySpace.js +87 -0
- package/dist/mjs/EntityManager/getIndexComponents.js +21 -0
- package/dist/mjs/EntityManager/getPrimaryKey.js +74 -0
- package/dist/mjs/EntityManager/getShardBump.js +22 -0
- package/dist/mjs/EntityManager/query.js +128 -0
- package/dist/mjs/EntityManager/rehydrateIndexItem.js +63 -0
- package/dist/mjs/EntityManager/rehydratePageKeyMap.js +101 -0
- package/dist/mjs/EntityManager/removeKeys.js +49 -0
- package/dist/mjs/EntityManager/unwrapIndex.js +57 -0
- package/dist/mjs/EntityManager/updateItemHashKey.js +77 -0
- package/dist/mjs/EntityManager/updateItemRangeKey.js +63 -0
- package/dist/mjs/EntityManager/validateEntityToken.js +15 -0
- package/dist/mjs/EntityManager/validateGeneratedProperty.js +21 -0
- package/dist/mjs/EntityManager/validateIndexToken.js +14 -0
- package/dist/mjs/EntityManager/validateTranscodedProperty.js +14 -0
- package/dist/mjs/index.js +5 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/hierarchy.js +1 -0
- package/docs/assets/highlight.css +99 -0
- package/docs/assets/icons.js +18 -0
- package/docs/assets/icons.svg +1 -0
- package/docs/assets/main.js +60 -0
- package/docs/assets/navigation.js +1 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1648 -0
- package/docs/classes/index.BaseEntityClient.html +124 -0
- package/docs/classes/index.BaseQueryBuilder.html +229 -0
- package/docs/classes/index.EntityManager.html +510 -0
- package/docs/documents/CHANGELOG.html +1432 -0
- package/docs/documents/guides_stan-assistant-guide.html +431 -0
- package/docs/functions/index.createEntityManager.html +60 -0
- package/docs/hierarchy.html +31 -0
- package/docs/index.html +212 -0
- package/docs/interfaces/index.BaseConfigMap.html +113 -0
- package/docs/interfaces/index.BaseEntityClientOptions.html +82 -0
- package/docs/interfaces/index.BaseQueryBuilderOptions.html +92 -0
- package/docs/interfaces/index.CapturedConfigMapFrom.html +126 -0
- package/docs/interfaces/index.ConfigInput.html +189 -0
- package/docs/interfaces/index.ParsedConfig.html +144 -0
- package/docs/interfaces/index.ParsedEntityConfig.html +91 -0
- package/docs/interfaces/index.ParsedGeneratedPropertiesConfig.html +67 -0
- package/docs/interfaces/index.ParsedIndexConfig.html +79 -0
- package/docs/interfaces/index.ParsedTranscoder.html +71 -0
- package/docs/interfaces/index.QueryOptions.html +180 -0
- package/docs/interfaces/index.QueryResult.html +91 -0
- package/docs/interfaces/index.ShardBump.html +79 -0
- package/docs/interfaces/index.ShardQueryResult.html +93 -0
- package/docs/modules/index.html +47 -0
- package/docs/modules.html +38 -0
- package/docs/sitemap.xml +263 -0
- package/docs/types/index.BaseKeyTokens.html +39 -0
- package/docs/types/index.Config.html +75 -0
- package/docs/types/index.ConfigMap.html +41 -0
- package/docs/types/index.ConfigOfClient.html +45 -0
- package/docs/types/index.EntitiesFromSchema.html +39 -0
- package/docs/types/index.EntityClientItemByToken.html +45 -0
- package/docs/types/index.EntityClientRecordByToken.html +43 -0
- package/docs/types/index.EntityItem.html +41 -0
- package/docs/types/index.EntityItemPartial.html +44 -0
- package/docs/types/index.EntityKey.html +40 -0
- package/docs/types/index.EntityOfToken.html +39 -0
- package/docs/types/index.EntityRecord.html +39 -0
- package/docs/types/index.EntityRecordPartial.html +40 -0
- package/docs/types/index.EntityToken.html +40 -0
- package/docs/types/index.FallbackIndexTokenSet.html +40 -0
- package/docs/types/index.HasIndexFor.html +43 -0
- package/docs/types/index.HashKeyFrom.html +38 -0
- package/docs/types/index.IndexComponentTokens.html +45 -0
- package/docs/types/index.IndexHashKeyOf.html +42 -0
- package/docs/types/index.IndexRangeKeyOf.html +41 -0
- package/docs/types/index.IndexTokensFrom.html +41 -0
- package/docs/types/index.IndexTokensOf.html +40 -0
- package/docs/types/index.KeysFrom.html +38 -0
- package/docs/types/index.PageKey.html +40 -0
- package/docs/types/index.PageKeyByIndex.html +46 -0
- package/docs/types/index.PresentIndexTokenSet.html +45 -0
- package/docs/types/index.Projected.html +39 -0
- package/docs/types/index.QueryBuilderQueryOptions.html +45 -0
- package/docs/types/index.QueryOptionsByCC.html +49 -0
- package/docs/types/index.QueryOptionsByCF.html +47 -0
- package/docs/types/index.RangeKeyFrom.html +38 -0
- package/docs/types/index.ShardQueryFunction.html +63 -0
- package/docs/types/index.ShardQueryMap.html +56 -0
- package/docs/types/index.ShardQueryMapByCC.html +49 -0
- package/docs/types/index.ShardQueryMapByCF.html +47 -0
- package/docs/types/index.ShardedKeysFrom.html +38 -0
- package/docs/types/index.StorageItem.html +42 -0
- package/docs/types/index.StorageRecord.html +40 -0
- package/docs/types/index.TranscodedPropertiesFrom.html +38 -0
- package/docs/types/index.UnshardedKeysFrom.html +38 -0
- package/docs/types/index.ValidateConfigMap.html +40 -0
- package/lib/EntityManager/PrivateEntityManager.js +4 -0
- package/package.json +6 -6
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>guides\stan-assistant-guide | @karmaniverous/entity-manager</title><meta name="description" content="Documentation for @karmaniverous/entity-manager"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar">
|
|
2
|
+
<div class="tsd-toolbar-contents container"><a href="https://github.com/karmaniverous/entity-manager" class="title">@karmaniverous/entity-manager</a>
|
|
3
|
+
<div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/>
|
|
4
|
+
<ul role="listbox" id="tsd-search-results"></ul>
|
|
5
|
+
<div id="tsd-search-status" aria-live="polite" aria-atomic="true">
|
|
6
|
+
<div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header>
|
|
7
|
+
<div class="container container-main">
|
|
8
|
+
<div class="col-content">
|
|
9
|
+
<div class="tsd-page-title">
|
|
10
|
+
<ul class="tsd-breadcrumb" aria-label="Breadcrumb">
|
|
11
|
+
<li><a href="" aria-current="page">guides\stan-assistant-guide</a></li></ul></div>
|
|
12
|
+
<div class="tsd-panel tsd-typography"><h1 id="stan-assistant-guide-" class="tsd-anchor-link">STAN Assistant Guide — <code>@karmaniverous/entity-manager</code><a href="#stan-assistant-guide-" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h1>
|
|
13
|
+
<p>This guide is written for STAN assistants working in codebases that use <strong>Entity Manager</strong>. It is intended to be self-contained: it explains the library’s runtime model, configuration rules, and the type-level contracts you must satisfy when integrating a provider (e.g., DynamoDB) or writing app code.</p>
|
|
14
|
+
<p>Entity Manager is provider-agnostic: it does <strong>not</strong> talk to your database. Instead it:</p>
|
|
15
|
+
<ul>
|
|
16
|
+
<li>Generates and maintains key fields and other generated properties from config (<code>addKeys</code>, <code>getPrimaryKey</code>, <code>removeKeys</code>).</li>
|
|
17
|
+
<li>Encodes/decodes generated properties via transcodes.</li>
|
|
18
|
+
<li>Orchestrates parallel, cross-shard queries through injected shard query functions (<code>query</code>).</li>
|
|
19
|
+
<li>Dehydrates/rehydrates cross-shard page keys into a single compact token (<code>pageKeyMap</code>).</li>
|
|
20
|
+
</ul>
|
|
21
|
+
<hr>
|
|
22
|
+
<h2 id="acronyms-used-in-generics-local-glossary" class="tsd-anchor-link">Acronyms used in generics (local glossary)<a href="#acronyms-used-in-generics-local-glossary" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
23
|
+
<p>This repo uses a strict generic-parameter dictionary. In this guide, acronyms appear primarily in generic type parameters.</p>
|
|
24
|
+
<ul>
|
|
25
|
+
<li>Captured config map (<strong>CC</strong>): the config-derived type map used across the library.</li>
|
|
26
|
+
<li>Values-first config literal (<strong>CF</strong>): the literal config type captured at construction time (type-only “phantom” generic).</li>
|
|
27
|
+
<li>Entity token (<strong>ET</strong>): a union of entity names (keys of the configured entity map).</li>
|
|
28
|
+
<li>Index token (<strong>IT</strong>): a union of index names (keys of <code>config.indexes</code>).</li>
|
|
29
|
+
<li>Index token subset (<strong>ITS</strong>): a subset union of index tokens used in a given query/map.</li>
|
|
30
|
+
<li>Projection tuple (<strong>K</strong>): a type-only channel representing projected attribute keys (e.g., <code>const attrs = ['userId'] as const</code>).</li>
|
|
31
|
+
</ul>
|
|
32
|
+
<hr>
|
|
33
|
+
<h2 id="mental-model-runtime" class="tsd-anchor-link">Mental model (runtime)<a href="#mental-model-runtime" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
34
|
+
<h3 id="the-global-keys" class="tsd-anchor-link">The global keys<a href="#the-global-keys" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
35
|
+
<p>Entity Manager assumes a table with a <strong>global</strong> hash key and range key property name shared across all entity types:</p>
|
|
36
|
+
<ul>
|
|
37
|
+
<li><code>config.hashKey</code>: e.g. <code>"pk"</code> or <code>"hashKey2"</code>.</li>
|
|
38
|
+
<li><code>config.rangeKey</code>: e.g. <code>"sk"</code> or <code>"rangeKey"</code>.</li>
|
|
39
|
+
</ul>
|
|
40
|
+
<p>For each entity token:</p>
|
|
41
|
+
<ul>
|
|
42
|
+
<li><strong>Hash key value</strong> is <code>"<entityToken><shardKeyDelimiter><shardSuffix>"</code>, e.g. <code>user!0a</code>.
|
|
43
|
+
<ul>
|
|
44
|
+
<li>If the active shard bump has <code>chars === 0</code>, the suffix is empty: <code>user!</code>.</li>
|
|
45
|
+
</ul>
|
|
46
|
+
</li>
|
|
47
|
+
<li><strong>Range key value</strong> is <code>"<uniqueProperty><generatedValueDelimiter><uniqueValue>"</code>, e.g. <code>userId#abc123</code>.</li>
|
|
48
|
+
</ul>
|
|
49
|
+
<h3 id="sharding-shard-bumps" class="tsd-anchor-link">Sharding (“shard bumps”)<a href="#sharding-shard-bumps" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
50
|
+
<p>Each entity can define a time-based scale-up schedule via <code>shardBumps</code>:</p>
|
|
51
|
+
<pre><code class="ts"><span class="hl-1">{ </span><span class="hl-10">timestamp</span><span class="hl-1">: </span><span class="hl-6">number</span><span class="hl-1">; </span><span class="hl-10">charBits</span><span class="hl-1">: </span><span class="hl-8">1..5</span><span class="hl-1">; </span><span class="hl-10">chars</span><span class="hl-1">: </span><span class="hl-8">0..40</span><span class="hl-1"> }</span>
|
|
52
|
+
</code><button type="button">Copy</button></pre>
|
|
53
|
+
|
|
54
|
+
<ul>
|
|
55
|
+
<li>The applicable bump is chosen by <code>timestampProperty</code> on the item (e.g., <code>created</code>).</li>
|
|
56
|
+
<li><code>charBits</code> controls radix: <code>radix = 2 ** charBits</code>.</li>
|
|
57
|
+
<li><code>chars</code> controls width; full shard space is <code>radix ** chars</code>.</li>
|
|
58
|
+
<li>The shard suffix is computed deterministically from <code>uniqueProperty</code> (string-hash) modulo the full shard space.</li>
|
|
59
|
+
</ul>
|
|
60
|
+
<h3 id="generated-properties-index-helpers" class="tsd-anchor-link">Generated properties (index helpers)<a href="#generated-properties-index-helpers" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
61
|
+
<p>Generated properties are additional string-valued tokens used as index key components:</p>
|
|
62
|
+
<ul>
|
|
63
|
+
<li><strong>Sharded generated property</strong>:
|
|
64
|
+
<ul>
|
|
65
|
+
<li>Encoded format: <code>"<hashKeyValue>|k#v|k#v..."</code></li>
|
|
66
|
+
<li><strong>Atomic</strong>: if any required element is <code>null</code>/<code>undefined</code>, encoding returns <code>undefined</code>.</li>
|
|
67
|
+
<li>Used only on the hash-key side of an index (must be global hashKey or a sharded generated property).</li>
|
|
68
|
+
</ul>
|
|
69
|
+
</li>
|
|
70
|
+
<li><strong>Unsharded generated property</strong>:
|
|
71
|
+
<ul>
|
|
72
|
+
<li>Encoded format: <code>"k#v|k#v..."</code> (missing values become empty strings)</li>
|
|
73
|
+
<li>Used on the range-key side of an index.</li>
|
|
74
|
+
</ul>
|
|
75
|
+
</li>
|
|
76
|
+
</ul>
|
|
77
|
+
<h3 id="indexes" class="tsd-anchor-link">Indexes<a href="#indexes" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
78
|
+
<p><code>config.indexes</code> describes secondary index key <em>tokens</em> (not provider-specific index definitions):</p>
|
|
79
|
+
<pre><code class="ts"><span class="hl-10">indexes</span><span class="hl-1">: {</span><br/><span class="hl-1"> [</span><span class="hl-6">indexToken</span><span class="hl-1">]: {</span><br/><span class="hl-1"> </span><span class="hl-6">hashKey:</span><span class="hl-1"> </span><span class="hl-6">config</span><span class="hl-1">.</span><span class="hl-6">hashKey</span><span class="hl-1"> | </span><span class="hl-6">shardedGeneratedKey</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-6">rangeKey</span><span class="hl-1">: </span><span class="hl-6">config</span><span class="hl-1">.</span><span class="hl-6">rangeKey</span><span class="hl-1"> | </span><span class="hl-6">unshardedGeneratedKey</span><span class="hl-1"> | </span><span class="hl-6">transcodedProperty</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-6">projections</span><span class="hl-1">?: </span><span class="hl-6">string</span><span class="hl-1">[]; </span><span class="hl-3">// optional, validated (must not include key tokens)</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
|
|
80
|
+
</code><button type="button">Copy</button></pre>
|
|
81
|
+
|
|
82
|
+
<p>Entity Manager uses index definitions for:</p>
|
|
83
|
+
<ul>
|
|
84
|
+
<li>Determining page key <em>shape</em> per index (type narrowing with CF).</li>
|
|
85
|
+
<li>Rehydrating and dehydrating page keys.</li>
|
|
86
|
+
<li>Validating index tokens and finding an index token by (hashKeyToken, rangeKeyToken).</li>
|
|
87
|
+
</ul>
|
|
88
|
+
<hr>
|
|
89
|
+
<h2 id="values-first-configuration-and" class="tsd-anchor-link">Values-first configuration and <code>createEntityManager</code><a href="#values-first-configuration-and" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
90
|
+
<h3 id="preferred-construction-inference-first" class="tsd-anchor-link">Preferred construction (inference-first)<a href="#preferred-construction-inference-first" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
91
|
+
<p>Use <code>createEntityManager(config)</code> with a values-first config literal (<code>as const</code>) to capture tokens and index names:</p>
|
|
92
|
+
<pre><code class="ts"><span class="hl-5">import</span><span class="hl-1"> { </span><span class="hl-6">z</span><span class="hl-1"> } </span><span class="hl-5">from</span><span class="hl-1"> </span><span class="hl-2">'zod'</span><span class="hl-1">;</span><br/><span class="hl-5">import</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">createEntityManager</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">defaultTranscodes</span><span class="hl-1">,</span><br/><span class="hl-1">} </span><span class="hl-5">from</span><span class="hl-1"> </span><span class="hl-2">'@karmaniverous/entity-manager'</span><span class="hl-1">;</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">userSchema</span><span class="hl-1"> = </span><span class="hl-6">z</span><span class="hl-1">.</span><span class="hl-0">object</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-6">userId:</span><span class="hl-1"> </span><span class="hl-6">z</span><span class="hl-1">.</span><span class="hl-0">string</span><span class="hl-1">(),</span><br/><span class="hl-1"> </span><span class="hl-6">created:</span><span class="hl-1"> </span><span class="hl-6">z</span><span class="hl-1">.</span><span class="hl-0">number</span><span class="hl-1">(),</span><br/><span class="hl-1"> </span><span class="hl-6">firstNameCanonical:</span><span class="hl-1"> </span><span class="hl-6">z</span><span class="hl-1">.</span><span class="hl-0">string</span><span class="hl-1">(),</span><br/><span class="hl-1"> </span><span class="hl-6">lastNameCanonical:</span><span class="hl-1"> </span><span class="hl-6">z</span><span class="hl-1">.</span><span class="hl-0">string</span><span class="hl-1">(),</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">config</span><span class="hl-1"> = {</span><br/><span class="hl-1"> </span><span class="hl-6">hashKey:</span><span class="hl-1"> </span><span class="hl-2">'hashKey2'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">rangeKey:</span><span class="hl-1"> </span><span class="hl-2">'rangeKey'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">generatedProperties:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">sharded:</span><span class="hl-1"> { </span><span class="hl-6">userPK:</span><span class="hl-1"> [</span><span class="hl-2">'userId'</span><span class="hl-1">] </span><span class="hl-5">as</span><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-6">unsharded:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">firstNameRK:</span><span class="hl-1"> [</span><span class="hl-2">'firstNameCanonical'</span><span class="hl-1">, </span><span class="hl-2">'lastNameCanonical'</span><span class="hl-1">] </span><span class="hl-5">as</span><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-6">propertyTranscodes:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">userId:</span><span class="hl-1"> </span><span class="hl-2">'string'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">created:</span><span class="hl-1"> </span><span class="hl-2">'timestamp'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">firstNameCanonical:</span><span class="hl-1"> </span><span class="hl-2">'string'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">lastNameCanonical:</span><span class="hl-1"> </span><span class="hl-2">'string'</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-6">indexes:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">created:</span><span class="hl-1"> { </span><span class="hl-6">hashKey:</span><span class="hl-1"> </span><span class="hl-2">'hashKey2'</span><span class="hl-1">, </span><span class="hl-6">rangeKey:</span><span class="hl-1"> </span><span class="hl-2">'created'</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-6">firstName:</span><span class="hl-1"> { </span><span class="hl-6">hashKey:</span><span class="hl-1"> </span><span class="hl-2">'hashKey2'</span><span class="hl-1">, </span><span class="hl-6">rangeKey:</span><span class="hl-1"> </span><span class="hl-2">'firstNameRK'</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-6">userCreated:</span><span class="hl-1"> { </span><span class="hl-6">hashKey:</span><span class="hl-1"> </span><span class="hl-2">'userPK'</span><span class="hl-1">, </span><span class="hl-6">rangeKey:</span><span class="hl-1"> </span><span class="hl-2">'created'</span><span class="hl-1"> },</span><br/><span class="hl-1"> } </span><span class="hl-5">as</span><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">entities:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">user:</span><span class="hl-1"> { </span><span class="hl-6">uniqueProperty:</span><span class="hl-1"> </span><span class="hl-2">'userId'</span><span class="hl-1">, </span><span class="hl-6">timestampProperty:</span><span class="hl-1"> </span><span class="hl-2">'created'</span><span class="hl-1"> },</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-3">// compile-time shape capture only; stripped from runtime config</span><br/><span class="hl-1"> </span><span class="hl-6">entitiesSchema:</span><span class="hl-1"> { </span><span class="hl-6">user:</span><span class="hl-1"> </span><span class="hl-6">userSchema</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-6">transcodes:</span><span class="hl-1"> </span><span class="hl-6">defaultTranscodes</span><span class="hl-1">,</span><br/><span class="hl-1">} </span><span class="hl-5">as</span><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1">;</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">em</span><span class="hl-1"> = </span><span class="hl-0">createEntityManager</span><span class="hl-1">(</span><span class="hl-6">config</span><span class="hl-1">);</span>
|
|
93
|
+
</code><button type="button">Copy</button></pre>
|
|
94
|
+
|
|
95
|
+
<p>Notes:</p>
|
|
96
|
+
<ul>
|
|
97
|
+
<li><code>entitiesSchema</code> is compile-time only; the runtime config is still validated by Zod, and <code>entitiesSchema</code> is stripped before parsing.</li>
|
|
98
|
+
<li>Use <code>as const</code> (especially on <code>indexes</code> and generated property element arrays) to preserve literal unions.</li>
|
|
99
|
+
</ul>
|
|
100
|
+
<h3 id="runtime-config-validation-what-can-break-at-construction-time" class="tsd-anchor-link">Runtime config validation (what can break at construction time)<a href="#runtime-config-validation-what-can-break-at-construction-time" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
101
|
+
<p>The constructor parses config with Zod and rejects many mismatches, including:</p>
|
|
102
|
+
<ul>
|
|
103
|
+
<li>delimiter collisions (<code>generatedKeyDelimiter</code>, <code>generatedValueDelimiter</code>, <code>shardKeyDelimiter</code>)</li>
|
|
104
|
+
<li>key token collisions (hashKey/rangeKey vs generated keys vs transcoded properties)</li>
|
|
105
|
+
<li>generatedProperties elements not present in <code>propertyTranscodes</code></li>
|
|
106
|
+
<li>indexes with invalid hashKey/rangeKey tokens, duplicate hash/range pairs, or invalid projections</li>
|
|
107
|
+
<li>shard bump monotonicity errors</li>
|
|
108
|
+
</ul>
|
|
109
|
+
<p>If config parsing fails, treat it as a <strong>schema error</strong> and fix the config, not the code.</p>
|
|
110
|
+
<hr>
|
|
111
|
+
<h2 id="type-model-you-must-understand" class="tsd-anchor-link">Type model you must understand<a href="#type-model-you-must-understand" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
112
|
+
<h3 id="by-token-domain-vs-db-shapes" class="tsd-anchor-link">By-token domain vs DB shapes<a href="#by-token-domain-vs-db-shapes" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
113
|
+
<p>Entity Manager’s public item/record types are by-token (narrowed by entity token).</p>
|
|
114
|
+
<ul>
|
|
115
|
+
<li><code>EntityItem<CC, ET></code>
|
|
116
|
+
<ul>
|
|
117
|
+
<li>Domain-facing “full” shape for that entity token, plus optional key/token strings.</li>
|
|
118
|
+
</ul>
|
|
119
|
+
</li>
|
|
120
|
+
<li><code>EntityItemPartial<CC, ET, K = unknown></code>
|
|
121
|
+
<ul>
|
|
122
|
+
<li>Domain-facing projected/seed shape.</li>
|
|
123
|
+
<li>If <code>K</code> omitted: permissive partial.</li>
|
|
124
|
+
<li>If <code>K</code> provided: a <code>Pick<...></code> restricted to <code>K</code>.</li>
|
|
125
|
+
</ul>
|
|
126
|
+
</li>
|
|
127
|
+
<li><code>EntityRecord<CC, ET></code>
|
|
128
|
+
<ul>
|
|
129
|
+
<li>DB-facing record: required global hash/range keys + partial domain fields.</li>
|
|
130
|
+
</ul>
|
|
131
|
+
</li>
|
|
132
|
+
<li><code>EntityRecordPartial<CC, ET, K = unknown></code>
|
|
133
|
+
<ul>
|
|
134
|
+
<li>Projected DB record (Pick by <code>K</code>).</li>
|
|
135
|
+
</ul>
|
|
136
|
+
</li>
|
|
137
|
+
</ul>
|
|
138
|
+
<p>Token-agnostic storage helpers (exported for reference and advanced use):</p>
|
|
139
|
+
<ul>
|
|
140
|
+
<li><code>StorageItem<CC></code> / <code>StorageRecord<CC></code> (property-level, flattened across entities)</li>
|
|
141
|
+
</ul>
|
|
142
|
+
<h3 id="key-type" class="tsd-anchor-link">Key type<a href="#key-type" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
143
|
+
<ul>
|
|
144
|
+
<li><code>EntityKey<CC></code>: <code>Record<CC['HashKey'] | CC['RangeKey'], string></code></li>
|
|
145
|
+
</ul>
|
|
146
|
+
<h3 id="index-aware-page-keys-optional-cf-channel" class="tsd-anchor-link">Index-aware page keys (optional CF channel)<a href="#index-aware-page-keys-optional-cf-channel" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
147
|
+
<ul>
|
|
148
|
+
<li><code>PageKeyByIndex<CC, ET, IT, CF></code> narrows the page key object to only the key components for that index <strong>when CF carries <code>indexes</code></strong>.</li>
|
|
149
|
+
<li>Without CF, it falls back to the broader <code>PageKey<CC></code> shape.</li>
|
|
150
|
+
</ul>
|
|
151
|
+
<hr>
|
|
152
|
+
<h2 id="key-lifecycle-" class="tsd-anchor-link">Key lifecycle: <code>addKeys</code>, <code>removeKeys</code>, <code>getPrimaryKey</code><a href="#key-lifecycle-" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
153
|
+
<h3 id="_" class="tsd-anchor-link"><code>addKeys(entityToken, item, overwrite?)</code><a href="#_" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
154
|
+
<ul>
|
|
155
|
+
<li>Input: domain-ish partial item (<code>EntityItemPartial</code>).</li>
|
|
156
|
+
<li>Output: DB-ish record (<code>EntityRecordPartial</code>) with:
|
|
157
|
+
<ul>
|
|
158
|
+
<li>global hash/range keys set (unless already present and <code>overwrite=false</code>)</li>
|
|
159
|
+
<li>generated properties updated based on overwrite rules</li>
|
|
160
|
+
</ul>
|
|
161
|
+
</li>
|
|
162
|
+
</ul>
|
|
163
|
+
<p>Use it before writes.</p>
|
|
164
|
+
<pre><code class="ts"><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">record</span><span class="hl-1"> = </span><span class="hl-6">em</span><span class="hl-1">.</span><span class="hl-0">addKeys</span><span class="hl-1">(</span><span class="hl-2">'user'</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-6">userId:</span><span class="hl-1"> </span><span class="hl-2">'u1'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">created:</span><span class="hl-1"> </span><span class="hl-6">Date</span><span class="hl-1">.</span><span class="hl-0">now</span><span class="hl-1">(),</span><br/><span class="hl-1"> </span><span class="hl-6">firstNameCanonical:</span><span class="hl-1"> </span><span class="hl-2">'lee'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">lastNameCanonical:</span><span class="hl-1"> </span><span class="hl-2">'zhang'</span><span class="hl-1">,</span><br/><span class="hl-1">});</span><br/><span class="hl-3">// record.hashKey2 and record.rangeKey are present (strings)</span>
|
|
165
|
+
</code><button type="button">Copy</button></pre>
|
|
166
|
+
|
|
167
|
+
<h3 id="_-1" class="tsd-anchor-link"><code>removeKeys(entityToken, recordOrRecords)</code><a href="#_-1" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
168
|
+
<ul>
|
|
169
|
+
<li>Strips global keys and generated property tokens from a DB record.</li>
|
|
170
|
+
<li>Overloads preserve projected-vs-strict behavior:
|
|
171
|
+
<ul>
|
|
172
|
+
<li>Strict <code>EntityRecord</code> input yields strict <code>EntityItem</code> output.</li>
|
|
173
|
+
<li>Projected <code>EntityRecordPartial<..., K></code> yields <code>EntityItemPartial<..., K></code>.</li>
|
|
174
|
+
</ul>
|
|
175
|
+
</li>
|
|
176
|
+
</ul>
|
|
177
|
+
<p>Use it after reads if your app layer should not see storage keys.</p>
|
|
178
|
+
<h3 id="_-2" class="tsd-anchor-link"><code>getPrimaryKey(entityToken, itemOrItems, overwrite?)</code><a href="#_-2" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
179
|
+
<ul>
|
|
180
|
+
<li>Always returns an array of keys (<code>EntityKey<CC>[]</code>).</li>
|
|
181
|
+
<li>Behavior:
|
|
182
|
+
<ul>
|
|
183
|
+
<li>If both keys exist and <code>overwrite=false</code>, returns exactly that pair.</li>
|
|
184
|
+
<li>Otherwise computes <code>rangeKey</code> from <code>uniqueProperty</code>.</li>
|
|
185
|
+
<li>If <code>timestampProperty</code> is present, computes exactly one hash key.</li>
|
|
186
|
+
<li>If <code>timestampProperty</code> is missing, enumerates hash key space across bumps (deterministic per bump if <code>uniqueProperty</code> is present).</li>
|
|
187
|
+
</ul>
|
|
188
|
+
</li>
|
|
189
|
+
</ul>
|
|
190
|
+
<p>Use it to generate keys for point reads / batch reads.</p>
|
|
191
|
+
<hr>
|
|
192
|
+
<h2 id="query-orchestration-what-does" class="tsd-anchor-link">Query orchestration: what <code>EntityManager.query()</code> does<a href="#query-orchestration-what-does" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
193
|
+
<p>Entity Manager’s query API is <em>orchestration only</em>. You provide shard query functions (provider integration); it runs them across shards and indexes and merges results.</p>
|
|
194
|
+
<h3 id="your-responsibility-implement" class="tsd-anchor-link">Your responsibility: implement <code>ShardQueryFunction</code><a href="#your-responsibility-implement" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
195
|
+
<p><code>ShardQueryFunction<CC, ET, IT, CF, K></code> is:</p>
|
|
196
|
+
<pre><code class="ts"><span class="hl-1">(</span><span class="hl-6">hashKey</span><span class="hl-1">: </span><span class="hl-9">string</span><span class="hl-1">, </span><span class="hl-6">pageKey</span><span class="hl-1">?: </span><span class="hl-9">PageKeyByIndex</span><span class="hl-1"><...>, </span><span class="hl-6">pageSize</span><span class="hl-1">?: </span><span class="hl-9">number</span><span class="hl-1">)</span><br/><span class="hl-1"> </span><span class="hl-4">=></span><span class="hl-1"> </span><span class="hl-9">Promise</span><span class="hl-1"><{ </span><span class="hl-10">count</span><span class="hl-1">: </span><span class="hl-6">number</span><span class="hl-1">; </span><span class="hl-10">items</span><span class="hl-1">: </span><span class="hl-6">EntityItemPartial</span><span class="hl-1"><</span><span class="hl-7">CC</span><span class="hl-1">, </span><span class="hl-7">ET</span><span class="hl-1">, </span><span class="hl-7">K</span><span class="hl-1">>[]; </span><span class="hl-6">pageKey</span><span class="hl-1">?: </span><span class="hl-6">PageKeyByIndex</span><span class="hl-1"><...> }></span>
|
|
197
|
+
</code><button type="button">Copy</button></pre>
|
|
198
|
+
|
|
199
|
+
<p>Rules for a correct implementation:</p>
|
|
200
|
+
<ul>
|
|
201
|
+
<li>Query <strong>exactly one shard</strong> (partition) per call using the provided <code>hashKey</code> value.</li>
|
|
202
|
+
<li>Query <strong>exactly one index</strong> per function (the map key tells you which index you’re implementing).</li>
|
|
203
|
+
<li>Respect <code>pageKey</code> and <code>pageSize</code> as “resume token” and per-shard page size.</li>
|
|
204
|
+
<li>Return <code>pageKey: undefined</code> when that shard/index is exhausted.</li>
|
|
205
|
+
</ul>
|
|
206
|
+
<h3 id="orchestration-behavior-library-responsibility" class="tsd-anchor-link">Orchestration behavior (library responsibility)<a href="#orchestration-behavior-library-responsibility" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
207
|
+
<p>When you call <code>em.query(options)</code>:</p>
|
|
208
|
+
<ul>
|
|
209
|
+
<li>It rehydrates the (possibly compressed) <code>pageKeyMap</code> into a 2-layer structure:
|
|
210
|
+
<ul>
|
|
211
|
+
<li><code>indexToken -> hashKeyValue -> pageKey | undefined</code></li>
|
|
212
|
+
</ul>
|
|
213
|
+
</li>
|
|
214
|
+
<li>It enumerates shard hash key space for the given <code>entityToken</code>, <code>hashKeyToken</code>, and <code>[timestampFrom, timestampTo]</code>.</li>
|
|
215
|
+
<li>It runs all shard queries in parallel (bounded by <code>throttle</code>).</li>
|
|
216
|
+
<li>It repeats shard querying until:
|
|
217
|
+
<ul>
|
|
218
|
+
<li>all shards return <code>pageKey === undefined</code> (no pages remain), or</li>
|
|
219
|
+
<li>the accumulated item count reaches <code>limit</code> (note: fan-out can exceed <code>limit</code>).</li>
|
|
220
|
+
</ul>
|
|
221
|
+
</li>
|
|
222
|
+
<li>It dedupes by <code>uniqueProperty</code> and sorts by <code>sortOrder</code>.</li>
|
|
223
|
+
<li>It dehydrates + compresses the updated page-key map into a single string token (<code>result.pageKeyMap</code>) you pass into the next call.</li>
|
|
224
|
+
</ul>
|
|
225
|
+
<h3 id="fields-you-must-understand" class="tsd-anchor-link"><code>QueryOptions</code> fields you must understand<a href="#fields-you-must-understand" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
226
|
+
<p>Key options:</p>
|
|
227
|
+
<ul>
|
|
228
|
+
<li><code>entityToken</code>: selects entity config (uniqueProperty, timestampProperty, shard bumps, defaults).</li>
|
|
229
|
+
<li><code>item</code>: a partial item used to generate alternate hash key spaces (if needed); may be <code>{}</code> for global hash key indexes.</li>
|
|
230
|
+
<li><code>shardQueryMap</code>: map of <code>indexToken -> ShardQueryFunction</code> (single- or multi-index).</li>
|
|
231
|
+
<li><code>pageKeyMap?: string</code>: the returned token from a prior query call.</li>
|
|
232
|
+
<li><code>limit?: number | Infinity</code>: target maximum total items across shards (positive int or Infinity).</li>
|
|
233
|
+
<li><code>pageSize?: number</code>: max per-shard page size (positive int).</li>
|
|
234
|
+
<li><code>timestampFrom?: number</code>, <code>timestampTo?: number</code>: bounds which shard bumps/shards are queried.</li>
|
|
235
|
+
<li><code>sortOrder?: SortOrder<...></code>: used after merge/dedupe.</li>
|
|
236
|
+
<li><code>throttle?: number</code>: max shard queries in flight.</li>
|
|
237
|
+
</ul>
|
|
238
|
+
<h3 id="minimal-multi-index-example-provider-agnostic" class="tsd-anchor-link">Minimal multi-index example (provider-agnostic)<a href="#minimal-multi-index-example-provider-agnostic" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
239
|
+
<pre><code class="ts"><span class="hl-5">import</span><span class="hl-1"> </span><span class="hl-5">type</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">QueryOptionsByCF</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">ShardQueryFunction</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">ShardQueryMapByCF</span><span class="hl-1">,</span><br/><span class="hl-1">} </span><span class="hl-5">from</span><span class="hl-1"> </span><span class="hl-2">'@karmaniverous/entity-manager'</span><span class="hl-1">;</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">cf</span><span class="hl-1"> = {</span><br/><span class="hl-1"> </span><span class="hl-6">indexes:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">firstName:</span><span class="hl-1"> { </span><span class="hl-6">hashKey:</span><span class="hl-1"> </span><span class="hl-2">'hashKey2'</span><span class="hl-1">, </span><span class="hl-6">rangeKey:</span><span class="hl-1"> </span><span class="hl-2">'firstNameRK'</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-6">lastName:</span><span class="hl-1"> { </span><span class="hl-6">hashKey:</span><span class="hl-1"> </span><span class="hl-2">'hashKey2'</span><span class="hl-1">, </span><span class="hl-6">rangeKey:</span><span class="hl-1"> </span><span class="hl-2">'lastNameRK'</span><span class="hl-1"> },</span><br/><span class="hl-1"> },</span><br/><span class="hl-1">} </span><span class="hl-5">as</span><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1">;</span><br/><span class="hl-4">type</span><span class="hl-1"> </span><span class="hl-9">CF</span><span class="hl-1"> = </span><span class="hl-4">typeof</span><span class="hl-1"> </span><span class="hl-6">cf</span><span class="hl-1">;</span><br/><br/><span class="hl-4">type</span><span class="hl-1"> </span><span class="hl-9">CC</span><span class="hl-1"> = </span><span class="hl-3">/* your ConfigMap<...> */</span><span class="hl-1">;</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">firstNameSQF</span><span class="hl-1">: </span><span class="hl-9">ShardQueryFunction</span><span class="hl-1"><</span><span class="hl-9">CC</span><span class="hl-1">, </span><span class="hl-2">'user'</span><span class="hl-1">, </span><span class="hl-2">'firstName'</span><span class="hl-1">, </span><span class="hl-9">CF</span><span class="hl-1">> =</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> (</span><span class="hl-6">hashKey</span><span class="hl-1">, </span><span class="hl-6">pageKey</span><span class="hl-1">, </span><span class="hl-6">pageSize</span><span class="hl-1">) </span><span class="hl-4">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">// provider-specific query here</span><br/><span class="hl-1"> </span><span class="hl-5">return</span><span class="hl-1"> { </span><span class="hl-6">count:</span><span class="hl-1"> </span><span class="hl-8">0</span><span class="hl-1">, </span><span class="hl-6">items:</span><span class="hl-1"> [], </span><span class="hl-6">pageKey</span><span class="hl-1"> };</span><br/><span class="hl-1"> };</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">lastNameSQF</span><span class="hl-1">: </span><span class="hl-9">ShardQueryFunction</span><span class="hl-1"><</span><span class="hl-9">CC</span><span class="hl-1">, </span><span class="hl-2">'user'</span><span class="hl-1">, </span><span class="hl-2">'lastName'</span><span class="hl-1">, </span><span class="hl-9">CF</span><span class="hl-1">> =</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> (</span><span class="hl-6">hashKey</span><span class="hl-1">, </span><span class="hl-6">pageKey</span><span class="hl-1">, </span><span class="hl-6">pageSize</span><span class="hl-1">) </span><span class="hl-4">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">return</span><span class="hl-1"> { </span><span class="hl-6">count:</span><span class="hl-1"> </span><span class="hl-8">0</span><span class="hl-1">, </span><span class="hl-6">items:</span><span class="hl-1"> [], </span><span class="hl-6">pageKey</span><span class="hl-1"> };</span><br/><span class="hl-1"> };</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">shardQueryMap</span><span class="hl-1">: </span><span class="hl-9">ShardQueryMapByCF</span><span class="hl-1"><</span><span class="hl-9">CC</span><span class="hl-1">, </span><span class="hl-2">'user'</span><span class="hl-1">, </span><span class="hl-9">CF</span><span class="hl-1">> = {</span><br/><span class="hl-1"> </span><span class="hl-6">firstName:</span><span class="hl-1"> </span><span class="hl-6">firstNameSQF</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">lastName:</span><span class="hl-1"> </span><span class="hl-6">lastNameSQF</span><span class="hl-1">,</span><br/><span class="hl-1">};</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">options</span><span class="hl-1">: </span><span class="hl-9">QueryOptionsByCF</span><span class="hl-1"><</span><span class="hl-9">CC</span><span class="hl-1">, </span><span class="hl-2">'user'</span><span class="hl-1">, </span><span class="hl-9">CF</span><span class="hl-1">> = {</span><br/><span class="hl-1"> </span><span class="hl-6">entityToken:</span><span class="hl-1"> </span><span class="hl-2">'user'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">item:</span><span class="hl-1"> {},</span><br/><span class="hl-1"> </span><span class="hl-6">shardQueryMap</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">pageSize:</span><span class="hl-1"> </span><span class="hl-8">25</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">limit:</span><span class="hl-1"> </span><span class="hl-8">200</span><span class="hl-1">,</span><br/><span class="hl-1">};</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">result</span><span class="hl-1"> = </span><span class="hl-5">await</span><span class="hl-1"> </span><span class="hl-6">em</span><span class="hl-1">.</span><span class="hl-0">query</span><span class="hl-1">(</span><span class="hl-6">options</span><span class="hl-1">);</span><br/><span class="hl-3">// result.pageKeyMap is a compact token: pass it back into the next call</span>
|
|
240
|
+
</code><button type="button">Copy</button></pre>
|
|
241
|
+
|
|
242
|
+
<hr>
|
|
243
|
+
<h2 id="projection-type-only-k-and-adapter-responsibilities" class="tsd-anchor-link">Projection (type-only K) and adapter responsibilities<a href="#projection-type-only-k-and-adapter-responsibilities" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
244
|
+
<p><code>K</code> is a type-only way to express “I projected a subset of attributes at runtime”.</p>
|
|
245
|
+
<p>If you pass a projection tuple type through your shard query functions/options/results, then:</p>
|
|
246
|
+
<ul>
|
|
247
|
+
<li>Items become <code>Pick<EntityItem<...>, KeysFrom<K>>[]</code>.</li>
|
|
248
|
+
<li>Sort typing aligns to the projected shape.</li>
|
|
249
|
+
</ul>
|
|
250
|
+
<p>Example:</p>
|
|
251
|
+
<pre><code class="ts"><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">attrs</span><span class="hl-1"> = [</span><span class="hl-2">'userId'</span><span class="hl-1">, </span><span class="hl-2">'created'</span><span class="hl-1">] </span><span class="hl-5">as</span><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1">;</span><br/><span class="hl-4">type</span><span class="hl-1"> </span><span class="hl-9">K</span><span class="hl-1"> = </span><span class="hl-4">typeof</span><span class="hl-1"> </span><span class="hl-6">attrs</span><span class="hl-1">;</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-0">sqf</span><span class="hl-1">: </span><span class="hl-9">ShardQueryFunction</span><span class="hl-1"><</span><span class="hl-9">CC</span><span class="hl-1">, </span><span class="hl-2">'user'</span><span class="hl-1">, </span><span class="hl-2">'firstName'</span><span class="hl-1">, </span><span class="hl-9">CF</span><span class="hl-1">, </span><span class="hl-9">K</span><span class="hl-1">> = </span><span class="hl-4">async</span><span class="hl-1"> () </span><span class="hl-4">=></span><span class="hl-1"> ({</span><br/><span class="hl-1"> </span><span class="hl-6">count:</span><span class="hl-1"> </span><span class="hl-8">0</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">items:</span><span class="hl-1"> [],</span><br/><span class="hl-1">});</span>
|
|
252
|
+
</code><button type="button">Copy</button></pre>
|
|
253
|
+
|
|
254
|
+
<p>Critical invariant:</p>
|
|
255
|
+
<ul>
|
|
256
|
+
<li>Entity Manager dedupes by <code>uniqueProperty</code> and sorts by <code>sortOrder</code>.</li>
|
|
257
|
+
<li>If your adapter uses projections at runtime, it should auto-include:
|
|
258
|
+
<ul>
|
|
259
|
+
<li>the entity’s <code>uniqueProperty</code>, and</li>
|
|
260
|
+
<li>any attributes used by the sort order,
|
|
261
|
+
even if the caller omitted them from the projection tuple.</li>
|
|
262
|
+
</ul>
|
|
263
|
+
</li>
|
|
264
|
+
</ul>
|
|
265
|
+
<p>Otherwise, runtime dedupe/sort may be incorrect.</p>
|
|
266
|
+
<hr>
|
|
267
|
+
<h2 id="index-token-inference-and-narrowing-patterns" class="tsd-anchor-link">Index token inference and narrowing patterns<a href="#index-token-inference-and-narrowing-patterns" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
268
|
+
<p>Entity Manager supports two complementary inference routes:</p>
|
|
269
|
+
<h3 id="cf-route-values-first-config-literal" class="tsd-anchor-link">CF route (values-first config literal)<a href="#cf-route-values-first-config-literal" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
270
|
+
<p>If you have a literal like:</p>
|
|
271
|
+
<pre><code class="ts"><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-7">cf</span><span class="hl-1"> = { </span><span class="hl-6">indexes:</span><span class="hl-1"> { </span><span class="hl-6">firstName:</span><span class="hl-1"> {...}, </span><span class="hl-6">lastName:</span><span class="hl-1"> {...} } } </span><span class="hl-5">as</span><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1">;</span>
|
|
272
|
+
</code><button type="button">Copy</button></pre>
|
|
273
|
+
|
|
274
|
+
<p>Then:</p>
|
|
275
|
+
<ul>
|
|
276
|
+
<li><code>IndexTokensOf<typeof cf></code> becomes <code>'firstName' | 'lastName'</code></li>
|
|
277
|
+
<li><code>ShardQueryMapByCF<..., typeof cf></code> only allows those keys</li>
|
|
278
|
+
<li><code>PageKeyByIndex<..., 'firstName', typeof cf></code> narrows the page key shape to that index’s components</li>
|
|
279
|
+
</ul>
|
|
280
|
+
<h3 id="cc-route-captured-config-type" class="tsd-anchor-link">CC route (captured config type)<a href="#cc-route-captured-config-type" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
281
|
+
<p>If you want ITS derived from a captured config literal type (commonly your config value type):</p>
|
|
282
|
+
<ul>
|
|
283
|
+
<li><code>ShardQueryMapByCC<CCMap, ET, CCLiteral></code></li>
|
|
284
|
+
<li><code>QueryOptionsByCC<CCMap, ET, CCLiteral></code></li>
|
|
285
|
+
</ul>
|
|
286
|
+
<p>These derive ITS from <code>IndexTokensFrom<CCLiteral></code> and pass <code>CCLiteral</code> through the CF channel for page-key narrowing.</p>
|
|
287
|
+
<h3 id="convenience" class="tsd-anchor-link"><code>findIndexToken</code> convenience<a href="#convenience" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
288
|
+
<p><code>EntityManager.findIndexToken(hashKeyToken, rangeKeyToken, suppressError?)</code> returns an index token, and when the manager was constructed with a values-first config literal, its return type narrows to <code>IndexTokensOf<CF></code>.</p>
|
|
289
|
+
<hr>
|
|
290
|
+
<h2 id="adapter-building-blocks-shipped-in-this-package" class="tsd-anchor-link">Adapter building blocks shipped in this package<a href="#adapter-building-blocks-shipped-in-this-package" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
291
|
+
<p>This package includes abstract helpers meant for provider adapters.</p>
|
|
292
|
+
<h3 id="_-3" class="tsd-anchor-link"><code>BaseEntityClient</code><a href="#_-3" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
293
|
+
<ul>
|
|
294
|
+
<li>Owns an <code>entityManager</code> and a <code>logger</code> (<code>debug</code>/<code>error</code>).</li>
|
|
295
|
+
<li>Holds optional <code>batchProcessOptions</code> (used by downstream adapters).</li>
|
|
296
|
+
</ul>
|
|
297
|
+
<h3 id="_-4" class="tsd-anchor-link"><code>BaseQueryBuilder</code><a href="#_-4" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
298
|
+
<p><code>BaseQueryBuilder</code> helps adapters construct a <code>ShardQueryMap</code> fluently while keeping the provider-specific logic inside <code>getShardQueryFunction(indexToken)</code>.</p>
|
|
299
|
+
<p>Key points:</p>
|
|
300
|
+
<ul>
|
|
301
|
+
<li>You define an <code>IndexParams</code> type (your per-index mutable query state).</li>
|
|
302
|
+
<li>The builder maintains <code>indexParamsMap: Record<ITS, IndexParams></code>.</li>
|
|
303
|
+
<li><code>build()</code> returns a <code>ShardQueryMap</code> by mapping index tokens to shard query functions.</li>
|
|
304
|
+
<li><code>query()</code> forwards to <code>entityManager.query(...)</code> with the builder’s <code>pageKeyMap</code> and built shardQueryMap.</li>
|
|
305
|
+
</ul>
|
|
306
|
+
<p>The shared query options type for builder <code>query()</code> is:</p>
|
|
307
|
+
<ul>
|
|
308
|
+
<li><code>QueryBuilderQueryOptions<CC, ET, CF></code> = <code>QueryOptions</code> minus <code>entityToken</code>, <code>pageKeyMap</code>, <code>shardQueryMap</code>.</li>
|
|
309
|
+
</ul>
|
|
310
|
+
<hr>
|
|
311
|
+
<h2 id="common-failure-modes-debug-checklist" class="tsd-anchor-link">Common failure modes (debug checklist)<a href="#common-failure-modes-debug-checklist" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
312
|
+
<p>When queries behave unexpectedly, check:</p>
|
|
313
|
+
<ul>
|
|
314
|
+
<li>Config validity:
|
|
315
|
+
<ul>
|
|
316
|
+
<li><code>propertyTranscodes</code> includes every property referenced by generated properties.</li>
|
|
317
|
+
<li>Index hashKey token is global hashKey or a <em>sharded</em> generated key.</li>
|
|
318
|
+
<li>Index rangeKey token is global rangeKey or an <em>unsharded</em> generated key or a transcoded scalar.</li>
|
|
319
|
+
</ul>
|
|
320
|
+
</li>
|
|
321
|
+
<li>Shard query function correctness:
|
|
322
|
+
<ul>
|
|
323
|
+
<li>You used the passed <code>hashKey</code> value as the partition key value.</li>
|
|
324
|
+
<li>You mapped <code>pageKey</code> into provider pagination correctly.</li>
|
|
325
|
+
<li>You return <code>pageKey: undefined</code> when exhausted.</li>
|
|
326
|
+
</ul>
|
|
327
|
+
</li>
|
|
328
|
+
<li>Paging token handling:
|
|
329
|
+
<ul>
|
|
330
|
+
<li>You treat <code>result.pageKeyMap</code> as an opaque token and pass it unchanged.</li>
|
|
331
|
+
<li>You keep the same set of index tokens between query calls (same shardQueryMap keys); otherwise pageKeyMap validation will fail.</li>
|
|
332
|
+
</ul>
|
|
333
|
+
</li>
|
|
334
|
+
<li>Projection invariants:
|
|
335
|
+
<ul>
|
|
336
|
+
<li>If using projections, your adapter auto-included uniqueProperty and sort keys at runtime.</li>
|
|
337
|
+
</ul>
|
|
338
|
+
</li>
|
|
339
|
+
<li>“limit” expectations:
|
|
340
|
+
<ul>
|
|
341
|
+
<li><code>limit</code> is a target cap across all shards. Fan-out may overshoot because it queries shards in batches of <code>pageSize</code>.</li>
|
|
342
|
+
</ul>
|
|
343
|
+
</li>
|
|
344
|
+
</ul>
|
|
345
|
+
<hr>
|
|
346
|
+
<h2 id="what-stan-assistants-should-do-when-editing-code-that-uses-entity-manager" class="tsd-anchor-link">What STAN assistants should do when editing code that uses Entity Manager<a href="#what-stan-assistants-should-do-when-editing-code-that-uses-entity-manager" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
347
|
+
<ul>
|
|
348
|
+
<li>Prefer values-first configs (<code>as const</code>) and avoid broad annotations that widen literal unions.</li>
|
|
349
|
+
<li>Keep providers thin:
|
|
350
|
+
<ul>
|
|
351
|
+
<li>put orchestration in Entity Manager,</li>
|
|
352
|
+
<li>put provider query details in the shard query functions or adapter helpers.</li>
|
|
353
|
+
</ul>
|
|
354
|
+
</li>
|
|
355
|
+
<li>When you add a projection feature in an adapter, implement the auto-include policy for uniqueProperty and explicit sort keys.</li>
|
|
356
|
+
<li>When you add a new index token, update:
|
|
357
|
+
<ul>
|
|
358
|
+
<li>config indexes,</li>
|
|
359
|
+
<li>any adapter query builder maps/condition helpers that assume specific index names,</li>
|
|
360
|
+
<li>tests that validate page key narrowing or index token unions.</li>
|
|
361
|
+
</ul>
|
|
362
|
+
</li>
|
|
363
|
+
</ul>
|
|
364
|
+
<p>That’s the full contract: if your shard query functions behave like “query one shard page”, Entity Manager can do the rest.</p>
|
|
365
|
+
</div></div>
|
|
366
|
+
<div class="col-sidebar">
|
|
367
|
+
<div class="page-menu">
|
|
368
|
+
<div class="tsd-navigation settings">
|
|
369
|
+
<details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>
|
|
370
|
+
<h3>Settings</h3></summary>
|
|
371
|
+
<div class="tsd-accordion-details">
|
|
372
|
+
<div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span>
|
|
373
|
+
<ul id="tsd-filter-options">
|
|
374
|
+
<li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li></ul></div>
|
|
375
|
+
<div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div>
|
|
376
|
+
<details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>
|
|
377
|
+
<h3>On This Page</h3></summary>
|
|
378
|
+
<div class="tsd-accordion-details"><a href="#stan-assistant-guide-"><span>STAN <wbr/>Assistant <wbr/>Guide — </span></a>
|
|
379
|
+
<ul>
|
|
380
|
+
<li><a href="#acronyms-used-in-generics-local-glossary"><span>Acronyms used in generics (local glossary)</span></a></li>
|
|
381
|
+
<li><a href="#mental-model-runtime"><span>Mental model (runtime)</span></a></li>
|
|
382
|
+
<li>
|
|
383
|
+
<ul>
|
|
384
|
+
<li><a href="#the-global-keys"><span>The global keys</span></a></li>
|
|
385
|
+
<li><a href="#sharding-shard-bumps"><span>Sharding (“shard bumps”)</span></a></li>
|
|
386
|
+
<li><a href="#generated-properties-index-helpers"><span>Generated properties (index helpers)</span></a></li>
|
|
387
|
+
<li><a href="#indexes"><span>Indexes</span></a></li></ul></li>
|
|
388
|
+
<li><a href="#values-first-configuration-and"><span>Values-<wbr/>first configuration and </span></a></li>
|
|
389
|
+
<li>
|
|
390
|
+
<ul>
|
|
391
|
+
<li><a href="#preferred-construction-inference-first"><span>Preferred construction (inference-<wbr/>first)</span></a></li>
|
|
392
|
+
<li><a href="#runtime-config-validation-what-can-break-at-construction-time"><span>Runtime config validation (what can break at construction time)</span></a></li></ul></li>
|
|
393
|
+
<li><a href="#type-model-you-must-understand"><span>Type model you must understand</span></a></li>
|
|
394
|
+
<li>
|
|
395
|
+
<ul>
|
|
396
|
+
<li><a href="#by-token-domain-vs-db-shapes"><span>By-<wbr/>token domain vs <wbr/>DB shapes</span></a></li>
|
|
397
|
+
<li><a href="#key-type"><span>Key type</span></a></li>
|
|
398
|
+
<li><a href="#index-aware-page-keys-optional-cf-channel"><span>Index-<wbr/>aware page keys (optional <wbr/>CF channel)</span></a></li></ul></li>
|
|
399
|
+
<li><a href="#key-lifecycle-"><span>Key lifecycle: , , </span></a></li>
|
|
400
|
+
<li>
|
|
401
|
+
<ul>
|
|
402
|
+
<li><a href="#_"><span></span></a></li>
|
|
403
|
+
<li><a href="#_-1"><span></span></a></li>
|
|
404
|
+
<li><a href="#_-2"><span></span></a></li></ul></li>
|
|
405
|
+
<li><a href="#query-orchestration-what-does"><span>Query orchestration: what does</span></a></li>
|
|
406
|
+
<li>
|
|
407
|
+
<ul>
|
|
408
|
+
<li><a href="#your-responsibility-implement"><span>Your responsibility: implement </span></a></li>
|
|
409
|
+
<li><a href="#orchestration-behavior-library-responsibility"><span>Orchestration behavior (library responsibility)</span></a></li>
|
|
410
|
+
<li><a href="#fields-you-must-understand"><span> fields you must understand</span></a></li>
|
|
411
|
+
<li><a href="#minimal-multi-index-example-provider-agnostic"><span>Minimal multi-<wbr/>index example (provider-<wbr/>agnostic)</span></a></li></ul></li>
|
|
412
|
+
<li><a href="#projection-type-only-k-and-adapter-responsibilities"><span>Projection (type-<wbr/>only <wbr/>K) and adapter responsibilities</span></a></li>
|
|
413
|
+
<li><a href="#index-token-inference-and-narrowing-patterns"><span>Index token inference and narrowing patterns</span></a></li>
|
|
414
|
+
<li>
|
|
415
|
+
<ul>
|
|
416
|
+
<li><a href="#cf-route-values-first-config-literal"><span>CF route (values-<wbr/>first config literal)</span></a></li>
|
|
417
|
+
<li><a href="#cc-route-captured-config-type"><span>CC route (captured config type)</span></a></li>
|
|
418
|
+
<li><a href="#convenience"><span> convenience</span></a></li></ul></li>
|
|
419
|
+
<li><a href="#adapter-building-blocks-shipped-in-this-package"><span>Adapter building blocks shipped in this package</span></a></li>
|
|
420
|
+
<li>
|
|
421
|
+
<ul>
|
|
422
|
+
<li><a href="#_-3"><span></span></a></li>
|
|
423
|
+
<li><a href="#_-4"><span></span></a></li></ul></li>
|
|
424
|
+
<li><a href="#common-failure-modes-debug-checklist"><span>Common failure modes (debug checklist)</span></a></li>
|
|
425
|
+
<li><a href="#what-stan-assistants-should-do-when-editing-code-that-uses-entity-manager"><span>What <wbr/>STAN assistants should do when editing code that uses <wbr/>Entity <wbr/>Manager</span></a></li></ul></div></details></div>
|
|
426
|
+
<div class="site-menu">
|
|
427
|
+
<nav class="tsd-navigation"><a href="../modules.html">@karmaniverous/entity-manager</a>
|
|
428
|
+
<ul class="tsd-small-nested-navigation" id="tsd-nav-container">
|
|
429
|
+
<li>Loading...</li></ul></nav></div></div></div><footer>
|
|
430
|
+
<p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer>
|
|
431
|
+
<div class="overlay"></div></body></html>
|